Reescritura para usar libnl3.
parent
3aedf1869e
commit
060cc47735
12
configure.ac
12
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
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
# List of source files which contain translatable strings.
|
||||
src/network-inador.c
|
||||
src/main.c
|
||||
|
|
|
@ -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
|
||||
|
|
300
src/bridge.c
300
src/bridge.c
|
@ -1,300 +0,0 @@
|
|||
/*
|
||||
* bridge.c
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2018 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Network-inador is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Network-inador; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_addr.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "interfaces.h"
|
||||
#include "rta_aux.h"
|
||||
|
||||
void bridge_create (int sock, const char *name) {
|
||||
struct msghdr rtnl_msg;
|
||||
struct iovec io;
|
||||
struct sockaddr_nl kernel;
|
||||
char buffer[8192];
|
||||
int len;
|
||||
struct nlmsghdr *nl;
|
||||
struct ifinfomsg *ifi;
|
||||
struct rtattr *linkinfo;
|
||||
struct nlmsgerr *l_err;
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
if (name != NULL) {
|
||||
/* Validar la longitud del nombre, por seguridad */
|
||||
len = strlen (name) + 1;
|
||||
if (len == 1) {
|
||||
/* Nombre muy corto */
|
||||
return;
|
||||
}
|
||||
if (len > IFNAMSIZ) {
|
||||
/* Nombre muy largo */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
memset (&kernel, 0, sizeof (kernel));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
|
||||
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
|
||||
kernel.nl_groups = 0;
|
||||
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
nl->nlmsg_len = NLMSG_LENGTH (sizeof(struct ifinfomsg));
|
||||
nl->nlmsg_type = RTM_NEWLINK;
|
||||
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
|
||||
nl->nlmsg_seq = global_nl_seq++;
|
||||
nl->nlmsg_pid = local_nl.nl_pid;
|
||||
|
||||
ifi = (struct ifinfomsg*) NLMSG_DATA (nl);
|
||||
ifi->ifi_family = AF_UNSPEC;
|
||||
ifi->ifi_index = 0;
|
||||
|
||||
/* Si existe un nombre, anexar como atributo */
|
||||
if (name != NULL) {
|
||||
rta_addattr_l (nl, sizeof (buffer), IFLA_IFNAME, name, strlen (name));
|
||||
}
|
||||
|
||||
linkinfo = rta_addattr_nest (nl, sizeof (buffer), IFLA_LINKINFO);
|
||||
rta_addattr_l (nl, sizeof (buffer), IFLA_INFO_KIND, "bridge", strlen ("bridge"));
|
||||
rta_addattr_nest_end (nl, linkinfo);
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = nl->nlmsg_len;
|
||||
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = sizeof (buffer);
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = recvmsg(sock, &rtnl_msg, 0);
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
|
||||
if (nl->nlmsg_type == NLMSG_DONE) {
|
||||
printf ("Bridge ADD Msg type: DONE!\n");
|
||||
break;
|
||||
}
|
||||
if (nl->nlmsg_type == NLMSG_ERROR) {
|
||||
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
|
||||
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
|
||||
printf ("Bridge ADD Error tamaño truncado\n");
|
||||
} else if (l_err->error != 0) {
|
||||
// Error:
|
||||
printf ("Bridge ADD Error: %i\n", l_err->error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bridge_add_interface (int sock, Interface *bridge, Interface *slave) {
|
||||
struct msghdr rtnl_msg;
|
||||
struct iovec io;
|
||||
struct sockaddr_nl kernel;
|
||||
char buffer[8192];
|
||||
int len;
|
||||
struct nlmsghdr *nl;
|
||||
struct ifinfomsg *ifi;
|
||||
struct nlmsgerr *l_err;
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
memset (&kernel, 0, sizeof (kernel));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
|
||||
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
|
||||
kernel.nl_groups = 0;
|
||||
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
nl->nlmsg_len = NLMSG_LENGTH (sizeof(struct ifinfomsg));
|
||||
nl->nlmsg_type = RTM_NEWLINK;
|
||||
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
nl->nlmsg_seq = global_nl_seq++;
|
||||
nl->nlmsg_pid = local_nl.nl_pid;
|
||||
|
||||
ifi = (struct ifinfomsg*) NLMSG_DATA (nl);
|
||||
ifi->ifi_family = AF_UNSPEC;
|
||||
ifi->ifi_index = slave->index;
|
||||
|
||||
rta_addattr_l (nl, sizeof (buffer), IFLA_MASTER, &bridge->index, 4);
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = nl->nlmsg_len;
|
||||
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = sizeof (buffer);
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = recvmsg(sock, &rtnl_msg, 0);
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
|
||||
if (nl->nlmsg_type == NLMSG_DONE) {
|
||||
printf ("Bridge ADD Slave Msg type: DONE!\n");
|
||||
break;
|
||||
}
|
||||
if (nl->nlmsg_type == NLMSG_ERROR) {
|
||||
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
|
||||
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
|
||||
printf ("Bridge ADD Slave Error tamaño truncado\n");
|
||||
} else if (l_err->error != 0) {
|
||||
// Error:
|
||||
printf ("Bridge ADD Slave Error: %i\n", l_err->error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bridge_remove_slave_from_bridge (int sock, Interface *slave) {
|
||||
struct msghdr rtnl_msg;
|
||||
struct iovec io;
|
||||
struct sockaddr_nl kernel;
|
||||
char buffer[8192];
|
||||
int len;
|
||||
struct nlmsghdr *nl;
|
||||
struct ifinfomsg *ifi;
|
||||
struct nlmsgerr *l_err;
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
memset (&kernel, 0, sizeof (kernel));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
|
||||
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
|
||||
kernel.nl_groups = 0;
|
||||
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
nl->nlmsg_len = NLMSG_LENGTH (sizeof(struct ifinfomsg));
|
||||
nl->nlmsg_type = RTM_NEWLINK;
|
||||
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
nl->nlmsg_seq = global_nl_seq++;
|
||||
nl->nlmsg_pid = local_nl.nl_pid;
|
||||
|
||||
ifi = (struct ifinfomsg*) NLMSG_DATA (nl);
|
||||
ifi->ifi_family = AF_UNSPEC;
|
||||
ifi->ifi_index = slave->index;
|
||||
|
||||
int ifindex = 0;
|
||||
rta_addattr_l (nl, sizeof (buffer), IFLA_MASTER, &ifindex, 4);
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = nl->nlmsg_len;
|
||||
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = sizeof (buffer);
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = recvmsg(sock, &rtnl_msg, 0);
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
|
||||
if (nl->nlmsg_type == NLMSG_DONE) {
|
||||
printf ("Bridge NOMaster Msg type: DONE!\n");
|
||||
break;
|
||||
}
|
||||
if (nl->nlmsg_type == NLMSG_ERROR) {
|
||||
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
|
||||
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
|
||||
printf ("Bridge NOMaster Error tamaño truncado\n");
|
||||
} else if (l_err->error != 0) {
|
||||
// Error:
|
||||
printf ("Bridge NOMaster Error: %i\n", l_err->error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
33
src/bridge.h
33
src/bridge.h
|
@ -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
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
* network-inador.h
|
||||
* common.h
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2011 - Félix Arreola Rodríguez
|
||||
* Copyright (C) 2019, 2020 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,64 +20,23 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __NETWORK_INADOR_H__
|
||||
#define __NETWORK_INADOR_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef __COMMON_H__
|
||||
#define __COMMON_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <linux/if.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <linux/if.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
/* Para almacenar la información de DHCP */
|
||||
enum {
|
||||
IFACE_NO_DHCP_RUNNING = 0,
|
||||
IFACE_DHCP_CLIENT,
|
||||
};
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
enum {
|
||||
DHCP_CLIENT_DECONFIG = 1,
|
||||
DHCP_CLIENT_LEASEFAIL,
|
||||
DHCP_CLIENT_BOUND,
|
||||
DHCP_CLIENT_RENEW,
|
||||
DHCP_CLIENT_NAK
|
||||
};
|
||||
|
||||
typedef struct _DHCPStateInfo {
|
||||
int type;
|
||||
|
||||
int read_pipe;
|
||||
GPid process_pid;
|
||||
|
||||
int client_state;
|
||||
} DHCPStateInfo;
|
||||
|
||||
typedef struct _IPv4 {
|
||||
struct in_addr sin_addr;
|
||||
uint32_t prefix;
|
||||
|
||||
unsigned char flags;
|
||||
|
||||
struct _IPv4 *next;
|
||||
} IPv4;
|
||||
|
||||
typedef struct _WirelessAccessPoint {
|
||||
int freq;
|
||||
int essid;
|
||||
char bssid[10];
|
||||
|
||||
struct _WirelessAccessPoint *next;
|
||||
} WirelessAccessPoint;
|
||||
|
||||
typedef struct {
|
||||
int wiphy;
|
||||
|
||||
WirelessAccessPoint *scaned_aps;
|
||||
} WirelessInfo;
|
||||
#ifndef TRUE
|
||||
#define TRUE !FALSE
|
||||
#endif
|
||||
|
||||
typedef struct _Interface {
|
||||
char name[IFNAMSIZ];
|
||||
|
@ -90,6 +49,9 @@ typedef struct _Interface {
|
|||
|
||||
unsigned int mtu;
|
||||
|
||||
/* Para las interfaces vlan */
|
||||
unsigned int vlan_parent;
|
||||
|
||||
/* Banderas estilo ioctl */
|
||||
short flags;
|
||||
|
||||
|
@ -101,37 +63,24 @@ typedef struct _Interface {
|
|||
int is_bridge;
|
||||
int is_vlan;
|
||||
int is_nlmon;
|
||||
int is_dummy;
|
||||
|
||||
IPv4 *v4_address;
|
||||
//IPv4 *v4_address;
|
||||
|
||||
DHCPStateInfo dhcp_info;
|
||||
//DHCPStateInfo dhcp_info;
|
||||
|
||||
/* Información wireless */
|
||||
WirelessInfo *wireless;
|
||||
|
||||
struct _Interface *next;
|
||||
//WirelessInfo *wireless;
|
||||
} Interface;
|
||||
|
||||
typedef struct _Routev4 {
|
||||
struct in_addr dest;
|
||||
uint32_t prefix;
|
||||
|
||||
struct in_addr gateway;
|
||||
unsigned int index;
|
||||
|
||||
unsigned char table;
|
||||
unsigned char type;
|
||||
|
||||
struct _Routev4 *next;
|
||||
} Routev4;
|
||||
|
||||
typedef struct {
|
||||
Interface *interfaces;
|
||||
Routev4 *rtable_v4;
|
||||
GList *interfaces;
|
||||
//Routev4 *rtable_v4;
|
||||
|
||||
int netlink_sock_request;
|
||||
int netlink_sock_request_generic;
|
||||
struct nl_sock * nl_sock_route;
|
||||
struct nl_sock * nl_sock_route_events;
|
||||
guint route_events_source;
|
||||
} NetworkInadorHandle;
|
||||
|
||||
#endif
|
||||
#endif /* __COMMON_H__ */
|
||||
|
286
src/dhcp.c
286
src/dhcp.c
|
@ -1,286 +0,0 @@
|
|||
/*
|
||||
* dhcp.c
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2018 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Network-inador is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Network-inador; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "network-inador.h"
|
||||
#include "dhcp.h"
|
||||
#include "interfaces.h"
|
||||
#include "utils.h"
|
||||
#include "routes.h"
|
||||
|
||||
#define DHCPC_PIPEOUT_HAS_IP 0x01
|
||||
#define DHCPC_PIPEOUT_HAS_SERVER_IP 0x02
|
||||
#define DHCPC_PIPEOUT_HAS_OPTS 0x04
|
||||
|
||||
static void _dhcp_parse_client_packet (NetworkInadorHandle *handle, Interface *iface, unsigned char *buffer, int len) {
|
||||
int type, flags, current_opt, count_opt;
|
||||
IPv4 address;
|
||||
struct in_addr mask, siaddr_nip, route;
|
||||
type = buffer[0];
|
||||
int pos;
|
||||
int has_gateway = 0;
|
||||
|
||||
memset (&address, 0, sizeof (address));
|
||||
|
||||
/* Máscara por default */
|
||||
inet_pton (AF_INET, "255.255.255.0", &mask);
|
||||
|
||||
iface->dhcp_info.client_state = type;
|
||||
switch (type) {
|
||||
case DHCP_CLIENT_DECONFIG:
|
||||
/* Desconfigurar la interfaz, borrar las IPs */
|
||||
interfaces_clear_all_ipv4_address (handle, iface);
|
||||
interfaces_bring_up (handle->netlink_sock_request, iface);
|
||||
break;
|
||||
case DHCP_CLIENT_LEASEFAIL:
|
||||
case DHCP_CLIENT_NAK:
|
||||
/* leasefail, nak */
|
||||
break;
|
||||
case DHCP_CLIENT_BOUND:
|
||||
case DHCP_CLIENT_RENEW:
|
||||
/* Bound, renew */
|
||||
flags = buffer[1];
|
||||
|
||||
pos = 2;
|
||||
if (flags & DHCPC_PIPEOUT_HAS_IP) {
|
||||
memcpy (&address.sin_addr, &buffer[pos], 4);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
if (flags & DHCPC_PIPEOUT_HAS_SERVER_IP) {
|
||||
memcpy (&siaddr_nip, &buffer[pos], 4);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
if (flags & DHCPC_PIPEOUT_HAS_OPTS) {
|
||||
current_opt = buffer[pos];
|
||||
|
||||
while (current_opt != 255) {
|
||||
pos++;
|
||||
|
||||
if (current_opt == 0x01) {
|
||||
memcpy (&mask, &buffer[pos], 4);
|
||||
pos += 4;
|
||||
} else if (current_opt == 0x03) {
|
||||
count_opt = buffer[pos];
|
||||
pos++;
|
||||
|
||||
/* TODO: Solo tomamos la ultima ruta, arreglar */
|
||||
while (count_opt) {
|
||||
memcpy (&route, &buffer[pos], 4);
|
||||
pos += 4;
|
||||
has_gateway = 1;
|
||||
|
||||
count_opt--;
|
||||
}
|
||||
} else if (current_opt == 0x06) {
|
||||
/* TODO: Procesar la lista de DNS */
|
||||
count_opt = buffer[pos];
|
||||
pos++;
|
||||
|
||||
while (count_opt) {
|
||||
count_opt--;
|
||||
pos += 4;
|
||||
}
|
||||
} else if (current_opt == 0x0c || current_opt == 0x0f) {
|
||||
/* TODO: Procesar el hostname o domain name */
|
||||
while (buffer[pos] != 0) {
|
||||
pos++;
|
||||
}
|
||||
} else if (current_opt == 0x2a) {
|
||||
/* TODO: Procesar la lista de NTP */
|
||||
count_opt = buffer[pos];
|
||||
pos++;
|
||||
|
||||
while (count_opt) {
|
||||
count_opt--;
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
current_opt = buffer[pos];
|
||||
}
|
||||
|
||||
/* Ejecutar la configuración de la IP */
|
||||
address.prefix = utils_ip4_netmask_to_prefix (mask.s_addr);
|
||||
interfaces_manual_add_ipv4 (handle->netlink_sock_request, iface, &address);
|
||||
|
||||
/* Y esperar a que se active la IP para luego configurar la ruta */
|
||||
if (has_gateway) {
|
||||
IPv4 default_dest;
|
||||
|
||||
inet_pton (AF_INET, "0.0.0.0", &default_dest.sin_addr);
|
||||
default_dest.prefix = 0;
|
||||
routes_manual_add_ipv4 (handle->netlink_sock_request, iface, &default_dest, route);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean _dhcp_read_client_data (GIOChannel *source, GIOCondition condition, gpointer data) {
|
||||
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
|
||||
int sock;
|
||||
char buffer[256];
|
||||
int len;
|
||||
Interface *iface;
|
||||
int exit_estatus;
|
||||
int ret;
|
||||
|
||||
sock = g_io_channel_unix_get_fd (source);
|
||||
|
||||
len = read (sock, buffer, sizeof (buffer));
|
||||
|
||||
printf ("\n-------------> Read DHCP client from PIPE (%i) = %i\n", sock, len);
|
||||
|
||||
iface = handle->interfaces;
|
||||
while (iface != NULL) {
|
||||
if (sock == iface->dhcp_info.read_pipe) {
|
||||
/* Esta es la interfaz activa */
|
||||
break;
|
||||
}
|
||||
iface = iface->next;
|
||||
}
|
||||
|
||||
if (iface == NULL) {
|
||||
/* Que raro... no debería ocurrir */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
close (sock);
|
||||
|
||||
/* El proceso del cliente de dhcp murió, si lo reiniciamos se maneja en g_child_wait */
|
||||
iface->dhcp_info.read_pipe = 0;
|
||||
|
||||
return FALSE;
|
||||
} else if (len < 0) {
|
||||
printf ("_--------------_____________ Soy el error que buscas\n");
|
||||
return FALSE;
|
||||
} else {
|
||||
/* Parsear lo leido por el dhcp client */
|
||||
_dhcp_parse_client_packet (handle, iface, buffer, len);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void _dhcp_client_exited (GPid pid, gint status, gpointer data) {
|
||||
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
|
||||
Interface *iface;
|
||||
|
||||
iface = handle->interfaces;
|
||||
while (iface != NULL) {
|
||||
if (pid == iface->dhcp_info.process_pid) {
|
||||
/* Esta es la interfaz activa */
|
||||
break;
|
||||
}
|
||||
iface = iface->next;
|
||||
}
|
||||
|
||||
if (iface == NULL) {
|
||||
/* El dhcp para una interfaz eliminada murió */
|
||||
|
||||
g_spawn_close_pid (pid);
|
||||
return;
|
||||
}
|
||||
|
||||
iface->dhcp_info.process_pid = 0;
|
||||
|
||||
/* Si el estado quedó en "running", reiniciar el proceso de dhcp */
|
||||
if (iface->dhcp_info.type == IFACE_DHCP_CLIENT) {
|
||||
iface->dhcp_info.type = IFACE_NO_DHCP_RUNNING;
|
||||
dhcp_run_client (handle, iface);
|
||||
}
|
||||
|
||||
g_spawn_close_pid (pid);
|
||||
}
|
||||
|
||||
void dhcp_run_client (NetworkInadorHandle *handle, Interface *iface) {
|
||||
GIOChannel *channel;
|
||||
gboolean result;
|
||||
gint read_from_child;
|
||||
GPid child_pid;
|
||||
|
||||
/* FIXME: Arreglar el path */
|
||||
char *argv[] = {"/tmp/abc/sbin/nidhcpc", iface->name, NULL};
|
||||
|
||||
if (iface->dhcp_info.type != IFACE_NO_DHCP_RUNNING) {
|
||||
printf ("DHCP (client or server) already running\n");
|
||||
return;
|
||||
}
|
||||
|
||||
interfaces_bring_up (handle->netlink_sock_request, iface);
|
||||
|
||||
result = g_spawn_async_with_pipes (
|
||||
NULL, /* working directory */
|
||||
argv, /* Argumentos */
|
||||
NULL, /* envp */
|
||||
G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_CLOEXEC_PIPES, /* Banderas */
|
||||
NULL, NULL, /* Child setup func and data */
|
||||
&child_pid,
|
||||
NULL, /* Entrada estándar */
|
||||
&read_from_child, /* Salida estándar */
|
||||
NULL, /* Salida de errores */
|
||||
NULL); /* Gerror */
|
||||
|
||||
if (result == FALSE) {
|
||||
printf ("Falló al lanzar proceso de cliente de dhcp\n");
|
||||
return;
|
||||
}
|
||||
|
||||
iface->dhcp_info.type = IFACE_DHCP_CLIENT;
|
||||
iface->dhcp_info.read_pipe = read_from_child;
|
||||
iface->dhcp_info.process_pid = child_pid;
|
||||
|
||||
iface->dhcp_info.client_state = DHCP_CLIENT_DECONFIG;
|
||||
|
||||
/* Instalar un GIOChannel */
|
||||
channel = g_io_channel_unix_new (read_from_child);
|
||||
|
||||
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _dhcp_read_client_data, handle);
|
||||
|
||||
/* Para manejar la muerte del proceso */
|
||||
g_child_watch_add (child_pid, _dhcp_client_exited, handle);
|
||||
}
|
||||
|
||||
void dhcp_stop_client (NetworkInadorHandle *handle, Interface *iface) {
|
||||
if (iface->dhcp_info.type == IFACE_DHCP_CLIENT) {
|
||||
iface->dhcp_info.type = IFACE_NO_DHCP_RUNNING;
|
||||
kill (iface->dhcp_info.process_pid, SIGTERM);
|
||||
}
|
||||
}
|
||||
|
29
src/dhcp.h
29
src/dhcp.h
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -1,441 +0,0 @@
|
|||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
|
||||
unsigned dhcp_verbose;
|
||||
#endif
|
||||
|
||||
const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
/* Supported options are easily added here.
|
||||
* See RFC2132 for more options.
|
||||
* OPTION_REQ: these options are requested by udhcpc (unless -o).
|
||||
*/
|
||||
const struct dhcp_optflag dhcp_optflags[] = {
|
||||
/* flags code */
|
||||
{ OPTION_IP | OPTION_REQ, 0x01 }, /* DHCP_SUBNET */
|
||||
{ OPTION_S32 , 0x02 }, /* DHCP_TIME_OFFSET */
|
||||
{ OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03 }, /* DHCP_ROUTER */
|
||||
// { OPTION_IP | OPTION_LIST , 0x04 }, /* DHCP_TIME_SERVER */
|
||||
// { OPTION_IP | OPTION_LIST , 0x05 }, /* DHCP_NAME_SERVER */
|
||||
{ OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER */
|
||||
// { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */
|
||||
// { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */
|
||||
{ OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */
|
||||
{ OPTION_STRING_HOST | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */
|
||||
{ OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */
|
||||
{ OPTION_STRING_HOST | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */
|
||||
{ OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */
|
||||
{ OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */
|
||||
{ OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */
|
||||
{ OPTION_U16 , 0x1a }, /* DHCP_MTU */
|
||||
//TODO: why do we request DHCP_BROADCAST? Can't we assume that
|
||||
//in the unlikely case it is different from typical N.N.255.255,
|
||||
//server would let us know anyway?
|
||||
{ OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */
|
||||
{ OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */
|
||||
{ OPTION_STRING_HOST , 0x28 }, /* DHCP_NIS_DOMAIN */
|
||||
{ OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */
|
||||
{ OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */
|
||||
{ OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */
|
||||
{ OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */
|
||||
{ OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */
|
||||
{ OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */
|
||||
//TODO: must be combined with 'sname' and 'file' handling:
|
||||
{ OPTION_STRING_HOST , 0x42 }, /* DHCP_TFTP_SERVER_NAME */
|
||||
{ OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */
|
||||
//TODO: not a string, but a set of LASCII strings:
|
||||
// { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */
|
||||
#if ENABLE_FEATURE_UDHCP_RFC3397
|
||||
{ OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */
|
||||
{ OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */
|
||||
#endif
|
||||
{ OPTION_STATIC_ROUTES | OPTION_LIST , 0x79 }, /* DHCP_STATIC_ROUTES */
|
||||
#if ENABLE_FEATURE_UDHCP_8021Q
|
||||
{ OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */
|
||||
{ OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */
|
||||
#endif
|
||||
{ OPTION_STRING , 0xd1 }, /* DHCP_PXE_CONF_FILE */
|
||||
{ OPTION_6RD , 0xd4 }, /* DHCP_6RD */
|
||||
{ OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
|
||||
{ OPTION_STRING , 0xfc }, /* DHCP_WPAD */
|
||||
|
||||
/* Options below have no match in dhcp_option_strings[],
|
||||
* are not passed to dhcpc scripts, and cannot be specified
|
||||
* with "option XXX YYY" syntax in dhcpd config file.
|
||||
* These entries are only used internally by udhcp[cd]
|
||||
* to correctly encode options into packets.
|
||||
*/
|
||||
|
||||
{ OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */
|
||||
{ OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */
|
||||
{ OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */
|
||||
//looks like these opts will work just fine even without these defs:
|
||||
// { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */
|
||||
// /* not really a string: */
|
||||
// { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */
|
||||
{ 0, 0 } /* zeroed terminating entry */
|
||||
};
|
||||
|
||||
/* Used for converting options from incoming packets to env variables
|
||||
* for udhcpc stript, and for setting options for udhcpd via
|
||||
* "opt OPTION_NAME OPTION_VALUE" directives in udhcpd.conf file.
|
||||
*/
|
||||
/* Must match dhcp_optflags[] order */
|
||||
const char dhcp_option_strings[] ALIGN1 =
|
||||
"subnet" "\0" /* DHCP_SUBNET */
|
||||
"timezone" "\0" /* DHCP_TIME_OFFSET */
|
||||
"router" "\0" /* DHCP_ROUTER */
|
||||
// "timesrv" "\0" /* DHCP_TIME_SERVER */
|
||||
// "namesrv" "\0" /* DHCP_NAME_SERVER */
|
||||
"dns" "\0" /* DHCP_DNS_SERVER */
|
||||
// "logsrv" "\0" /* DHCP_LOG_SERVER */
|
||||
// "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */
|
||||
"lprsrv" "\0" /* DHCP_LPR_SERVER */
|
||||
"hostname" "\0" /* DHCP_HOST_NAME */
|
||||
"bootsize" "\0" /* DHCP_BOOT_SIZE */
|
||||
"domain" "\0" /* DHCP_DOMAIN_NAME */
|
||||
"swapsrv" "\0" /* DHCP_SWAP_SERVER */
|
||||
"rootpath" "\0" /* DHCP_ROOT_PATH */
|
||||
"ipttl" "\0" /* DHCP_IP_TTL */
|
||||
"mtu" "\0" /* DHCP_MTU */
|
||||
"broadcast" "\0" /* DHCP_BROADCAST */
|
||||
"routes" "\0" /* DHCP_ROUTES */
|
||||
"nisdomain" "\0" /* DHCP_NIS_DOMAIN */
|
||||
"nissrv" "\0" /* DHCP_NIS_SERVER */
|
||||
"ntpsrv" "\0" /* DHCP_NTP_SERVER */
|
||||
"wins" "\0" /* DHCP_WINS_SERVER */
|
||||
"lease" "\0" /* DHCP_LEASE_TIME */
|
||||
"serverid" "\0" /* DHCP_SERVER_ID */
|
||||
"message" "\0" /* DHCP_ERR_MESSAGE */
|
||||
"tftp" "\0" /* DHCP_TFTP_SERVER_NAME */
|
||||
"bootfile" "\0" /* DHCP_BOOT_FILE */
|
||||
// "userclass" "\0" /* DHCP_USER_CLASS */
|
||||
#if ENABLE_FEATURE_UDHCP_RFC3397
|
||||
"search" "\0" /* DHCP_DOMAIN_SEARCH */
|
||||
// doesn't work in udhcpd.conf since OPTION_SIP_SERVERS
|
||||
// is not handled yet by "string->option" conversion code:
|
||||
"sipsrv" "\0" /* DHCP_SIP_SERVERS */
|
||||
#endif
|
||||
"staticroutes" "\0"/* DHCP_STATIC_ROUTES */
|
||||
#if ENABLE_FEATURE_UDHCP_8021Q
|
||||
"vlanid" "\0" /* DHCP_VLAN_ID */
|
||||
"vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */
|
||||
#endif
|
||||
"pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */
|
||||
"ip6rd" "\0" /* DHCP_6RD */
|
||||
"msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
|
||||
"wpad" "\0" /* DHCP_WPAD */
|
||||
;
|
||||
|
||||
/* Lengths of the option types in binary form.
|
||||
* Used by:
|
||||
* udhcp_str2optset: to determine how many bytes to allocate.
|
||||
* xmalloc_optname_optval: to estimate string length
|
||||
* from binary option length: (option[LEN] / dhcp_option_lengths[opt_type])
|
||||
* is the number of elements, multiply in by one element's string width
|
||||
* (len_of_option_as_string[opt_type]) and you know how wide string you need.
|
||||
*/
|
||||
const uint8_t dhcp_option_lengths[] ALIGN1 = {
|
||||
[OPTION_IP] = 4,
|
||||
[OPTION_IP_PAIR] = 8,
|
||||
// [OPTION_BOOLEAN] = 1,
|
||||
[OPTION_STRING] = 1, /* ignored by udhcp_str2optset */
|
||||
[OPTION_STRING_HOST] = 1, /* ignored by udhcp_str2optset */
|
||||
#if ENABLE_FEATURE_UDHCP_RFC3397
|
||||
[OPTION_DNS_STRING] = 1, /* ignored by both udhcp_str2optset and xmalloc_optname_optval */
|
||||
[OPTION_SIP_SERVERS] = 1,
|
||||
#endif
|
||||
[OPTION_U8] = 1,
|
||||
[OPTION_U16] = 2,
|
||||
// [OPTION_S16] = 2,
|
||||
[OPTION_U32] = 4,
|
||||
[OPTION_S32] = 4,
|
||||
/* Just like OPTION_STRING, we use minimum length here */
|
||||
[OPTION_STATIC_ROUTES] = 5,
|
||||
[OPTION_6RD] = 22, /* ignored by udhcp_str2optset */
|
||||
};
|
||||
|
||||
|
||||
#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
|
||||
static void log_option(const char *pfx, const uint8_t *opt)
|
||||
{
|
||||
if (dhcp_verbose >= 2) {
|
||||
char buf[256 * 2 + 2];
|
||||
*bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0';
|
||||
bb_info_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define log_option(pfx, opt) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Get an option with bounds checking (warning, result is not aligned) */
|
||||
uint8_t* udhcp_get_option(struct dhcp_packet *packet, int code)
|
||||
{
|
||||
uint8_t *optionptr;
|
||||
int len;
|
||||
int rem;
|
||||
int overload = 0;
|
||||
enum {
|
||||
FILE_FIELD101 = FILE_FIELD * 0x101,
|
||||
SNAME_FIELD101 = SNAME_FIELD * 0x101,
|
||||
};
|
||||
|
||||
/* option bytes: [code][len][data1][data2]..[dataLEN] */
|
||||
optionptr = packet->options;
|
||||
rem = sizeof(packet->options);
|
||||
while (1) {
|
||||
if (rem <= 0) {
|
||||
fprintf (stderr, "bad packet, malformed option field");
|
||||
return NULL;
|
||||
}
|
||||
if (optionptr[OPT_CODE] == DHCP_PADDING) {
|
||||
rem--;
|
||||
optionptr++;
|
||||
continue;
|
||||
}
|
||||
if (optionptr[OPT_CODE] == DHCP_END) {
|
||||
if ((overload & FILE_FIELD101) == FILE_FIELD) {
|
||||
/* can use packet->file, and didn't look at it yet */
|
||||
overload |= FILE_FIELD101; /* "we looked at it" */
|
||||
optionptr = packet->file;
|
||||
rem = sizeof(packet->file);
|
||||
continue;
|
||||
}
|
||||
if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
|
||||
/* can use packet->sname, and didn't look at it yet */
|
||||
overload |= SNAME_FIELD101; /* "we looked at it" */
|
||||
optionptr = packet->sname;
|
||||
rem = sizeof(packet->sname);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
len = 2 + optionptr[OPT_LEN];
|
||||
rem -= len;
|
||||
if (rem < 0)
|
||||
continue; /* complain and return NULL */
|
||||
|
||||
if (optionptr[OPT_CODE] == code) {
|
||||
log_option("Option found", optionptr);
|
||||
return optionptr + OPT_DATA;
|
||||
}
|
||||
|
||||
if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
|
||||
overload |= optionptr[OPT_DATA];
|
||||
/* fall through */
|
||||
}
|
||||
optionptr += len;
|
||||
}
|
||||
|
||||
/* log3 because udhcpc uses it a lot - very noisy */
|
||||
log3("Option 0x%02x not found", code);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return the position of the 'end' option (no bounds checking) */
|
||||
int udhcp_end_option(uint8_t *optionptr)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (optionptr[i] != DHCP_END) {
|
||||
if (optionptr[i] != DHCP_PADDING)
|
||||
i += optionptr[i + OPT_LEN] + OPT_DATA-1;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Add an option (supplied in binary form) to the options.
|
||||
* Option format: [code][len][data1][data2]..[dataLEN]
|
||||
*/
|
||||
void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt)
|
||||
{
|
||||
unsigned len;
|
||||
uint8_t *optionptr = packet->options;
|
||||
unsigned end = udhcp_end_option(optionptr);
|
||||
|
||||
len = OPT_DATA + addopt[OPT_LEN];
|
||||
/* end position + (option code/length + addopt length) + end option */
|
||||
if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE) {
|
||||
//TODO: learn how to use overflow option if we exhaust packet->options[]
|
||||
fprintf (stderr, "option 0x%02x did not fit into the packet",
|
||||
addopt[OPT_CODE]);
|
||||
return;
|
||||
}
|
||||
log_option("Adding option", addopt);
|
||||
memcpy(optionptr + end, addopt, len);
|
||||
optionptr[end + len] = DHCP_END;
|
||||
}
|
||||
|
||||
/* Add an one to four byte option to a packet */
|
||||
void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data)
|
||||
{
|
||||
const struct dhcp_optflag *dh;
|
||||
|
||||
for (dh = dhcp_optflags; dh->code; dh++) {
|
||||
if (dh->code == code) {
|
||||
uint8_t option[6], len;
|
||||
|
||||
option[OPT_CODE] = code;
|
||||
len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK];
|
||||
option[OPT_LEN] = len;
|
||||
if (BB_BIG_ENDIAN)
|
||||
data <<= 8 * (4 - len);
|
||||
/* Assignment is unaligned! */
|
||||
move_to_unaligned32(&option[OPT_DATA], data);
|
||||
udhcp_add_binary_option(packet, option);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (stderr, "can't add option 0x%02x", code);
|
||||
}
|
||||
|
||||
/* Find option 'code' in opt_list */
|
||||
struct option_set* udhcp_find_option(struct option_set *opt_list, uint8_t code)
|
||||
{
|
||||
while (opt_list && opt_list->data[OPT_CODE] < code)
|
||||
opt_list = opt_list->next;
|
||||
|
||||
if (opt_list && opt_list->data[OPT_CODE] == code)
|
||||
return opt_list;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parse string to IP in network order */
|
||||
int udhcp_str2nip(const char *str, void *arg)
|
||||
{
|
||||
len_and_sockaddr *lsa;
|
||||
|
||||
lsa = host_and_af2sockaddr(str, 0, AF_INET);
|
||||
if (!lsa)
|
||||
return 0;
|
||||
/* arg maybe unaligned */
|
||||
move_to_unaligned32((uint32_t*)arg, lsa->u.sin.sin_addr.s_addr);
|
||||
free(lsa);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* udhcp_str2optset:
|
||||
* Parse string option representation to binary form and add it to opt_list.
|
||||
* Called to parse "udhcpc -x OPTNAME:OPTVAL"
|
||||
* and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives.
|
||||
*/
|
||||
/* helper for the helper */
|
||||
static char *allocate_tempopt_if_needed(
|
||||
const struct dhcp_optflag *optflag,
|
||||
char *buffer,
|
||||
int *length_p)
|
||||
{
|
||||
char *allocated = NULL;
|
||||
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) {
|
||||
const char *end;
|
||||
allocated = xstrdup(buffer); /* more than enough */
|
||||
end = hex2bin(allocated, buffer, 255);
|
||||
if (errno) {
|
||||
fprintf (stderr, "malformed hex string '%s'", buffer);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
*length_p = end - allocated;
|
||||
}
|
||||
return allocated;
|
||||
}
|
||||
/* helper: add an option to the opt_list */
|
||||
static NOINLINE void attach_option(
|
||||
struct option_set **opt_list,
|
||||
const struct dhcp_optflag *optflag,
|
||||
char *buffer,
|
||||
int length)
|
||||
{
|
||||
struct option_set *existing;
|
||||
char *allocated;
|
||||
|
||||
allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
|
||||
#if ENABLE_FEATURE_UDHCP_RFC3397
|
||||
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
|
||||
/* reuse buffer and length for RFC1035-formatted string */
|
||||
allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length);
|
||||
}
|
||||
#endif
|
||||
|
||||
existing = udhcp_find_option(*opt_list, optflag->code);
|
||||
if (!existing) {
|
||||
struct option_set *new, **curr;
|
||||
|
||||
/* make a new option */
|
||||
log2("Attaching option %02x to list", optflag->code);
|
||||
new = xmalloc(sizeof(*new));
|
||||
new->data = xmalloc(length + OPT_DATA);
|
||||
new->data[OPT_CODE] = optflag->code;
|
||||
new->data[OPT_LEN] = length;
|
||||
memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer), length);
|
||||
|
||||
curr = opt_list;
|
||||
while (*curr && (*curr)->data[OPT_CODE] < optflag->code)
|
||||
curr = &(*curr)->next;
|
||||
|
||||
new->next = *curr;
|
||||
*curr = new;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
if (optflag->flags & OPTION_LIST) {
|
||||
unsigned old_len;
|
||||
|
||||
/* add it to an existing option */
|
||||
log2("Attaching option %02x to existing member of list", optflag->code);
|
||||
old_len = existing->data[OPT_LEN];
|
||||
if (old_len + length < 255) {
|
||||
/* actually 255 is ok too, but adding a space can overlow it */
|
||||
|
||||
existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length);
|
||||
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING
|
||||
|| (optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING_HOST
|
||||
) {
|
||||
/* add space separator between STRING options in a list */
|
||||
existing->data[OPT_DATA + old_len] = ' ';
|
||||
old_len++;
|
||||
}
|
||||
memcpy(existing->data + OPT_DATA + old_len, (allocated ? allocated : buffer), length);
|
||||
existing->data[OPT_LEN] = old_len + length;
|
||||
} /* else, ignore the data, we could put this in a second option in the future */
|
||||
} /* else, ignore the new data */
|
||||
|
||||
ret:
|
||||
free(allocated);
|
||||
}
|
||||
|
||||
/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */
|
||||
int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip)
|
||||
{
|
||||
char hexstrbuf[16 * 2];
|
||||
bin2hex(hexstrbuf, (void*)ip, 16);
|
||||
return sprintf(dest, /* "%s" */
|
||||
"%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s",
|
||||
/* pre, */
|
||||
hexstrbuf + 0 * 4,
|
||||
hexstrbuf + 1 * 4,
|
||||
hexstrbuf + 2 * 4,
|
||||
hexstrbuf + 3 * 4,
|
||||
hexstrbuf + 4 * 4,
|
||||
hexstrbuf + 5 * 4,
|
||||
hexstrbuf + 6 * 4,
|
||||
hexstrbuf + 7 * 4
|
||||
);
|
||||
}
|
|
@ -1,317 +0,0 @@
|
|||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Russ Dill <Russ.Dill@asu.edu> September 2001
|
||||
* Rewritten by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
|
||||
*
|
||||
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
||||
*/
|
||||
#ifndef UDHCP_COMMON_H
|
||||
#define UDHCP_COMMON_H 1
|
||||
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
#include "extra.h"
|
||||
|
||||
extern const uint8_t MAC_BCAST_ADDR[6] ALIGN2; /* six all-ones */
|
||||
|
||||
|
||||
/*** DHCP packet ***/
|
||||
|
||||
/* DHCP protocol. See RFC 2131 */
|
||||
#define DHCP_MAGIC 0x63825363
|
||||
#define DHCP_OPTIONS_BUFSIZE 308
|
||||
#define BOOTREQUEST 1
|
||||
#define BOOTREPLY 2
|
||||
|
||||
//TODO: rename ciaddr/yiaddr/chaddr
|
||||
struct dhcp_packet {
|
||||
uint8_t op; /* BOOTREQUEST or BOOTREPLY */
|
||||
uint8_t htype; /* hardware address type. 1 = 10mb ethernet */
|
||||
uint8_t hlen; /* hardware address length */
|
||||
uint8_t hops; /* used by relay agents only */
|
||||
uint32_t xid; /* unique id */
|
||||
uint16_t secs; /* elapsed since client began acquisition/renewal */
|
||||
uint16_t flags; /* only one flag so far: */
|
||||
#define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */
|
||||
uint32_t ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */
|
||||
uint32_t yiaddr; /* 'your' (client) IP address */
|
||||
/* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */
|
||||
uint32_t siaddr_nip;
|
||||
uint32_t gateway_nip; /* relay agent IP address */
|
||||
uint8_t chaddr[16]; /* link-layer client hardware address (MAC) */
|
||||
uint8_t sname[64]; /* server host name (ASCIZ) */
|
||||
uint8_t file[128]; /* boot file name (ASCIZ) */
|
||||
uint32_t cookie; /* fixed first four option bytes (99,130,83,99 dec) */
|
||||
uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS];
|
||||
} PACKED;
|
||||
#define DHCP_PKT_SNAME_LEN 64
|
||||
#define DHCP_PKT_FILE_LEN 128
|
||||
#define DHCP_PKT_SNAME_LEN_STR "64"
|
||||
#define DHCP_PKT_FILE_LEN_STR "128"
|
||||
|
||||
struct ip_udp_dhcp_packet {
|
||||
struct iphdr ip;
|
||||
struct udphdr udp;
|
||||
struct dhcp_packet data;
|
||||
} PACKED;
|
||||
|
||||
struct udp_dhcp_packet {
|
||||
struct udphdr udp;
|
||||
struct dhcp_packet data;
|
||||
} PACKED;
|
||||
|
||||
enum {
|
||||
IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
|
||||
UDP_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
|
||||
DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
|
||||
};
|
||||
|
||||
/* Let's see whether compiler understood us right */
|
||||
struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet {
|
||||
char c[IP_UDP_DHCP_SIZE == 576 ? 1 : -1];
|
||||
};
|
||||
|
||||
|
||||
/*** Options ***/
|
||||
|
||||
enum {
|
||||
OPTION_IP = 1,
|
||||
OPTION_IP_PAIR,
|
||||
OPTION_STRING,
|
||||
/* Opts of STRING_HOST type will be sanitized before they are passed
|
||||
* to udhcpc script's environment: */
|
||||
OPTION_STRING_HOST,
|
||||
// OPTION_BOOLEAN,
|
||||
OPTION_U8,
|
||||
OPTION_U16,
|
||||
// OPTION_S16,
|
||||
OPTION_U32,
|
||||
OPTION_S32,
|
||||
OPTION_BIN,
|
||||
OPTION_STATIC_ROUTES,
|
||||
OPTION_6RD,
|
||||
#if ENABLE_FEATURE_UDHCP_RFC3397
|
||||
OPTION_DNS_STRING, /* RFC1035 compressed domain name list */
|
||||
OPTION_SIP_SERVERS,
|
||||
#endif
|
||||
|
||||
OPTION_TYPE_MASK = 0x0f,
|
||||
/* Client requests this option by default */
|
||||
OPTION_REQ = 0x10,
|
||||
/* There can be a list of 1 or more of these */
|
||||
OPTION_LIST = 0x20,
|
||||
};
|
||||
|
||||
/* DHCP option codes (partial list). See RFC 2132 and
|
||||
* http://www.iana.org/assignments/bootp-dhcp-parameters/
|
||||
* Commented out options are handled by common option machinery,
|
||||
* uncommented ones have special cases (grep for them to see).
|
||||
*/
|
||||
#define DHCP_PADDING 0x00
|
||||
#define DHCP_SUBNET 0x01
|
||||
//#define DHCP_TIME_OFFSET 0x02 /* (localtime - UTC_time) in seconds. signed */
|
||||
//#define DHCP_ROUTER 0x03
|
||||
//#define DHCP_TIME_SERVER 0x04 /* RFC 868 time server (32-bit, 0 = 1.1.1900) */
|
||||
//#define DHCP_NAME_SERVER 0x05 /* IEN 116 _really_ ancient kind of NS */
|
||||
//#define DHCP_DNS_SERVER 0x06
|
||||
//#define DHCP_LOG_SERVER 0x07 /* port 704 UDP log (not syslog)
|
||||
//#define DHCP_COOKIE_SERVER 0x08 /* "quote of the day" server */
|
||||
//#define DHCP_LPR_SERVER 0x09
|
||||
#define DHCP_HOST_NAME 0x0c /* either client informs server or server gives name to client */
|
||||
//#define DHCP_BOOT_SIZE 0x0d
|
||||
//#define DHCP_DOMAIN_NAME 0x0f /* server gives domain suffix */
|
||||
//#define DHCP_SWAP_SERVER 0x10
|
||||
//#define DHCP_ROOT_PATH 0x11
|
||||
//#define DHCP_IP_TTL 0x17
|
||||
//#define DHCP_MTU 0x1a
|
||||
//#define DHCP_BROADCAST 0x1c
|
||||
//#define DHCP_ROUTES 0x21
|
||||
//#define DHCP_NIS_DOMAIN 0x28
|
||||
//#define DHCP_NIS_SERVER 0x29
|
||||
//#define DHCP_NTP_SERVER 0x2a
|
||||
//#define DHCP_WINS_SERVER 0x2c
|
||||
#define DHCP_REQUESTED_IP 0x32 /* sent by client if specific IP is wanted */
|
||||
#define DHCP_LEASE_TIME 0x33
|
||||
#define DHCP_OPTION_OVERLOAD 0x34
|
||||
#define DHCP_MESSAGE_TYPE 0x35
|
||||
#define DHCP_SERVER_ID 0x36 /* by default server's IP */
|
||||
#define DHCP_PARAM_REQ 0x37 /* list of options client wants */
|
||||
//#define DHCP_ERR_MESSAGE 0x38 /* error message when sending NAK etc */
|
||||
#define DHCP_MAX_SIZE 0x39
|
||||
#define DHCP_VENDOR 0x3c /* client's vendor (a string) */
|
||||
#define DHCP_CLIENT_ID 0x3d /* by default client's MAC addr, but may be arbitrarily long */
|
||||
//#define DHCP_TFTP_SERVER_NAME 0x42 /* same as 'sname' field */
|
||||
//#define DHCP_BOOT_FILE 0x43 /* same as 'file' field */
|
||||
//#define DHCP_USER_CLASS 0x4d /* RFC 3004. set of LASCII strings. "I am a printer" etc */
|
||||
#define DHCP_FQDN 0x51 /* client asks to update DNS to map its FQDN to its new IP */
|
||||
//#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */
|
||||
//#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */
|
||||
//#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */
|
||||
//#define DHCP_VLAN_ID 0x84 /* 802.1P VLAN ID */
|
||||
//#define DHCP_VLAN_PRIORITY 0x85 /* 802.1Q VLAN priority */
|
||||
//#define DHCP_PXE_CONF_FILE 0xd1 /* RFC 5071 Configuration File */
|
||||
//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */
|
||||
//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */
|
||||
#define DHCP_END 0xff
|
||||
|
||||
/* Offsets in option byte sequence */
|
||||
#define OPT_CODE 0
|
||||
#define OPT_LEN 1
|
||||
#define OPT_DATA 2
|
||||
/* Bits in "overload" option */
|
||||
#define OPTION_FIELD 0
|
||||
#define FILE_FIELD 1
|
||||
#define SNAME_FIELD 2
|
||||
|
||||
/* DHCP_MESSAGE_TYPE values */
|
||||
#define DHCPDISCOVER 1 /* client -> server */
|
||||
#define DHCPOFFER 2 /* client <- server */
|
||||
#define DHCPREQUEST 3 /* client -> server */
|
||||
#define DHCPDECLINE 4 /* client -> server */
|
||||
#define DHCPACK 5 /* client <- server */
|
||||
#define DHCPNAK 6 /* client <- server */
|
||||
#define DHCPRELEASE 7 /* client -> server */
|
||||
#define DHCPINFORM 8 /* client -> server */
|
||||
#define DHCP_MINTYPE DHCPDISCOVER
|
||||
#define DHCP_MAXTYPE DHCPINFORM
|
||||
|
||||
struct dhcp_optflag {
|
||||
uint8_t flags;
|
||||
uint8_t code;
|
||||
};
|
||||
|
||||
struct option_set {
|
||||
uint8_t *data;
|
||||
struct option_set *next;
|
||||
};
|
||||
|
||||
extern const struct dhcp_optflag dhcp_optflags[];
|
||||
extern const char dhcp_option_strings[] ALIGN1;
|
||||
extern const uint8_t dhcp_option_lengths[] ALIGN1;
|
||||
|
||||
unsigned udhcp_option_idx(const char *name);
|
||||
|
||||
uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code);
|
||||
int udhcp_end_option(uint8_t *optionptr);
|
||||
void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt);
|
||||
void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data);
|
||||
#if ENABLE_FEATURE_UDHCP_RFC3397
|
||||
char *dname_dec(const uint8_t *cstr, int clen, const char *pre);
|
||||
uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen);
|
||||
#endif
|
||||
struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code);
|
||||
|
||||
|
||||
// RFC 2131 Table 5: Fields and options used by DHCP clients
|
||||
//
|
||||
// Fields 'hops', 'yiaddr', 'siaddr', 'giaddr' are always zero
|
||||
//
|
||||
// Field DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE
|
||||
// ----- ------------ ------------ ----------- ----------- -----------
|
||||
// 'xid' selected by client selected by client 'xid' from server selected by client selected by client
|
||||
// DHCPOFFER message
|
||||
// 'secs' 0 or seconds since 0 or seconds since 0 or seconds since 0 0
|
||||
// DHCP process started DHCP process started DHCP process started
|
||||
// 'flags' Set 'BROADCAST' Set 'BROADCAST' Set 'BROADCAST' 0 0
|
||||
// flag if client flag if client flag if client
|
||||
// requires broadcast requires broadcast requires broadcast
|
||||
// reply reply reply
|
||||
// 'ciaddr' 0 client's IP 0 or client's IP 0 client's IP
|
||||
// (BOUND/RENEW/REBIND)
|
||||
// 'chaddr' client's MAC client's MAC client's MAC client's MAC client's MAC
|
||||
// 'sname' options or sname options or sname options or sname (unused) (unused)
|
||||
// 'file' options or file options or file options or file (unused) (unused)
|
||||
// 'options' options options options message type opt message type opt
|
||||
//
|
||||
// Option DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE
|
||||
// ------ ------------ ---------- ----------- ----------- -----------
|
||||
// Requested IP address MAY MUST NOT MUST (in MUST MUST NOT
|
||||
// SELECTING or
|
||||
// INIT-REBOOT)
|
||||
// MUST NOT (in
|
||||
// BOUND or
|
||||
// RENEWING)
|
||||
// IP address lease time MAY MUST NOT MAY MUST NOT MUST NOT
|
||||
// Use 'file'/'sname' fields MAY MAY MAY MAY MAY
|
||||
// Client identifier MAY MAY MAY MAY MAY
|
||||
// Vendor class identifier MAY MAY MAY MUST NOT MUST NOT
|
||||
// Server identifier MUST NOT MUST NOT MUST (after MUST MUST
|
||||
// SELECTING)
|
||||
// MUST NOT (after
|
||||
// INIT-REBOOT,
|
||||
// BOUND, RENEWING
|
||||
// or REBINDING)
|
||||
// Parameter request list MAY MAY MAY MUST NOT MUST NOT
|
||||
// Maximum message size MAY MAY MAY MUST NOT MUST NOT
|
||||
// Message SHOULD NOT SHOULD NOT SHOULD NOT SHOULD SHOULD
|
||||
// Site-specific MAY MAY MAY MUST NOT MUST NOT
|
||||
// All others MAY MAY MAY MUST NOT MUST NOT
|
||||
|
||||
|
||||
/*** Logging ***/
|
||||
|
||||
#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
|
||||
# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
|
||||
extern unsigned dhcp_verbose;
|
||||
# define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0)
|
||||
# if CONFIG_UDHCP_DEBUG >= 2
|
||||
void udhcp_dump_packet(struct dhcp_packet *packet);
|
||||
# define log2(...) do { if (dhcp_verbose >= 2) bb_info_msg(__VA_ARGS__); } while (0)
|
||||
# else
|
||||
# define udhcp_dump_packet(...) ((void)0)
|
||||
# define log2(...) ((void)0)
|
||||
# endif
|
||||
# if CONFIG_UDHCP_DEBUG >= 3
|
||||
# define log3(...) do { if (dhcp_verbose >= 3) bb_info_msg(__VA_ARGS__); } while (0)
|
||||
# else
|
||||
# define log3(...) ((void)0)
|
||||
# endif
|
||||
#else
|
||||
# define IF_UDHCP_VERBOSE(...)
|
||||
# define udhcp_dump_packet(...) ((void)0)
|
||||
# define log1(...) ((void)0)
|
||||
# define log2(...) ((void)0)
|
||||
# define log3(...) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
/*** Other shared functions ***/
|
||||
|
||||
/* 2nd param is "uint32_t*" */
|
||||
int udhcp_str2nip(const char *str, void *arg);
|
||||
/* 2nd param is "struct option_set**" */
|
||||
int udhcp_str2optset(const char *str, void *arg);
|
||||
|
||||
void udhcp_init_header(struct dhcp_packet *packet, char type);
|
||||
|
||||
int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd);
|
||||
|
||||
int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
|
||||
uint32_t source_nip, int source_port,
|
||||
uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
|
||||
int ifindex);
|
||||
|
||||
int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
|
||||
uint32_t source_nip, int source_port,
|
||||
uint32_t dest_nip, int dest_port);
|
||||
|
||||
void udhcp_sp_setup(void);
|
||||
int udhcp_sp_fd_set(fd_set *rfds, int extra_fd);
|
||||
int udhcp_sp_read(const fd_set *rfds);
|
||||
|
||||
int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac);
|
||||
|
||||
int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf);
|
||||
|
||||
/* Returns 1 if no reply received */
|
||||
int arpping(uint32_t test_nip,
|
||||
const uint8_t *safe_mac,
|
||||
uint32_t from_ip,
|
||||
uint8_t *from_mac,
|
||||
const char *interface);
|
||||
|
||||
/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */
|
||||
int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip);
|
||||
|
||||
#endif
|
1444
src/dhcpc/dhcpc.c
1444
src/dhcpc/dhcpc.c
File diff suppressed because it is too large
Load Diff
|
@ -1,39 +0,0 @@
|
|||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef UDHCP_DHCPC_H
|
||||
#define UDHCP_DHCPC_H 1
|
||||
|
||||
int udhcpc_main(int pipefd, char *interface);
|
||||
|
||||
struct client_config_t {
|
||||
uint8_t client_mac[6]; /* Our mac address */
|
||||
int ifindex; /* Index number of the interface to use */
|
||||
uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */
|
||||
const char *interface; /* The name of the interface to use */
|
||||
char *pidfile; /* Optionally store the process ID */
|
||||
const char *script; /* User script to run at dhcp events */
|
||||
struct option_set *options; /* list of DHCP options to send to server */
|
||||
uint8_t *clientid; /* Optional client id to use */
|
||||
uint8_t *vendorclass; /* Optional vendor class-id to use */
|
||||
uint8_t *hostname; /* Optional hostname to use */
|
||||
uint8_t *fqdn; /* Optional fully qualified domain name to use */
|
||||
|
||||
uint16_t first_secs;
|
||||
uint16_t last_secs;
|
||||
} FIX_ALIASING;
|
||||
|
||||
/* server_config sits in 1st half of bb_common_bufsiz1 */
|
||||
//#define client_config (*(struct client_config_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE / 2]))
|
||||
extern struct client_config_t client_config;
|
||||
|
||||
#define CLIENT_PORT 68
|
||||
#define CLIENT_PORT6 546
|
||||
|
||||
#define SERVER_PORT 67
|
||||
#define SERVER_PORT6 547
|
||||
|
||||
#endif
|
|
@ -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
|
|
@ -1,499 +0,0 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "extra.h"
|
||||
|
||||
const int const_int_1 = 1;
|
||||
const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
|
||||
|
||||
void xpipe(int filedes[2]) {
|
||||
if (pipe(filedes)) {
|
||||
fprintf (stderr, "can't create pipe");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void bb_signals(int sigs, void (*f)(int)) {
|
||||
int sig_no = 0;
|
||||
int bit = 1;
|
||||
|
||||
while (sigs) {
|
||||
if (sigs & bit) {
|
||||
sigs -= bit;
|
||||
signal(sig_no, f);
|
||||
}
|
||||
sig_no++;
|
||||
bit <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void close_on_exec_on(int fd) {
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
}
|
||||
|
||||
/* Turn on nonblocking I/O on a fd */
|
||||
void ndelay_on(int fd) {
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
if (flags & O_NONBLOCK)
|
||||
return;
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
|
||||
void ndelay_off(int fd) {
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
if (!(flags & O_NONBLOCK))
|
||||
return;
|
||||
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
// Die if we can't copy a string to freshly allocated memory.
|
||||
char* xstrdup(const char *s)
|
||||
{
|
||||
char *t;
|
||||
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
t = strdup(s);
|
||||
|
||||
if (t == NULL) {
|
||||
fprintf (stderr, "Memory allocation failed");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
char* hex2bin(char *dst, const char *str, int count)
|
||||
{
|
||||
errno = EINVAL;
|
||||
while (*str && count) {
|
||||
uint8_t val;
|
||||
uint8_t c = *str++;
|
||||
if (isdigit(c))
|
||||
val = c - '0';
|
||||
else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
|
||||
val = (c|0x20) - ('a' - 10);
|
||||
else
|
||||
return NULL;
|
||||
val <<= 4;
|
||||
c = *str;
|
||||
if (isdigit(c))
|
||||
val |= c - '0';
|
||||
else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
|
||||
val |= (c|0x20) - ('a' - 10);
|
||||
else if (c == ':' || c == '\0')
|
||||
val >>= 4;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
*dst++ = val;
|
||||
if (c != '\0')
|
||||
str++;
|
||||
if (*str == ':')
|
||||
str++;
|
||||
count--;
|
||||
}
|
||||
errno = (*str ? ERANGE : 0);
|
||||
return dst;
|
||||
}
|
||||
|
||||
#define DIE_ON_ERROR AI_CANONNAME
|
||||
|
||||
/* host: "1.2.3.4[:port]", "www.google.com[:port]"
|
||||
* port: if neither of above specifies port # */
|
||||
static len_and_sockaddr* str2sockaddr(
|
||||
const char *host, int port,
|
||||
sa_family_t af,
|
||||
int ai_flags)
|
||||
{
|
||||
int rc;
|
||||
len_and_sockaddr *r;
|
||||
struct addrinfo *result = NULL;
|
||||
struct addrinfo *used_res;
|
||||
const char *org_host = host; /* only for error msg */
|
||||
const char *cp;
|
||||
struct addrinfo hint;
|
||||
|
||||
r = NULL;
|
||||
|
||||
/* Ugly parsing of host:addr */
|
||||
if (host[0] == '[') {
|
||||
/* Even uglier parsing of [xx]:nn */
|
||||
host++;
|
||||
cp = strchr(host, ']');
|
||||
if (!cp || (cp[1] != ':' && cp[1] != '\0')) {
|
||||
/* Malformed: must be [xx]:nn or [xx] */
|
||||
fprintf(stderr, "bad address '%s'", org_host);
|
||||
if (ai_flags & DIE_ON_ERROR) {
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
cp = strrchr(host, ':');
|
||||
if (cp && strchr(host, ':') != cp) {
|
||||
/* There is more than one ':' (e.g. "::1") */
|
||||
cp = NULL; /* it's not a port spec */
|
||||
}
|
||||
}
|
||||
if (cp) { /* points to ":" or "]:" */
|
||||
int sz = cp - host + 1;
|
||||
|
||||
host = safe_strncpy(alloca(sz), host, sz);
|
||||
if (*cp != ':') {
|
||||
cp++; /* skip ']' */
|
||||
if (*cp == '\0') /* [xx] without port */
|
||||
goto skip;
|
||||
}
|
||||
cp++; /* skip ':' */
|
||||
port = bb_strtou(cp, NULL, 10);
|
||||
if (errno || (unsigned)port > 0xffff) {
|
||||
fprintf(stderr, "bad port spec '%s'", org_host);
|
||||
if (ai_flags & DIE_ON_ERROR) {
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
skip: ;
|
||||
}
|
||||
|
||||
/* Next two if blocks allow to skip getaddrinfo()
|
||||
* in case host name is a numeric IP(v6) address.
|
||||
* getaddrinfo() initializes DNS resolution machinery,
|
||||
* scans network config and such - tens of syscalls.
|
||||
*/
|
||||
/* If we were not asked specifically for IPv6,
|
||||
* check whether this is a numeric IPv4 */
|
||||
if(af != AF_INET6) {
|
||||
struct in_addr in4;
|
||||
if (inet_aton(host, &in4) != 0) {
|
||||
r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in));
|
||||
r->len = sizeof(struct sockaddr_in);
|
||||
r->u.sa.sa_family = AF_INET;
|
||||
r->u.sin.sin_addr = in4;
|
||||
goto set_port;
|
||||
}
|
||||
}
|
||||
/* If we were not asked specifically for IPv4,
|
||||
* check whether this is a numeric IPv6 */
|
||||
if (af != AF_INET) {
|
||||
struct in6_addr in6;
|
||||
if (inet_pton(AF_INET6, host, &in6) > 0) {
|
||||
r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in6));
|
||||
r->len = sizeof(struct sockaddr_in6);
|
||||
r->u.sa.sa_family = AF_INET6;
|
||||
r->u.sin6.sin6_addr = in6;
|
||||
goto set_port;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&hint, 0 , sizeof(hint));
|
||||
hint.ai_family = af;
|
||||
/* Need SOCK_STREAM, or else we get each address thrice (or more)
|
||||
* for each possible socket type (tcp,udp,raw...): */
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
hint.ai_flags = ai_flags & ~DIE_ON_ERROR;
|
||||
rc = getaddrinfo(host, NULL, &hint, &result);
|
||||
if (rc || !result) {
|
||||
fprintf (stderr, "bad address '%s'", org_host);
|
||||
if (ai_flags & DIE_ON_ERROR) {
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
goto ret;
|
||||
}
|
||||
used_res = result;
|
||||
r = xmalloc(LSA_LEN_SIZE + used_res->ai_addrlen);
|
||||
r->len = used_res->ai_addrlen;
|
||||
memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
|
||||
|
||||
set_port:
|
||||
set_nport(&r->u.sa, htons(port));
|
||||
ret:
|
||||
if (result)
|
||||
freeaddrinfo(result);
|
||||
return r;
|
||||
}
|
||||
|
||||
len_and_sockaddr* host2sockaddr(const char *host, int port) {
|
||||
return str2sockaddr(host, port, AF_UNSPEC, 0);
|
||||
}
|
||||
|
||||
len_and_sockaddr* xhost2sockaddr(const char *host, int port) {
|
||||
return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR);
|
||||
}
|
||||
|
||||
void* xmalloc(size_t size) {
|
||||
void *ptr = malloc(size);
|
||||
if (ptr == NULL && size != 0) {
|
||||
fprintf (stderr, "Memory allocation failed");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void set_nport(struct sockaddr *sa, unsigned port)
|
||||
{
|
||||
if (sa->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6 = (void*) sa;
|
||||
sin6->sin6_port = port;
|
||||
return;
|
||||
}
|
||||
if (sa->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sin = (void*) sa;
|
||||
sin->sin_port = port;
|
||||
return;
|
||||
}
|
||||
/* What? UNIX socket? IPX?? :) */
|
||||
}
|
||||
|
||||
int xsocket(int domain, int type, int protocol) {
|
||||
int r = socket(domain, type, protocol);
|
||||
|
||||
if (r < 0) {
|
||||
/* Hijack vaguely related config option */
|
||||
const char *s = "INET";
|
||||
# ifdef AF_PACKET
|
||||
if (domain == AF_PACKET) s = "PACKET";
|
||||
# endif
|
||||
# ifdef AF_NETLINK
|
||||
if (domain == AF_NETLINK) s = "NETLINK";
|
||||
# endif
|
||||
if (domain == AF_INET6) s = "INET6";
|
||||
|
||||
fprintf (stderr, "Error socket (AF_%s,%d,%d)", s, type, protocol);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// Die with an error message if we can't bind a socket to an address.
|
||||
void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) {
|
||||
if (bind(sockfd, my_addr, addrlen)) {
|
||||
fprintf (stderr, "Error: bind");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int ioctl_or_perror(int fd, unsigned request, void *argp) {
|
||||
va_list p;
|
||||
int ret = ioctl(fd, request, argp);
|
||||
|
||||
if (ret < 0) {
|
||||
perror ("Error ioctl");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Like strncpy but make sure the resulting string is always 0 terminated. */
|
||||
char* safe_strncpy(char *dst, const char *src, size_t size) {
|
||||
if (!size) return dst;
|
||||
dst[--size] = '\0';
|
||||
return strncpy(dst, src, size);
|
||||
}
|
||||
|
||||
/* Like strcpy but can copy overlapping strings. */
|
||||
void overlapping_strcpy(char *dst, const char *src) {
|
||||
/* Cheap optimization for dst == src case -
|
||||
* better to have it here than in many callers.
|
||||
*/
|
||||
if (dst != src) {
|
||||
while ((*dst = *src) != '\0') {
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Die if we can't allocate and zero size bytes of memory.
|
||||
void* xzalloc(size_t size) {
|
||||
void *ptr = xmalloc(size);
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* xrealloc(void *ptr, size_t size) {
|
||||
ptr = realloc(ptr, size);
|
||||
if (ptr == NULL && size != 0) {
|
||||
fprintf (stderr, "Memory allocation failed");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ssize_t safe_read(int fd, void *buf, size_t count) {
|
||||
ssize_t n;
|
||||
|
||||
do {
|
||||
n = read(fd, buf, count);
|
||||
} while (n < 0 && errno == EINTR);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
uint16_t inet_cksum(uint16_t *addr, int nleft) {
|
||||
/*
|
||||
* Our algorithm is simple, using a 32 bit accumulator,
|
||||
* we add sequential 16 bit words to it, and at the end, fold
|
||||
* back all the carry bits from the top 16 bits into the lower
|
||||
* 16 bits.
|
||||
*/
|
||||
unsigned sum = 0;
|
||||
while (nleft > 1) {
|
||||
sum += *addr++;
|
||||
nleft -= 2;
|
||||
}
|
||||
|
||||
/* Mop up an odd byte, if necessary */
|
||||
if (nleft == 1) {
|
||||
if (BB_LITTLE_ENDIAN)
|
||||
sum += *(uint8_t*)addr;
|
||||
else
|
||||
sum += *(uint8_t*)addr << 8;
|
||||
}
|
||||
|
||||
/* Add back carry outs from top 16 bits to low 16 bits */
|
||||
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
|
||||
sum += (sum >> 16); /* add carry */
|
||||
|
||||
return (uint16_t)~sum;
|
||||
}
|
||||
|
||||
/* Emit a string of hex representation of bytes */
|
||||
char* bin2hex(char *p, const char *cp, int count) {
|
||||
while (count) {
|
||||
unsigned char c = *cp++;
|
||||
/* put lowercase hex digits */
|
||||
*p++ = 0x20 | bb_hexdigits_upcase[c >> 4];
|
||||
*p++ = 0x20 | bb_hexdigits_upcase[c & 0xf];
|
||||
count--;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char* xasprintf(const char *format, ...) {
|
||||
va_list p;
|
||||
int r;
|
||||
char *string_ptr;
|
||||
|
||||
va_start(p, format);
|
||||
r = vasprintf(&string_ptr, format, p);
|
||||
va_end(p);
|
||||
|
||||
if (r < 0) {
|
||||
fprintf (stderr, "Memory allocation failed");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return string_ptr;
|
||||
}
|
||||
|
||||
static unsigned long long ret_ERANGE(void)
|
||||
{
|
||||
errno = ERANGE; /* this ain't as small as it looks (on glibc) */
|
||||
return ULLONG_MAX;
|
||||
}
|
||||
|
||||
static unsigned long long handle_errors(unsigned long long v, char **endp)
|
||||
{
|
||||
char next_ch = **endp;
|
||||
|
||||
/* errno is already set to ERANGE by strtoXXX if value overflowed */
|
||||
if (next_ch) {
|
||||
/* "1234abcg" or out-of-range? */
|
||||
if (isalnum(next_ch) || errno)
|
||||
return ret_ERANGE();
|
||||
/* good number, just suspicious terminator */
|
||||
errno = EINVAL;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
unsigned bb_strtou(const char *arg, char **endp, int base) {
|
||||
unsigned long v;
|
||||
char *endptr;
|
||||
|
||||
if (!endp) endp = &endptr;
|
||||
*endp = (char*) arg;
|
||||
|
||||
if (!isalnum(arg[0])) return ret_ERANGE();
|
||||
errno = 0;
|
||||
v = strtoul(arg, endp, base);
|
||||
if (v > UINT_MAX) return ret_ERANGE();
|
||||
return handle_errors(v, endp);
|
||||
}
|
||||
|
||||
char* strncpy_IFNAMSIZ(char *dst, const char *src) {
|
||||
#ifndef IFNAMSIZ
|
||||
enum { IFNAMSIZ = 16 };
|
||||
#endif
|
||||
return strncpy(dst, src, IFNAMSIZ);
|
||||
}
|
||||
|
||||
void setsockopt_reuseaddr(int fd) {
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
|
||||
}
|
||||
|
||||
int setsockopt_broadcast(int fd) {
|
||||
return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
|
||||
}
|
||||
|
||||
#ifdef SO_BINDTODEVICE
|
||||
int setsockopt_bindtodevice(int fd, const char *iface) {
|
||||
int r;
|
||||
struct ifreq ifr;
|
||||
strncpy_IFNAMSIZ(ifr.ifr_name, iface);
|
||||
/* NB: passing (iface, strlen(iface) + 1) does not work!
|
||||
* (maybe it works on _some_ kernels, but not on 2.6.26)
|
||||
* Actually, ifr_name is at offset 0, and in practice
|
||||
* just giving char[IFNAMSIZ] instead of struct ifreq works too.
|
||||
* But just in case it's not true on some obscure arch... */
|
||||
r = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
|
||||
if (r)
|
||||
fprintf (stderr, "can't bind to interface %s", iface);
|
||||
return r;
|
||||
}
|
||||
#else
|
||||
int setsockopt_bindtodevice(int fd, const char *iface) {
|
||||
fprintf (stderr, "SO_BINDTODEVICE is not supported on this system");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned monotonic_sec(void) {
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
ssize_t safe_write(int fd, const void *buf, size_t count) {
|
||||
ssize_t n;
|
||||
|
||||
do {
|
||||
n = write(fd, buf, count);
|
||||
} while (n < 0 && errno == EINTR);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
#ifndef __EXTRA_H__
|
||||
#define __EXTRA_H__ 1
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* In this form code with pipes is much more readable */
|
||||
struct fd_pair { int rd; int wr; };
|
||||
#define piped_pair(pair) pipe(&((pair).rd))
|
||||
#define xpiped_pair(pair) xpipe(&((pair).rd))
|
||||
|
||||
#define ALIGN1 __attribute__((aligned(1)))
|
||||
#define ALIGN2 __attribute__((aligned(2)))
|
||||
#define PACKED __attribute__ ((__packed__))
|
||||
#define ALIGNED(m) __attribute__ ((__aligned__(m)))
|
||||
#define NOINLINE __attribute__((__noinline__))
|
||||
|
||||
#define CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS 80
|
||||
|
||||
#define host_and_af2sockaddr(host, port, af) host2sockaddr((host), (port))
|
||||
#define xhost_and_af2sockaddr(host, port, af) xhost2sockaddr((host), (port))
|
||||
|
||||
/* ---- Endian Detection ------------------------------------ */
|
||||
|
||||
#include <limits.h>
|
||||
#if defined(__digital__) && defined(__unix__)
|
||||
# include <sex.h>
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|
||||
|| defined(__APPLE__)
|
||||
# include <sys/resource.h> /* rlimit */
|
||||
# include <machine/endian.h>
|
||||
# define bswap_64 __bswap64
|
||||
# define bswap_32 __bswap32
|
||||
# define bswap_16 __bswap16
|
||||
#else
|
||||
# include <byteswap.h>
|
||||
# include <endian.h>
|
||||
#endif
|
||||
|
||||
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN
|
||||
# define BB_BIG_ENDIAN 1
|
||||
# define BB_LITTLE_ENDIAN 0
|
||||
#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define BB_BIG_ENDIAN 0
|
||||
# define BB_LITTLE_ENDIAN 1
|
||||
#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN
|
||||
# define BB_BIG_ENDIAN 1
|
||||
# define BB_LITTLE_ENDIAN 0
|
||||
#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
# define BB_BIG_ENDIAN 0
|
||||
# define BB_LITTLE_ENDIAN 1
|
||||
#elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
|
||||
# define BB_BIG_ENDIAN 1
|
||||
# define BB_LITTLE_ENDIAN 0
|
||||
#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define BB_BIG_ENDIAN 0
|
||||
# define BB_LITTLE_ENDIAN 1
|
||||
#elif defined(__386__)
|
||||
# define BB_BIG_ENDIAN 0
|
||||
# define BB_LITTLE_ENDIAN 1
|
||||
#else
|
||||
# error "Can't determine endianness"
|
||||
#endif
|
||||
|
||||
#if ULONG_MAX > 0xffffffff
|
||||
# define bb_bswap_64(x) bswap_64(x)
|
||||
#endif
|
||||
|
||||
/* SWAP_LEnn means "convert CPU<->little_endian by swapping bytes" */
|
||||
#if BB_BIG_ENDIAN
|
||||
# define SWAP_BE16(x) (x)
|
||||
# define SWAP_BE32(x) (x)
|
||||
# define SWAP_BE64(x) (x)
|
||||
# define SWAP_LE16(x) bswap_16(x)
|
||||
# define SWAP_LE32(x) bswap_32(x)
|
||||
# define SWAP_LE64(x) bb_bswap_64(x)
|
||||
# define IF_BIG_ENDIAN(...) __VA_ARGS__
|
||||
# define IF_LITTLE_ENDIAN(...)
|
||||
#else
|
||||
# define SWAP_BE16(x) bswap_16(x)
|
||||
# define SWAP_BE32(x) bswap_32(x)
|
||||
# define SWAP_BE64(x) bb_bswap_64(x)
|
||||
# define SWAP_LE16(x) (x)
|
||||
# define SWAP_LE32(x) (x)
|
||||
# define SWAP_LE64(x) (x)
|
||||
# define IF_BIG_ENDIAN(...)
|
||||
# define IF_LITTLE_ENDIAN(...) __VA_ARGS__
|
||||
#endif
|
||||
|
||||
/* At 4.4 gcc become much more anal about this, need to use "aliased" types */
|
||||
#if __GNUC_PREREQ(4,4)
|
||||
# define FIX_ALIASING __attribute__((__may_alias__))
|
||||
#else
|
||||
# define FIX_ALIASING
|
||||
#endif
|
||||
|
||||
/* ---- Unaligned access ------------------------------------ */
|
||||
|
||||
#include <stdint.h>
|
||||
typedef int bb__aliased_int FIX_ALIASING;
|
||||
typedef long bb__aliased_long FIX_ALIASING;
|
||||
typedef uint16_t bb__aliased_uint16_t FIX_ALIASING;
|
||||
typedef uint32_t bb__aliased_uint32_t FIX_ALIASING;
|
||||
typedef uint64_t bb__aliased_uint64_t FIX_ALIASING;
|
||||
|
||||
/* NB: unaligned parameter should be a pointer, aligned one -
|
||||
* a lvalue. This makes it more likely to not swap them by mistake
|
||||
*/
|
||||
#if defined(i386) || defined(__x86_64__) || defined(__powerpc__)
|
||||
# define move_from_unaligned_int(v, intp) ((v) = *(bb__aliased_int*)(intp))
|
||||
# define move_from_unaligned_long(v, longp) ((v) = *(bb__aliased_long*)(longp))
|
||||
# define move_from_unaligned16(v, u16p) ((v) = *(bb__aliased_uint16_t*)(u16p))
|
||||
# define move_from_unaligned32(v, u32p) ((v) = *(bb__aliased_uint32_t*)(u32p))
|
||||
# define move_to_unaligned16(u16p, v) (*(bb__aliased_uint16_t*)(u16p) = (v))
|
||||
# define move_to_unaligned32(u32p, v) (*(bb__aliased_uint32_t*)(u32p) = (v))
|
||||
/* #elif ... - add your favorite arch today! */
|
||||
#else
|
||||
/* performs reasonably well (gcc usually inlines memcpy here) */
|
||||
# define move_from_unaligned_int(v, intp) (memcpy(&(v), (intp), sizeof(int)))
|
||||
# define move_from_unaligned_long(v, longp) (memcpy(&(v), (longp), sizeof(long)))
|
||||
# define move_from_unaligned16(v, u16p) (memcpy(&(v), (u16p), 2))
|
||||
# define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4))
|
||||
# define move_to_unaligned16(u16p, v) do { \
|
||||
uint16_t __t = (v); \
|
||||
memcpy((u16p), &__t, 2); \
|
||||
} while (0)
|
||||
# define move_to_unaligned32(u32p, v) do { \
|
||||
uint32_t __t = (v); \
|
||||
memcpy((u32p), &__t, 4); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if defined(i386) || defined(__x86_64__) || defined(__mips__) || defined(__cris__)
|
||||
/* add other arches which benefit from this... */
|
||||
typedef signed char smallint;
|
||||
typedef unsigned char smalluint;
|
||||
#else
|
||||
/* for arches where byte accesses generate larger code: */
|
||||
typedef int smallint;
|
||||
typedef unsigned smalluint;
|
||||
#endif
|
||||
|
||||
extern const int const_int_1;
|
||||
|
||||
typedef struct len_and_sockaddr {
|
||||
socklen_t len;
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
} u;
|
||||
} len_and_sockaddr;
|
||||
|
||||
enum {
|
||||
LSA_LEN_SIZE = offsetof(len_and_sockaddr, u),
|
||||
LSA_SIZEOF_SA = sizeof(
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
void bb_signals(int sigs, void (*f)(int));
|
||||
void close_on_exec_on(int fd);
|
||||
void xpipe(int filedes[2]);
|
||||
void ndelay_on(int fd);
|
||||
void ndelay_off(int fd);
|
||||
char* xstrdup(const char *s);
|
||||
char* hex2bin(char *dst, const char *str, int count);
|
||||
char* bin2hex(char *p, const char *cp, int count);
|
||||
|
||||
len_and_sockaddr* host2sockaddr(const char *host, int port);
|
||||
len_and_sockaddr* xhost2sockaddr(const char *host, int port);
|
||||
void* xmalloc(size_t size);
|
||||
void set_nport(struct sockaddr *sa, unsigned port);
|
||||
int xsocket(int domain, int type, int protocol);
|
||||
void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
|
||||
int ioctl_or_perror(int fd, unsigned request, void *argp);
|
||||
char* safe_strncpy(char *dst, const char *src, size_t size);
|
||||
void overlapping_strcpy(char *dst, const char *src);
|
||||
void* xzalloc(size_t size);
|
||||
void* xrealloc(void *ptr, size_t size);
|
||||
ssize_t safe_read(int fd, void *buf, size_t count);
|
||||
ssize_t safe_write(int fd, const void *buf, size_t count);
|
||||
|
||||
uint16_t inet_cksum(uint16_t *addr, int nleft);
|
||||
char* xasprintf(const char *format, ...);
|
||||
|
||||
unsigned bb_strtou(const char *arg, char **endp, int base);
|
||||
char* strncpy_IFNAMSIZ(char *dst, const char *src);
|
||||
void setsockopt_reuseaddr(int fd);
|
||||
int setsockopt_broadcast(int fd);
|
||||
int setsockopt_bindtodevice(int fd, const char *iface);
|
||||
unsigned monotonic_sec(void);
|
||||
|
||||
#endif
|
|
@ -1,40 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "dhcpc.h"
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
/* Preparar el pipe que viene en STDOUT */
|
||||
int pipe;
|
||||
int null_fd;
|
||||
|
||||
pipe = dup (STDOUT_FILENO);
|
||||
null_fd = open ("/dev/null", O_RDWR);
|
||||
|
||||
close (STDOUT_FILENO);
|
||||
close (STDIN_FILENO);
|
||||
|
||||
dup2 (null_fd, STDOUT_FILENO);
|
||||
dup2 (null_fd, STDIN_FILENO);
|
||||
|
||||
close (null_fd);
|
||||
|
||||
/* Parsear aquí los argumentos */
|
||||
if (argc < 2) {
|
||||
fprintf (stderr, "Missing interface argument");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
udhcpc_main (pipe, argv[1]);
|
||||
|
||||
close (STDOUT_FILENO);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,194 +0,0 @@
|
|||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Packet ops
|
||||
*
|
||||
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <netpacket/packet.h>
|
||||
|
||||
void udhcp_init_header(struct dhcp_packet *packet, char type)
|
||||
{
|
||||
memset(packet, 0, sizeof(*packet));
|
||||
packet->op = BOOTREQUEST; /* if client to a server */
|
||||
switch (type) {
|
||||
case DHCPOFFER:
|
||||
case DHCPACK:
|
||||
case DHCPNAK:
|
||||
packet->op = BOOTREPLY; /* if server to client */
|
||||
}
|
||||
packet->htype = 1; /* ethernet */
|
||||
packet->hlen = 6;
|
||||
packet->cookie = htonl(DHCP_MAGIC);
|
||||
if (DHCP_END != 0)
|
||||
packet->options[0] = DHCP_END;
|
||||
udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type);
|
||||
}
|
||||
|
||||
/* Read a packet from socket fd, return -1 on read error, -2 on packet error */
|
||||
int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd)
|
||||
{
|
||||
int bytes;
|
||||
|
||||
memset(packet, 0, sizeof(*packet));
|
||||
bytes = safe_read(fd, packet, sizeof(*packet));
|
||||
if (bytes < 0) {
|
||||
log1("Packet read error, ignoring");
|
||||
return bytes; /* returns -1 */
|
||||
}
|
||||
|
||||
if (bytes < offsetof(struct dhcp_packet, options)
|
||||
|| packet->cookie != htonl(DHCP_MAGIC)
|
||||
) {
|
||||
fprintf (stderr, "Packet with bad magic, ignoring");
|
||||
return -2;
|
||||
}
|
||||
log1("Received a packet");
|
||||
udhcp_dump_packet(packet);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* Construct a ip/udp header for a packet, send packet */
|
||||
int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
|
||||
uint32_t source_nip, int source_port,
|
||||
uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
|
||||
int ifindex)
|
||||
{
|
||||
struct sockaddr_ll dest_sll;
|
||||
struct ip_udp_dhcp_packet packet;
|
||||
unsigned padding;
|
||||
int fd;
|
||||
int result = -1;
|
||||
const char *msg;
|
||||
|
||||
fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
|
||||
if (fd < 0) {
|
||||
msg = "socket(%s)";
|
||||
goto ret_msg;
|
||||
}
|
||||
|
||||
memset(&dest_sll, 0, sizeof(dest_sll));
|
||||
memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data));
|
||||
packet.data = *dhcp_pkt; /* struct copy */
|
||||
|
||||
dest_sll.sll_family = AF_PACKET;
|
||||
dest_sll.sll_protocol = htons(ETH_P_IP);
|
||||
dest_sll.sll_ifindex = ifindex;
|
||||
dest_sll.sll_halen = 6;
|
||||
memcpy(dest_sll.sll_addr, dest_arp, 6);
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) {
|
||||
msg = "bind(%s)";
|
||||
goto ret_close;
|
||||
}
|
||||
|
||||
/* We were sending full-sized DHCP packets (zero padded),
|
||||
* but some badly configured servers were seen dropping them.
|
||||
* Apparently they drop all DHCP packets >576 *ethernet* octets big,
|
||||
* whereas they may only drop packets >576 *IP* octets big
|
||||
* (which for typical Ethernet II means 590 octets: 6+6+2 + 576).
|
||||
*
|
||||
* In order to work with those buggy servers,
|
||||
* we truncate packets after end option byte.
|
||||
*
|
||||
* However, RFC 1542 says "The IP Total Length and UDP Length
|
||||
* must be large enough to contain the minimal BOOTP header of 300 octets".
|
||||
* Thus, we retain enough padding to not go below 300 BOOTP bytes.
|
||||
* Some devices have filters which drop DHCP packets shorter than that.
|
||||
*/
|
||||
padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options);
|
||||
if (padding > DHCP_SIZE - 300)
|
||||
padding = DHCP_SIZE - 300;
|
||||
|
||||
packet.ip.protocol = IPPROTO_UDP;
|
||||
packet.ip.saddr = source_nip;
|
||||
packet.ip.daddr = dest_nip;
|
||||
packet.udp.source = htons(source_port);
|
||||
packet.udp.dest = htons(dest_port);
|
||||
/* size, excluding IP header: */
|
||||
packet.udp.len = htons(UDP_DHCP_SIZE - padding);
|
||||
/* for UDP checksumming, ip.len is set to UDP packet len */
|
||||
packet.ip.tot_len = packet.udp.len;
|
||||
packet.udp.check = inet_cksum((uint16_t *)&packet,
|
||||
IP_UDP_DHCP_SIZE - padding);
|
||||
/* but for sending, it is set to IP packet len */
|
||||
packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding);
|
||||
packet.ip.ihl = sizeof(packet.ip) >> 2;
|
||||
packet.ip.version = IPVERSION;
|
||||
packet.ip.ttl = IPDEFTTL;
|
||||
packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip));
|
||||
|
||||
udhcp_dump_packet(dhcp_pkt);
|
||||
result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0,
|
||||
(struct sockaddr *) &dest_sll, sizeof(dest_sll));
|
||||
msg = "sendto";
|
||||
ret_close:
|
||||
close(fd);
|
||||
if (result < 0) {
|
||||
ret_msg:
|
||||
fprintf(stderr, msg, "PACKET");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Let the kernel do all the work for packet generation */
|
||||
int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
|
||||
uint32_t source_nip, int source_port,
|
||||
uint32_t dest_nip, int dest_port)
|
||||
{
|
||||
struct sockaddr_in sa;
|
||||
unsigned padding;
|
||||
int fd;
|
||||
int result = -1;
|
||||
const char *msg;
|
||||
|
||||
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (fd < 0) {
|
||||
msg = "socket(%s)";
|
||||
goto ret_msg;
|
||||
}
|
||||
setsockopt_reuseaddr(fd);
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(source_port);
|
||||
sa.sin_addr.s_addr = source_nip;
|
||||
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
|
||||
msg = "bind(%s)";
|
||||
goto ret_close;
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(dest_port);
|
||||
sa.sin_addr.s_addr = dest_nip;
|
||||
if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
|
||||
msg = "connect";
|
||||
goto ret_close;
|
||||
}
|
||||
|
||||
udhcp_dump_packet(dhcp_pkt);
|
||||
padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options);
|
||||
if (padding > DHCP_SIZE - 300)
|
||||
padding = DHCP_SIZE - 300;
|
||||
result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding);
|
||||
msg = "write";
|
||||
ret_close:
|
||||
close(fd);
|
||||
if (result < 0) {
|
||||
ret_msg:
|
||||
fprintf(stderr, msg, "UDP");
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Signal pipe infrastructure. A reliable way of delivering signals.
|
||||
*
|
||||
* Russ Dill <Russ.Dill@asu.edu> December 2003
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "extra.h"
|
||||
|
||||
/* Global variable: we access it from signal handler */
|
||||
static struct fd_pair signal_pipe;
|
||||
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
unsigned char ch = sig; /* use char, avoid dealing with partial writes */
|
||||
if (write(signal_pipe.wr, &ch, 1) != 1) {
|
||||
fprintf (stderr, "can't send signal");
|
||||
}
|
||||
}
|
||||
|
||||
/* Call this before doing anything else. Sets up the socket pair
|
||||
* and installs the signal handler */
|
||||
void udhcp_sp_setup(void)
|
||||
{
|
||||
/* was socketpair, but it needs AF_UNIX in kernel */
|
||||
xpiped_pair(signal_pipe);
|
||||
close_on_exec_on(signal_pipe.rd);
|
||||
close_on_exec_on(signal_pipe.wr);
|
||||
ndelay_on(signal_pipe.wr);
|
||||
bb_signals(0
|
||||
+ (1 << SIGUSR1)
|
||||
+ (1 << SIGUSR2)
|
||||
+ (1 << SIGTERM)
|
||||
, signal_handler);
|
||||
}
|
||||
|
||||
/* Quick little function to setup the rfds. Will return the
|
||||
* max_fd for use with select. Limited in that you can only pass
|
||||
* one extra fd */
|
||||
int udhcp_sp_fd_set(fd_set *rfds, int extra_fd)
|
||||
{
|
||||
FD_ZERO(rfds);
|
||||
FD_SET(signal_pipe.rd, rfds);
|
||||
if (extra_fd >= 0) {
|
||||
close_on_exec_on(extra_fd);
|
||||
FD_SET(extra_fd, rfds);
|
||||
}
|
||||
return signal_pipe.rd > extra_fd ? signal_pipe.rd : extra_fd;
|
||||
}
|
||||
|
||||
/* Read a signal from the signal pipe. Returns 0 if there is
|
||||
* no signal, -1 on error (and sets errno appropriately), and
|
||||
* your signal on success */
|
||||
int udhcp_sp_read(const fd_set *rfds)
|
||||
{
|
||||
unsigned char sig;
|
||||
|
||||
if (!FD_ISSET(signal_pipe.rd, rfds))
|
||||
return 0;
|
||||
|
||||
if (safe_read(signal_pipe.rd, &sig, 1) != 1)
|
||||
return -1;
|
||||
|
||||
return sig;
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* DHCP server client/server socket creation
|
||||
*
|
||||
* udhcp client/server
|
||||
* Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
|
||||
* Chris Trew <ctrew@moreton.com.au>
|
||||
*
|
||||
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "extra.h"
|
||||
#include "common.h"
|
||||
|
||||
int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac)
|
||||
{
|
||||
/* char buffer instead of bona-fide struct avoids aliasing warning */
|
||||
char ifr_buf[sizeof(struct ifreq)];
|
||||
struct ifreq *const ifr = (void *)ifr_buf;
|
||||
|
||||
int fd;
|
||||
struct sockaddr_in *our_ip;
|
||||
|
||||
memset(ifr, 0, sizeof(*ifr));
|
||||
fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
||||
|
||||
ifr->ifr_addr.sa_family = AF_INET;
|
||||
strncpy_IFNAMSIZ(ifr->ifr_name, interface);
|
||||
if (nip) {
|
||||
if (ioctl_or_perror(fd, SIOCGIFADDR, ifr)
|
||||
) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
our_ip = (struct sockaddr_in *) &ifr->ifr_addr;
|
||||
*nip = our_ip->sin_addr.s_addr;
|
||||
log1("IP %s", inet_ntoa(our_ip->sin_addr));
|
||||
}
|
||||
|
||||
if (ifindex) {
|
||||
if (ioctl_or_perror(fd, SIOCGIFINDEX, ifr) != 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
log1("Adapter index %d", ifr->ifr_ifindex);
|
||||
*ifindex = ifr->ifr_ifindex;
|
||||
}
|
||||
|
||||
if (mac) {
|
||||
if (ioctl_or_perror(fd, SIOCGIFHWADDR, ifr) != 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
memcpy(mac, ifr->ifr_hwaddr.sa_data, 6);
|
||||
log1("MAC %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 1. None of the callers expects it to ever fail */
|
||||
/* 2. ip was always INADDR_ANY */
|
||||
int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in addr;
|
||||
char *colon;
|
||||
|
||||
log1("Opening listen socket on *:%d %s", port, inf);
|
||||
fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
setsockopt_reuseaddr(fd);
|
||||
if (setsockopt_broadcast(fd) == -1) {
|
||||
fprintf (stderr, "SO_BROADCAST");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* SO_BINDTODEVICE doesn't work on ethernet aliases (ethN:M) */
|
||||
colon = strrchr(inf, ':');
|
||||
if (colon)
|
||||
*colon = '\0';
|
||||
|
||||
if (setsockopt_bindtodevice(fd, inf)) {
|
||||
exit (EXIT_FAILURE); /* warning is already printed */
|
||||
}
|
||||
|
||||
if (colon)
|
||||
*colon = ':';
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
/* addr.sin_addr.s_addr = ip; - all-zeros is INADDR_ANY */
|
||||
xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
return fd;
|
||||
}
|
292
src/gettext.h
292
src/gettext.h
|
@ -1,292 +0,0 @@
|
|||
/* Convenience header for conditional use of GNU <libintl.h>.
|
||||
Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2016 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _LIBGETTEXT_H
|
||||
#define _LIBGETTEXT_H 1
|
||||
|
||||
/* NLS can be disabled through the configure --disable-nls option. */
|
||||
#if ENABLE_NLS
|
||||
|
||||
/* Get declarations of GNU message catalog functions. */
|
||||
# include <libintl.h>
|
||||
|
||||
/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
|
||||
the gettext() and ngettext() macros. This is an alternative to calling
|
||||
textdomain(), and is useful for libraries. */
|
||||
# ifdef DEFAULT_TEXT_DOMAIN
|
||||
# undef gettext
|
||||
# define gettext(Msgid) \
|
||||
dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
|
||||
# undef ngettext
|
||||
# define ngettext(Msgid1, Msgid2, N) \
|
||||
dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
|
||||
chokes if dcgettext is defined as a macro. So include it now, to make
|
||||
later inclusions of <locale.h> a NOP. We don't include <libintl.h>
|
||||
as well because people using "gettext.h" will not include <libintl.h>,
|
||||
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
|
||||
is OK. */
|
||||
#if defined(__sun)
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
|
||||
<libintl.h>, which chokes if dcgettext is defined as a macro. So include
|
||||
it now, to make later inclusions of <libintl.h> a NOP. */
|
||||
#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
|
||||
# include <cstdlib>
|
||||
# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H
|
||||
# include <libintl.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Disabled NLS.
|
||||
The casts to 'const char *' serve the purpose of producing warnings
|
||||
for invalid uses of the value returned from these functions.
|
||||
On pre-ANSI systems without 'const', the config.h file is supposed to
|
||||
contain "#define const". */
|
||||
# undef gettext
|
||||
# define gettext(Msgid) ((const char *) (Msgid))
|
||||
# undef dgettext
|
||||
# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
|
||||
# undef dcgettext
|
||||
# define dcgettext(Domainname, Msgid, Category) \
|
||||
((void) (Category), dgettext (Domainname, Msgid))
|
||||
# undef ngettext
|
||||
# define ngettext(Msgid1, Msgid2, N) \
|
||||
((N) == 1 \
|
||||
? ((void) (Msgid2), (const char *) (Msgid1)) \
|
||||
: ((void) (Msgid1), (const char *) (Msgid2)))
|
||||
# undef dngettext
|
||||
# define dngettext(Domainname, Msgid1, Msgid2, N) \
|
||||
((void) (Domainname), ngettext (Msgid1, Msgid2, N))
|
||||
# undef dcngettext
|
||||
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
|
||||
((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N))
|
||||
# undef textdomain
|
||||
# define textdomain(Domainname) ((const char *) (Domainname))
|
||||
# undef bindtextdomain
|
||||
# define bindtextdomain(Domainname, Dirname) \
|
||||
((void) (Domainname), (const char *) (Dirname))
|
||||
# undef bind_textdomain_codeset
|
||||
# define bind_textdomain_codeset(Domainname, Codeset) \
|
||||
((void) (Domainname), (const char *) (Codeset))
|
||||
|
||||
#endif
|
||||
|
||||
/* Prefer gnulib's setlocale override over libintl's setlocale override. */
|
||||
#ifdef GNULIB_defined_setlocale
|
||||
# undef setlocale
|
||||
# define setlocale rpl_setlocale
|
||||
#endif
|
||||
|
||||
/* A pseudo function call that serves as a marker for the automated
|
||||
extraction of messages, but does not call gettext(). The run-time
|
||||
translation is done at a different place in the code.
|
||||
The argument, String, should be a literal string. Concatenated strings
|
||||
and other string expressions won't work.
|
||||
The macro's expansion is not parenthesized, so that it is suitable as
|
||||
initializer for static 'char[]' or 'const char[]' variables. */
|
||||
#define gettext_noop(String) String
|
||||
|
||||
/* The separator between msgctxt and msgid in a .mo file. */
|
||||
#define GETTEXT_CONTEXT_GLUE "\004"
|
||||
|
||||
/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
|
||||
MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be
|
||||
short and rarely need to change.
|
||||
The letter 'p' stands for 'particular' or 'special'. */
|
||||
#ifdef DEFAULT_TEXT_DOMAIN
|
||||
# define pgettext(Msgctxt, Msgid) \
|
||||
pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
|
||||
#else
|
||||
# define pgettext(Msgctxt, Msgid) \
|
||||
pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
|
||||
#endif
|
||||
#define dpgettext(Domainname, Msgctxt, Msgid) \
|
||||
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
|
||||
#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
|
||||
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
|
||||
#ifdef DEFAULT_TEXT_DOMAIN
|
||||
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
|
||||
npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
#else
|
||||
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
|
||||
npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
#endif
|
||||
#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
|
||||
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
|
||||
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static const char *
|
||||
pgettext_aux (const char *domain,
|
||||
const char *msg_ctxt_id, const char *msgid,
|
||||
int category)
|
||||
{
|
||||
const char *translation = dcgettext (domain, msg_ctxt_id, category);
|
||||
if (translation == msg_ctxt_id)
|
||||
return msgid;
|
||||
else
|
||||
return translation;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static const char *
|
||||
npgettext_aux (const char *domain,
|
||||
const char *msg_ctxt_id, const char *msgid,
|
||||
const char *msgid_plural, unsigned long int n,
|
||||
int category)
|
||||
{
|
||||
const char *translation =
|
||||
dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
|
||||
if (translation == msg_ctxt_id || translation == msgid_plural)
|
||||
return (n == 1 ? msgid : msgid_plural);
|
||||
else
|
||||
return translation;
|
||||
}
|
||||
|
||||
/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID
|
||||
can be arbitrary expressions. But for string literals these macros are
|
||||
less efficient than those above. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \
|
||||
/* || __STDC_VERSION__ >= 199901L */ )
|
||||
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1
|
||||
#else
|
||||
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0
|
||||
#endif
|
||||
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#define pgettext_expr(Msgctxt, Msgid) \
|
||||
dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
|
||||
#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
|
||||
dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static const char *
|
||||
dcpgettext_expr (const char *domain,
|
||||
const char *msgctxt, const char *msgid,
|
||||
int category)
|
||||
{
|
||||
size_t msgctxt_len = strlen (msgctxt) + 1;
|
||||
size_t msgid_len = strlen (msgid) + 1;
|
||||
const char *translation;
|
||||
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
char msg_ctxt_id[msgctxt_len + msgid_len];
|
||||
#else
|
||||
char buf[1024];
|
||||
char *msg_ctxt_id =
|
||||
(msgctxt_len + msgid_len <= sizeof (buf)
|
||||
? buf
|
||||
: (char *) malloc (msgctxt_len + msgid_len));
|
||||
if (msg_ctxt_id != NULL)
|
||||
#endif
|
||||
{
|
||||
int found_translation;
|
||||
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
|
||||
msg_ctxt_id[msgctxt_len - 1] = '\004';
|
||||
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
|
||||
translation = dcgettext (domain, msg_ctxt_id, category);
|
||||
found_translation = (translation != msg_ctxt_id);
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
if (msg_ctxt_id != buf)
|
||||
free (msg_ctxt_id);
|
||||
#endif
|
||||
if (found_translation)
|
||||
return translation;
|
||||
}
|
||||
return msgid;
|
||||
}
|
||||
|
||||
#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
|
||||
dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
|
||||
dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static const char *
|
||||
dcnpgettext_expr (const char *domain,
|
||||
const char *msgctxt, const char *msgid,
|
||||
const char *msgid_plural, unsigned long int n,
|
||||
int category)
|
||||
{
|
||||
size_t msgctxt_len = strlen (msgctxt) + 1;
|
||||
size_t msgid_len = strlen (msgid) + 1;
|
||||
const char *translation;
|
||||
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
char msg_ctxt_id[msgctxt_len + msgid_len];
|
||||
#else
|
||||
char buf[1024];
|
||||
char *msg_ctxt_id =
|
||||
(msgctxt_len + msgid_len <= sizeof (buf)
|
||||
? buf
|
||||
: (char *) malloc (msgctxt_len + msgid_len));
|
||||
if (msg_ctxt_id != NULL)
|
||||
#endif
|
||||
{
|
||||
int found_translation;
|
||||
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
|
||||
msg_ctxt_id[msgctxt_len - 1] = '\004';
|
||||
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
|
||||
translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
|
||||
found_translation = !(translation == msg_ctxt_id || translation == msgid_plural);
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
if (msg_ctxt_id != buf)
|
||||
free (msg_ctxt_id);
|
||||
#endif
|
||||
if (found_translation)
|
||||
return translation;
|
||||
}
|
||||
return (n == 1 ? msgid : msgid_plural);
|
||||
}
|
||||
|
||||
#endif /* _LIBGETTEXT_H */
|
1266
src/interfaces.c
1266
src/interfaces.c
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
|||
* interfaces.h
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2018 - Félix Arreola Rodríguez
|
||||
* Copyright (C) 2019, 2020 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -23,28 +23,17 @@
|
|||
#ifndef __INTERFACES_H__
|
||||
#define __INTERFACES_H__
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include "common.h"
|
||||
|
||||
#include "network-inador.h"
|
||||
void interfaces_init (NetworkInadorHandle *handle);
|
||||
int interface_receive_message_newlink (struct nl_msg *msg, void *arg);
|
||||
int interface_receive_message_dellink (struct nl_msg *msg, void *arg);
|
||||
|
||||
extern int global_nl_seq;
|
||||
|
||||
void interfaces_list_all (NetworkInadorHandle *handle, int sock);
|
||||
Interface * interfaces_locate_by_index (Interface *list, int index);
|
||||
void interfaces_add_or_update_rtnl_link (NetworkInadorHandle *handle, struct nlmsghdr *h, int first_time);
|
||||
void interfaces_del_rtnl_link (NetworkInadorHandle *handle, struct nlmsghdr *h);
|
||||
void interfaces_add_or_update_ipv4 (NetworkInadorHandle *handle, struct nlmsghdr *h);
|
||||
void interfaces_del_ipv4 (NetworkInadorHandle *handle, struct nlmsghdr *h);
|
||||
|
||||
IPv4 * _interfaces_serach_ipv4 (Interface *interface, struct in_addr address, uint32_t prefix);
|
||||
|
||||
void interfaces_clear_all_ipv4_address (NetworkInadorHandle *handle, Interface *interface);
|
||||
void interfaces_manual_add_ipv4 (int sock, Interface *interface, IPv4 *address);
|
||||
void interfaces_manual_del_ipv4 (int sock, Interface *interface, IPv4 *address);
|
||||
void interfaces_bring_up (int sock, Interface *interface);
|
||||
void interfaces_bring_down (int sock, Interface *interface);
|
||||
int interfaces_change_mac_address (NetworkInadorHandle *handle, int index, void *new_mac);
|
||||
int interfaces_change_mtu (NetworkInadorHandle *handle, int index, uint32_t new_mtu);
|
||||
int interfaces_change_set_up (NetworkInadorHandle *handle, int index);
|
||||
int interfaces_change_set_down (NetworkInadorHandle *handle, int index);
|
||||
int interfaces_change_name (NetworkInadorHandle *handle, int index, char * new_name);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
* network-inador.c
|
||||
* main.c
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2011 - Félix Arreola Rodríguez
|
||||
* Copyright (C) 2019, 2020 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,74 +22,34 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <asm/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/if.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "network-inador.h"
|
||||
#include <netlink/socket.h>
|
||||
#include <netlink/msg.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "interfaces.h"
|
||||
#include "netlink-events.h"
|
||||
#include "manager.h"
|
||||
#include "bridge.h"
|
||||
#include "routes.h"
|
||||
#include "wireless.h"
|
||||
#include "manager-events.h"
|
||||
#include "dhcp.h"
|
||||
|
||||
static GMainLoop *loop = NULL;
|
||||
|
||||
int create_route_netlink_socket (int groups) {
|
||||
int fd;
|
||||
struct sockaddr_nl local;
|
||||
|
||||
fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&local, 0, sizeof(local)); /* fill-in local address information */
|
||||
local.nl_family = AF_NETLINK;
|
||||
local.nl_pid = 0;
|
||||
local.nl_groups = groups;
|
||||
|
||||
if (bind (fd, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
||||
perror("cannot bind, are you root ? if yes, check netlink/rtnetlink kernel support");
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (fd, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
printf ("Primer puerto es %ld\n", local_nl.nl_pid);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Usados para salir en caso de una señal */
|
||||
static int sigterm_pipe_fds[2] = { -1, -1 };
|
||||
|
||||
static void sigterm_handler (int signum) {
|
||||
static void _init_handle (NetworkInadorHandle *handle) {
|
||||
assert (handle != NULL);
|
||||
|
||||
handle->interfaces = NULL;
|
||||
}
|
||||
|
||||
static void _sigterm_handler (int signum) {
|
||||
//fprintf (stderr, "SIGTERM SIGINT Handler\n");
|
||||
if (sigterm_pipe_fds[1] >= 0) {
|
||||
if (write (sigterm_pipe_fds[1], "", 1) == -1 ) {
|
||||
|
@ -100,11 +60,12 @@ static void sigterm_handler (int signum) {
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean quit_handler (GIOChannel *source, GIOCondition cond, gpointer data) {
|
||||
static gboolean _main_quit_handler (GIOChannel *source, GIOCondition cond, gpointer data) {
|
||||
GMainLoop *loop = (GMainLoop *) data;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void setup_signal (void) {
|
||||
static void _main_setup_signal (void *loop) {
|
||||
struct sigaction act;
|
||||
sigset_t empty_mask;
|
||||
|
||||
|
@ -118,7 +79,7 @@ static void setup_signal (void) {
|
|||
sigemptyset (&empty_mask);
|
||||
act.sa_mask = empty_mask;
|
||||
act.sa_flags = 0;
|
||||
act.sa_handler = &sigterm_handler;
|
||||
act.sa_handler = &_sigterm_handler;
|
||||
if (sigaction (SIGTERM, &act, NULL) < 0) {
|
||||
perror ("Failed to register SIGTERM handler");
|
||||
}
|
||||
|
@ -133,30 +94,30 @@ static void setup_signal (void) {
|
|||
io = g_io_channel_unix_new (sigterm_pipe_fds[0]);
|
||||
g_io_channel_set_close_on_unref (io, TRUE);
|
||||
|
||||
g_io_add_watch (io, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR, quit_handler, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void clean_process (NetworkInadorHandle *handle) {
|
||||
Interface *iface;
|
||||
|
||||
iface = handle->interfaces;
|
||||
|
||||
while (iface != NULL) {
|
||||
if (iface->dhcp_info.process_pid != 0) {
|
||||
kill (iface->dhcp_info.process_pid, SIGTERM);
|
||||
}
|
||||
g_io_add_watch (io, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR, _main_quit_handler, loop);
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
NetworkInadorHandle handle;
|
||||
int nl_sock;
|
||||
int nl_watch;
|
||||
Interface *to_up;
|
||||
GMainLoop *loop = NULL;
|
||||
struct nl_sock * sock_req;
|
||||
|
||||
//signal (SIGPIPE, SIG_IGN);
|
||||
//signal (SIGCHLD, SIG_IGN);
|
||||
_init_handle (&handle);
|
||||
|
||||
/* Crear el socket de peticiones */
|
||||
sock_req = nl_socket_alloc ();
|
||||
|
||||
if (nl_connect (sock_req, NETLINK_ROUTE) != 0) {
|
||||
perror ("Falló conectar netlink socket\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle.nl_sock_route = sock_req;
|
||||
|
||||
/* Crear el socket que escucha eventos */
|
||||
netlink_events_setup (&handle);
|
||||
|
||||
#if !defined(GLIB_VERSION_2_36)
|
||||
g_type_init ();
|
||||
|
@ -164,27 +125,9 @@ int main (int argc, char *argv[]) {
|
|||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
setup_signal ();
|
||||
_main_setup_signal (loop);
|
||||
|
||||
/* Inicializar nuestra estructura principal */
|
||||
handle.interfaces = NULL;
|
||||
handle.rtable_v4 = NULL;
|
||||
|
||||
/* Crear los sockets de petición */
|
||||
nl_sock = create_route_netlink_socket (0);
|
||||
handle.netlink_sock_request = nl_sock;
|
||||
nl_watch = create_route_netlink_socket (-1);
|
||||
|
||||
wireless_init (&handle);
|
||||
|
||||
manager_events_setup (&handle);
|
||||
manager_setup_socket (&handle);
|
||||
|
||||
interfaces_list_all (&handle, nl_sock);
|
||||
|
||||
routes_list (&handle, nl_sock);
|
||||
|
||||
netlink_events_setup_loop (&handle, nl_watch);
|
||||
interfaces_init (&handle);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
/*
|
||||
* manager-events.c
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2018 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Network-inador is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Network-inador; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_addr.h>
|
||||
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "network-inador.h"
|
||||
#include "manager-events.h"
|
||||
|
||||
#define EVENTS_SOCKET_PATH "/tmp/network-inador.events"
|
||||
#define MANAGER_EVENTS_MAX_CLIENT 50
|
||||
|
||||
static int _manager_events_clients[MANAGER_EVENTS_MAX_CLIENT];
|
||||
static int _manager_events_client_count = 0;
|
||||
|
||||
static gboolean _manager_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) {
|
||||
char buffer[128];
|
||||
|
||||
int sock;
|
||||
int ret;
|
||||
int g;
|
||||
|
||||
sock = g_io_channel_unix_get_fd (source);
|
||||
|
||||
ret = read (sock, buffer, sizeof (buffer));
|
||||
|
||||
if (ret == 0) {
|
||||
/* El socket del cliente se cerró */
|
||||
for (g = 0; g < _manager_events_client_count; g++) {
|
||||
if (_manager_events_clients[g] == sock) {
|
||||
/* Te encontré */
|
||||
if (_manager_events_client_count - 1 == g) {
|
||||
/* Es el último socket del arreglo */
|
||||
_manager_events_clients[g] = 0;
|
||||
_manager_events_client_count--;
|
||||
} else {
|
||||
/* Recorrer el último en posición de éste */
|
||||
_manager_events_clients[g] = _manager_events_clients[_manager_events_client_count - 1];
|
||||
_manager_events_clients[_manager_events_client_count - 1] = 0;
|
||||
_manager_events_client_count--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close (sock);
|
||||
} else {
|
||||
/* Procesar data o errores de lectura */
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean _manager_events_handle_new_conn (GIOChannel *source, GIOCondition condition, gpointer data) {
|
||||
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
|
||||
int sock;
|
||||
int new_c;
|
||||
GIOChannel *channel;
|
||||
|
||||
sock = g_io_channel_unix_get_fd (source);
|
||||
|
||||
new_c = accept (sock, NULL, NULL);
|
||||
if (new_c < 0) {
|
||||
printf ("Error al aceptar cliente\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (fcntl (new_c, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
printf ("Error set close-on-exec");
|
||||
}
|
||||
|
||||
if (_manager_events_client_count == MANAGER_EVENTS_MAX_CLIENT) {
|
||||
/* Rechazar el cliente por estar al máximo de capacidad */
|
||||
close (new_c);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
channel = g_io_channel_unix_new (new_c);
|
||||
|
||||
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_events_handle_read, handle);
|
||||
|
||||
/* Agregar a la lista de clientes */
|
||||
_manager_events_clients [_manager_events_client_count] = new_c;
|
||||
_manager_events_client_count++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void manager_events_notify_ipv4_address_added (Interface *iface, IPv4 *address) {
|
||||
char buffer[128];
|
||||
int size;
|
||||
int g;
|
||||
|
||||
buffer[0] = 0;
|
||||
buffer[1] = MANAGER_EVENT_IPV4_ADDED;
|
||||
|
||||
buffer[2] = iface->index;
|
||||
memcpy (&buffer[3], &address->sin_addr, sizeof (address->sin_addr));
|
||||
buffer[7] = address->prefix;
|
||||
|
||||
size = 8;
|
||||
|
||||
for (g = 0; g < _manager_events_client_count; g++) {
|
||||
write (_manager_events_clients [g], buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
void manager_events_setup (NetworkInadorHandle *handle) {
|
||||
int sock;
|
||||
struct sockaddr_un socket_name;
|
||||
GIOChannel *channel;
|
||||
|
||||
sock = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
|
||||
if (sock < 0) {
|
||||
perror ("Failed to create AF_UNIX socket");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
memset (_manager_events_clients, 0, sizeof (_manager_events_clients));
|
||||
memset (&socket_name, 0, sizeof (struct sockaddr_un));
|
||||
|
||||
socket_name.sun_family = AF_UNIX;
|
||||
strncpy (socket_name.sun_path, EVENTS_SOCKET_PATH, sizeof (socket_name.sun_path) - 1);
|
||||
|
||||
unlink (EVENTS_SOCKET_PATH);
|
||||
|
||||
if (bind (sock, (struct sockaddr *) &socket_name, sizeof (struct sockaddr_un)) < 0) {
|
||||
perror ("Bind");
|
||||
|
||||
close (sock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen (sock, 20)) {
|
||||
perror ("Listen");
|
||||
|
||||
close (sock);
|
||||
unlink (EVENTS_SOCKET_PATH);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Aplicar permisos aquí */
|
||||
chmod (EVENTS_SOCKET_PATH, 0666);
|
||||
|
||||
channel = g_io_channel_unix_new (sock);
|
||||
|
||||
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_events_handle_new_conn, handle);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
577
src/manager.c
577
src/manager.c
|
@ -1,577 +0,0 @@
|
|||
/*
|
||||
* manager.c
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2011 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Network-inador is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Network-inador; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <linux/if_addr.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "manager.h"
|
||||
#include "interfaces.h"
|
||||
#include "network-inador.h"
|
||||
#include "dhcp.h"
|
||||
|
||||
#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
|
||||
|
||||
enum {
|
||||
MANAGER_EVENT = 0,
|
||||
|
||||
MANAGER_COMMAND_REQUEST = 1,
|
||||
MANAGER_COMMAND_LIST_IFACES = 1,
|
||||
|
||||
MANAGER_COMMAND_BRING_UP_IFACE,
|
||||
MANAGER_COMMAND_BRING_DOWN_IFACE,
|
||||
|
||||
MANAGER_COMMAND_CLEAR_IPV4,
|
||||
MANAGER_COMMAND_ADD_IPV4,
|
||||
MANAGER_COMMAND_REMOVE_IPV4,
|
||||
|
||||
MANAGER_COMMAND_LIST_IPV4,
|
||||
|
||||
MANAGER_COMMAND_RUN_DHCP_CLIENT,
|
||||
MANAGER_COMMAND_STOP_DHCP_CLIENT,
|
||||
|
||||
MANAGER_COMMAND_LIST_ROUTES,
|
||||
|
||||
MANAGER_COMMAND_ADD_ROUTE_V4,
|
||||
MANAGER_COMMAND_REMOVE_ROUTE_V4,
|
||||
|
||||
MANAGER_RESPONSE = 128,
|
||||
MANAGER_RESPONSE_REQUEST_INVALID = 128,
|
||||
|
||||
MANAGER_RESPONSE_PROCESSING,
|
||||
|
||||
MANAGER_RESPONSE_LIST_IFACES,
|
||||
|
||||
MANAGER_RESPONSE_LIST_IPV4,
|
||||
|
||||
MANAGER_RESPONSE_LIST_ROUTES,
|
||||
};
|
||||
|
||||
enum {
|
||||
MANAGER_ERROR_UNKNOWN = 0,
|
||||
|
||||
MANAGER_ERROR_INCOMPLETE_REQUEST,
|
||||
|
||||
MANAGER_ERROR_UNKNOWN_COMMAND,
|
||||
|
||||
MANAGER_ERROR_PREFIX_INVALID,
|
||||
MANAGER_ERROR_IFACE_INVALID,
|
||||
MANAGER_ERROR_IPV4_INVALID,
|
||||
MANAGER_ERROR_DHCP_ALREADY_RUNNING,
|
||||
MANAGER_ERROR_DHCP_NOT_RUNNING
|
||||
};
|
||||
|
||||
#define MANAGER_IFACE_TYPE_WIRELESS 0x02
|
||||
#define MANAGER_IFACE_TYPE_BRIDGE 0x04
|
||||
#define MANAGER_IFACE_TYPE_LOOPBACK 0x8
|
||||
#define MANAGER_IFACE_TYPE_VLAN 0x10
|
||||
#define MANAGER_IFACE_TYPE_NLMON 0x20
|
||||
|
||||
#define MANAGER_IFACE_IPV4_ADDRESS_SECONDARY 0x01
|
||||
|
||||
typedef struct {
|
||||
int sock;
|
||||
struct sockaddr_un client;
|
||||
socklen_t socklen;
|
||||
|
||||
int seq;
|
||||
|
||||
int command;
|
||||
unsigned char *full_buffer;
|
||||
unsigned char *command_data;
|
||||
|
||||
int full_len;
|
||||
int command_len;
|
||||
|
||||
} ManagerCommandRequest;
|
||||
|
||||
static void _manager_send_invalid_request (ManagerCommandRequest *request, int error) {
|
||||
unsigned char buffer[128];
|
||||
|
||||
buffer[0] = MANAGER_RESPONSE_REQUEST_INVALID;
|
||||
buffer[1] = request->seq;
|
||||
|
||||
sendto (request->sock, buffer, 2, 0, (struct sockaddr *) &request->client, request->socklen);
|
||||
}
|
||||
|
||||
static void _manager_send_processing (ManagerCommandRequest *request) {
|
||||
unsigned char buffer[128];
|
||||
|
||||
buffer[0] = MANAGER_RESPONSE_PROCESSING;
|
||||
buffer[1] = request->seq;
|
||||
|
||||
sendto (request->sock, buffer, 2, 0, (struct sockaddr *) &request->client, request->socklen);
|
||||
}
|
||||
|
||||
static void _manager_send_response (ManagerCommandRequest *request, unsigned char *buffer, int len) {
|
||||
sendto (request->sock, buffer, len, 0, (struct sockaddr *) &request->client, request->socklen);
|
||||
}
|
||||
|
||||
static void _manager_send_list_interfaces (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
|
||||
unsigned char buffer[8192];
|
||||
Interface *iface_g;
|
||||
int pos;
|
||||
int flags;
|
||||
|
||||
buffer[0] = MANAGER_RESPONSE_LIST_IFACES;
|
||||
buffer[1] = request->seq;
|
||||
|
||||
iface_g = handle->interfaces;
|
||||
|
||||
pos = 2;
|
||||
while (iface_g != NULL) {
|
||||
buffer[pos] = iface_g->index;
|
||||
flags = 0;
|
||||
|
||||
if (iface_g->is_loopback) {
|
||||
flags |= MANAGER_IFACE_TYPE_LOOPBACK;
|
||||
}
|
||||
|
||||
if (iface_g->is_wireless) {
|
||||
flags |= MANAGER_IFACE_TYPE_WIRELESS;
|
||||
}
|
||||
|
||||
if (iface_g->is_bridge) {
|
||||
flags |= MANAGER_IFACE_TYPE_BRIDGE;
|
||||
}
|
||||
|
||||
if (iface_g->is_vlan) {
|
||||
flags |= MANAGER_IFACE_TYPE_VLAN;
|
||||
}
|
||||
|
||||
if (iface_g->is_nlmon) {
|
||||
flags |= MANAGER_IFACE_TYPE_NLMON;
|
||||
}
|
||||
|
||||
buffer[pos + 1] = flags;
|
||||
|
||||
/* Copiar la mac address */
|
||||
memcpy (&buffer[pos + 2], iface_g->real_hw, ETHER_ADDR_LEN);
|
||||
|
||||
/* Copiar el nombre y el terminador de cadena */
|
||||
memcpy (&buffer[pos + 2 + ETHER_ADDR_LEN], iface_g->name, strlen (iface_g->name) + 1);
|
||||
|
||||
pos += 2 + ETHER_ADDR_LEN + strlen (iface_g->name) + 1;
|
||||
iface_g = iface_g->next;
|
||||
}
|
||||
|
||||
buffer[pos] = 0;
|
||||
pos++;
|
||||
|
||||
_manager_send_response (request, buffer, pos);
|
||||
}
|
||||
|
||||
static void _manager_handle_clear_iface (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
|
||||
/* Primero, validar que haya suficientes bytes:
|
||||
* 1 byte de la interfaz
|
||||
*/
|
||||
|
||||
int index;
|
||||
Interface *iface;
|
||||
|
||||
if (request->command_len < 1) {
|
||||
/* Bytes unsuficientes */
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
index = request->command_data[0];
|
||||
|
||||
iface = interfaces_locate_by_index (handle->interfaces, index);
|
||||
|
||||
if (iface == NULL) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
interfaces_clear_all_ipv4_address (handle, iface);
|
||||
|
||||
_manager_send_processing (request);
|
||||
}
|
||||
|
||||
static void _manager_handle_bring_up_down_iface (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
|
||||
/* Primero, validar que haya suficientes bytes:
|
||||
* 1 byte de la interfaz
|
||||
*/
|
||||
|
||||
int index;
|
||||
Interface *iface;
|
||||
|
||||
if (request->command_len < 1) {
|
||||
/* Bytes unsuficientes */
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
index = request->command_data[0];
|
||||
|
||||
iface = interfaces_locate_by_index (handle->interfaces, index);
|
||||
|
||||
if (iface == NULL) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request->command == MANAGER_COMMAND_BRING_UP_IFACE) {
|
||||
interfaces_bring_up (handle->netlink_sock_request, iface);
|
||||
} else {
|
||||
interfaces_bring_down (handle->netlink_sock_request, iface);
|
||||
}
|
||||
|
||||
_manager_send_processing (request);
|
||||
}
|
||||
|
||||
static void _manager_handle_interface_add_ipv4 (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
|
||||
/* Primero, validar que haya suficientes bytes:
|
||||
* 1 byte de la interfaz
|
||||
* 4 bytes de la dirección
|
||||
* 1 byte del prefix
|
||||
*/
|
||||
uint32_t prefix;
|
||||
int index;
|
||||
Interface *iface;
|
||||
IPv4 address;
|
||||
|
||||
if (request->command_len < 6) {
|
||||
/* Bytes insuficientes */
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
prefix = request->command_data[5];
|
||||
|
||||
if (prefix < 0 || prefix > 32) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_PREFIX_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
index = request->command_data[0];
|
||||
|
||||
iface = interfaces_locate_by_index (handle->interfaces, index);
|
||||
|
||||
if (iface == NULL) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (&address.sin_addr, &request->command_data[1], sizeof (struct in_addr));
|
||||
address.prefix = prefix;
|
||||
address.next = NULL;
|
||||
|
||||
interfaces_manual_add_ipv4 (handle->netlink_sock_request, iface, &address);
|
||||
|
||||
_manager_send_processing (request);
|
||||
}
|
||||
|
||||
static void _manager_handle_interface_del_ipv4 (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
|
||||
/* Primero, validar que haya suficientes bytes:
|
||||
* 1 byte de la interfaz
|
||||
* 4 bytes de la dirección
|
||||
* 1 byte del prefix
|
||||
*/
|
||||
uint32_t prefix;
|
||||
struct in_addr sin_addr;
|
||||
int index;
|
||||
Interface *iface;
|
||||
IPv4 *to_del;
|
||||
|
||||
if (request->command_len < 6) {
|
||||
/* Bytes insuficientes */
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
prefix = request->command_data[5];
|
||||
|
||||
if (prefix < 0 || prefix > 32) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_PREFIX_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
index = request->command_data[0];
|
||||
|
||||
iface = interfaces_locate_by_index (handle->interfaces, index);
|
||||
|
||||
if (iface == NULL) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (&sin_addr, &request->command_data[1], sizeof (struct in_addr));
|
||||
|
||||
to_del = _interfaces_serach_ipv4 (iface, sin_addr, prefix);
|
||||
|
||||
if (to_del == NULL) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_IPV4_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
interfaces_manual_del_ipv4 (handle->netlink_sock_request, iface, to_del);
|
||||
|
||||
_manager_send_processing (request);
|
||||
}
|
||||
|
||||
static void _manager_send_list_ipv4 (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
|
||||
/* Primero, validar que haya suficientes bytes:
|
||||
* 1 byte de la interfaz
|
||||
*/
|
||||
|
||||
int index;
|
||||
Interface *iface;
|
||||
unsigned char buffer[8192];
|
||||
IPv4 *ip_g;
|
||||
int pos;
|
||||
int count;
|
||||
|
||||
if (request->command_len < 1) {
|
||||
/* Bytes unsuficientes */
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
index = request->command_data[0];
|
||||
|
||||
iface = interfaces_locate_by_index (handle->interfaces, index);
|
||||
|
||||
if (iface == NULL) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer[0] = MANAGER_RESPONSE_LIST_IPV4;
|
||||
buffer[1] = request->seq;
|
||||
|
||||
ip_g = iface->v4_address;
|
||||
|
||||
count = 0;
|
||||
pos = 6;
|
||||
|
||||
while (ip_g != NULL) {
|
||||
memcpy (&buffer[pos], &ip_g->sin_addr, sizeof (ip_g->sin_addr));
|
||||
pos = pos + sizeof (ip_g->sin_addr);
|
||||
|
||||
buffer[pos] = ip_g->prefix;
|
||||
|
||||
buffer[pos + 1] = 0;
|
||||
|
||||
if (ip_g->flags & IFA_F_SECONDARY) {
|
||||
buffer[pos + 1] |= MANAGER_IFACE_IPV4_ADDRESS_SECONDARY;
|
||||
}
|
||||
|
||||
pos = pos + 2;
|
||||
|
||||
ip_g = ip_g->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
memcpy (&buffer[2], &count, sizeof (int));
|
||||
|
||||
_manager_send_response (request, buffer, pos);
|
||||
}
|
||||
|
||||
static void _manager_handle_interface_set_dhcp (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
|
||||
/* Primero, validar que haya suficientes bytes:
|
||||
* 1 byte de la interfaz
|
||||
*/
|
||||
|
||||
int index;
|
||||
Interface *iface;
|
||||
unsigned char buffer[8192];
|
||||
IPv4 *ip_g;
|
||||
int pos;
|
||||
int count;
|
||||
|
||||
if (request->command_len < 1) {
|
||||
/* Bytes unsuficientes */
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
index = request->command_data[0];
|
||||
|
||||
iface = interfaces_locate_by_index (handle->interfaces, index);
|
||||
|
||||
if (iface == NULL) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request->command == MANAGER_COMMAND_RUN_DHCP_CLIENT && iface->dhcp_info.type != IFACE_NO_DHCP_RUNNING) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_DHCP_ALREADY_RUNNING);
|
||||
} else if (request->command == MANAGER_COMMAND_STOP_DHCP_CLIENT && iface->dhcp_info.type == IFACE_NO_DHCP_RUNNING) {
|
||||
_manager_send_invalid_request (request, MANAGER_ERROR_DHCP_NOT_RUNNING);
|
||||
} else if (request->command == MANAGER_COMMAND_RUN_DHCP_CLIENT) {
|
||||
dhcp_run_client (handle, iface);
|
||||
_manager_send_processing (request);
|
||||
} else if (request->command == MANAGER_COMMAND_STOP_DHCP_CLIENT) {
|
||||
dhcp_stop_client (handle, iface);
|
||||
_manager_send_processing (request);
|
||||
}
|
||||
}
|
||||
|
||||
static void _manager_send_list_routes (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
|
||||
unsigned char buffer[8192];
|
||||
Routev4 *route_g;
|
||||
int pos;
|
||||
int flags;
|
||||
unsigned int count;
|
||||
|
||||
buffer[0] = MANAGER_RESPONSE_LIST_ROUTES;
|
||||
buffer[1] = request->seq;
|
||||
|
||||
route_g = handle->rtable_v4;
|
||||
|
||||
count = 0;
|
||||
pos = 6;
|
||||
while (route_g != NULL) {
|
||||
memcpy (&buffer[pos], &route_g->dest, sizeof (route_g->dest));
|
||||
pos = pos + sizeof (route_g->dest);
|
||||
|
||||
buffer[pos] = route_g->prefix;
|
||||
buffer[pos + 1] = route_g->index;
|
||||
buffer[pos + 2] = route_g->table;
|
||||
buffer[pos + 3] = route_g->type;
|
||||
pos = pos + 4;
|
||||
|
||||
memcpy (&buffer[pos], &route_g->gateway, sizeof (route_g->gateway));
|
||||
|
||||
pos = pos + 4;
|
||||
|
||||
route_g = route_g->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
memcpy (&buffer[2], &count, sizeof (int));
|
||||
|
||||
_manager_send_response (request, buffer, pos);
|
||||
}
|
||||
|
||||
static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition, gpointer data) {
|
||||
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
|
||||
unsigned char buffer[4096];
|
||||
ManagerCommandRequest request;
|
||||
|
||||
request.full_buffer = buffer;
|
||||
|
||||
request.sock = g_io_channel_unix_get_fd (source);
|
||||
|
||||
request.socklen = sizeof (request.client);
|
||||
request.full_len = recvfrom (request.sock, buffer, sizeof (buffer), 0, (struct sockaddr *) &request.client, &request.socklen);
|
||||
|
||||
request.command_data = &buffer[2];
|
||||
request.command_len = request.full_len - 2;
|
||||
|
||||
request.seq = 0;
|
||||
|
||||
/* Procesar aquí la petición */
|
||||
if (request.full_len < 2) {
|
||||
_manager_send_invalid_request (&request, MANAGER_ERROR_INCOMPLETE_REQUEST);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
request.command = buffer[0];
|
||||
request.seq = buffer[1];
|
||||
|
||||
switch (request.command) {
|
||||
case MANAGER_COMMAND_LIST_IFACES:
|
||||
_manager_send_list_interfaces (handle, &request);
|
||||
break;
|
||||
case MANAGER_COMMAND_BRING_UP_IFACE:
|
||||
case MANAGER_COMMAND_BRING_DOWN_IFACE:
|
||||
_manager_handle_bring_up_down_iface (handle, &request);
|
||||
break;
|
||||
case MANAGER_COMMAND_CLEAR_IPV4:
|
||||
_manager_handle_clear_iface (handle, &request);
|
||||
break;
|
||||
case MANAGER_COMMAND_ADD_IPV4:
|
||||
_manager_handle_interface_add_ipv4 (handle, &request);
|
||||
break;
|
||||
case MANAGER_COMMAND_REMOVE_IPV4:
|
||||
_manager_handle_interface_del_ipv4 (handle, &request);
|
||||
break;
|
||||
case MANAGER_COMMAND_RUN_DHCP_CLIENT:
|
||||
case MANAGER_COMMAND_STOP_DHCP_CLIENT:
|
||||
_manager_handle_interface_set_dhcp (handle, &request);
|
||||
break;
|
||||
case MANAGER_COMMAND_LIST_IPV4:
|
||||
_manager_send_list_ipv4 (handle, &request);
|
||||
break;
|
||||
case MANAGER_COMMAND_LIST_ROUTES:
|
||||
_manager_send_list_routes (handle, &request);
|
||||
break;
|
||||
default:
|
||||
_manager_send_invalid_request (&request, MANAGER_ERROR_UNKNOWN_COMMAND);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int manager_setup_socket (NetworkInadorHandle *handle) {
|
||||
int sock;
|
||||
struct sockaddr_un socket_name;
|
||||
GIOChannel *channel;
|
||||
|
||||
sock = socket (AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
|
||||
if (sock < 0) {
|
||||
perror ("Failed to create AF_UNIX socket");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (&socket_name, 0, sizeof (struct sockaddr_un));
|
||||
|
||||
socket_name.sun_family = AF_UNIX;
|
||||
strncpy (socket_name.sun_path, COMMAND_SOCKET_PATH, sizeof (socket_name.sun_path) - 1);
|
||||
|
||||
unlink (COMMAND_SOCKET_PATH);
|
||||
|
||||
if (bind (sock, (struct sockaddr *) &socket_name, sizeof (struct sockaddr_un)) < 0) {
|
||||
perror ("Bind");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: Aplicar permisos aquí */
|
||||
chmod (COMMAND_SOCKET_PATH, 0666);
|
||||
|
||||
channel = g_io_channel_unix_new (sock);
|
||||
|
||||
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_client_data, handle);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
* netlink-events.c
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2018 - Félix Arreola Rodríguez
|
||||
* Copyright (C) 2019, 2020 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,107 +20,59 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_addr.h>
|
||||
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netlink/socket.h>
|
||||
#include <netlink/msg.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "netlink-events.h"
|
||||
#include "network-inador.h"
|
||||
#include "common.h"
|
||||
#include "interfaces.h"
|
||||
#include "routes.h"
|
||||
|
||||
static int _netlink_events_route_dispatcher (struct nl_msg *msg, void *arg) {
|
||||
struct nlmsghdr *reply;
|
||||
|
||||
reply = nlmsg_hdr (msg);
|
||||
|
||||
switch (reply->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
interface_receive_message_newlink (msg, arg);
|
||||
break;
|
||||
case RTM_DELLINK:
|
||||
interface_receive_message_dellink (msg, arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean _netlink_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) {
|
||||
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
|
||||
int sock;
|
||||
|
||||
sock = g_io_channel_unix_get_fd (source);
|
||||
|
||||
char reply[8192]; /* a large buffer */
|
||||
struct sockaddr_nl kernel;
|
||||
int len;
|
||||
|
||||
struct iovec io;
|
||||
/* Para la respuesta */
|
||||
struct nlmsghdr *msg_ptr; /* pointer to current part */
|
||||
struct msghdr rtnl_reply; /* generic msghdr structure */
|
||||
struct iovec io_reply;
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset(&io_reply, 0, sizeof(io_reply));
|
||||
memset(&rtnl_reply, 0, sizeof(rtnl_reply));
|
||||
|
||||
io.iov_base = reply;
|
||||
io.iov_len = sizeof (reply);
|
||||
rtnl_reply.msg_iov = &io;
|
||||
rtnl_reply.msg_iovlen = 1;
|
||||
rtnl_reply.msg_name = &kernel;
|
||||
rtnl_reply.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = recvmsg(sock, &rtnl_reply, 0);
|
||||
|
||||
if (len == 0) {
|
||||
printf ("Lectura de eventos regresó 0\n");
|
||||
return FALSE;
|
||||
} else if (len < 0) {
|
||||
perror ("Error en recvmsg\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
msg_ptr = (struct nlmsghdr *) reply;
|
||||
|
||||
for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) {
|
||||
printf ("Msg type: %i\n", msg_ptr->nlmsg_type);
|
||||
if (msg_ptr->nlmsg_type == RTM_NEWLINK) {
|
||||
printf ("Mensaje dinámico de nueva interfaz\n");
|
||||
interfaces_add_or_update_rtnl_link (handle, msg_ptr, 0);
|
||||
} else if (msg_ptr->nlmsg_type == RTM_DELLINK) {
|
||||
printf ("Mensaje dinámico de eliminar interfaz\n");
|
||||
interfaces_del_rtnl_link (handle, msg_ptr);
|
||||
} else if (msg_ptr->nlmsg_type == RTM_NEWADDR) {
|
||||
printf ("Mensaje dinámico de nueva IP\n");
|
||||
interfaces_add_or_update_ipv4 (handle, msg_ptr);
|
||||
} else if (msg_ptr->nlmsg_type == RTM_DELADDR) {
|
||||
printf ("Mensaje dinámico de eliminar IP\n");
|
||||
interfaces_del_ipv4 (handle, msg_ptr);
|
||||
} else if (msg_ptr->nlmsg_type == RTM_NEWROUTE) {
|
||||
printf ("Mensaje dinámico de nueva ruta\n");
|
||||
routes_add_or_update_rtm (handle, msg_ptr);
|
||||
} else if (msg_ptr->nlmsg_type == RTM_DELROUTE) {
|
||||
printf ("Mensaje dinámico de eliminar ruta\n");
|
||||
routes_del_rtm (handle, msg_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nl_recvmsgs_default (handle->nl_sock_route_events);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void netlink_events_setup_loop (NetworkInadorHandle *handle, int sock) {
|
||||
void netlink_events_setup (NetworkInadorHandle *handle) {
|
||||
struct nl_sock * sock_req;
|
||||
int fd;
|
||||
GIOChannel *channel;
|
||||
|
||||
channel = g_io_channel_unix_new (sock);
|
||||
sock_req = nl_socket_alloc ();
|
||||
|
||||
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _netlink_events_handle_read, handle);
|
||||
if (nl_connect (sock_req, NETLINK_ROUTE) != 0) {
|
||||
perror ("Falló conectar netlink socket para eventos\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
nl_socket_set_nonblocking (sock_req);
|
||||
nl_socket_add_memberships (sock_req, RTNLGRP_LINK, 0);
|
||||
nl_socket_disable_seq_check (sock_req);
|
||||
nl_socket_modify_cb (sock_req, NL_CB_VALID, NL_CB_CUSTOM, _netlink_events_route_dispatcher, handle);
|
||||
|
||||
fd = nl_socket_get_fd (sock_req);
|
||||
|
||||
channel = g_io_channel_unix_new (fd);
|
||||
|
||||
handle->route_events_source = g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _netlink_events_handle_read, handle);
|
||||
handle->nl_sock_route_events = sock_req;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
579
src/routes.c
579
src/routes.c
|
@ -1,579 +0,0 @@
|
|||
/*
|
||||
* routes.c
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2018 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Network-inador is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Network-inador; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "network-inador.h"
|
||||
#include "interfaces.h"
|
||||
#include "rta_aux.h"
|
||||
|
||||
static uint32_t _routes_utils_ip4_prefix_to_netmask (uint32_t prefix) {
|
||||
return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static Routev4 * _routes_append_routev4_to_struct (NetworkInadorHandle *handle, struct in_addr dest, uint32_t prefix) {
|
||||
Routev4 *new_route, *last;
|
||||
|
||||
new_route = (Routev4 *) malloc (sizeof (Routev4));
|
||||
|
||||
memset (new_route, 0, sizeof (Routev4));
|
||||
|
||||
new_route->dest = dest;
|
||||
new_route->prefix = prefix;
|
||||
|
||||
new_route->next = NULL;
|
||||
|
||||
if (handle->rtable_v4 == NULL) {
|
||||
handle->rtable_v4 = new_route;
|
||||
} else {
|
||||
last = handle->rtable_v4;
|
||||
|
||||
while (last->next != NULL) {
|
||||
last = last->next;
|
||||
}
|
||||
|
||||
last->next = new_route;
|
||||
}
|
||||
|
||||
return new_route;
|
||||
}
|
||||
|
||||
static Routev4 * _routes_search_ipv4 (NetworkInadorHandle *handle, struct in_addr dest, uint32_t prefix, unsigned int index) {
|
||||
Routev4 *list;
|
||||
|
||||
list = handle->rtable_v4;
|
||||
|
||||
while (list != NULL) {
|
||||
if (list->dest.s_addr == dest.s_addr &&
|
||||
list->prefix == prefix &&
|
||||
list->index == index) {
|
||||
return list;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _routes_delete_by_chain (NetworkInadorHandle *handle, Routev4 *route) {
|
||||
Routev4 *list, *next, *before;
|
||||
struct in_addr mask;
|
||||
struct in_addr with_mask;
|
||||
struct in_addr dest_masked;
|
||||
|
||||
/* Si esta es una ruta local sin gateway, lo más seguro es que se eliminó una IP,
|
||||
* hay que eliminar todas las rutas que contengan un gateway que haga match
|
||||
* con el destino de la ruta y la interfaz
|
||||
* Esto asegura que se eliminen rutas como 0.0.0.0/0
|
||||
*/
|
||||
|
||||
if (route->gateway.s_addr != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
list = handle->rtable_v4;
|
||||
|
||||
mask.s_addr = _routes_utils_ip4_prefix_to_netmask (route->prefix);
|
||||
dest_masked.s_addr = route->dest.s_addr & mask.s_addr;
|
||||
|
||||
while (list != NULL) {
|
||||
next = list->next;
|
||||
|
||||
if (list == route) {
|
||||
/* Solo por seguridad, la ruta ya debería estar desligada de la lista */
|
||||
list = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (list->index != route->index) {
|
||||
/* Son de diferentes interfaces, no aplica */
|
||||
list = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (list->gateway.s_addr != 0) {
|
||||
with_mask.s_addr = list->gateway.s_addr & mask.s_addr;
|
||||
|
||||
if (with_mask.s_addr == dest_masked.s_addr) {
|
||||
/* Eres una ruta que será eliminada */
|
||||
if (list == handle->rtable_v4) {
|
||||
/* Excelente, primera de la lista */
|
||||
handle->rtable_v4 = list->next;
|
||||
} else {
|
||||
before = handle->rtable_v4;
|
||||
|
||||
while (before->next != list) {
|
||||
before = before->next;
|
||||
}
|
||||
|
||||
before->next = list->next;
|
||||
}
|
||||
|
||||
printf ("Ruta eliminada en cadena\n");
|
||||
free (list);
|
||||
}
|
||||
}
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
void routes_manual_add_ipv4 (int sock, Interface *interface, IPv4 *dest, struct in_addr gateway) {
|
||||
struct msghdr rtnl_msg;
|
||||
struct iovec io;
|
||||
struct sockaddr_nl kernel;
|
||||
char buffer[8192];
|
||||
int len;
|
||||
struct nlmsghdr *nl;
|
||||
struct rtmsg *route_addr;
|
||||
struct rtattr *rta;
|
||||
|
||||
struct nlmsgerr *l_err;
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
memset (&kernel, 0, sizeof (kernel));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
|
||||
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
|
||||
kernel.nl_groups = 0;
|
||||
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
nl->nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
|
||||
nl->nlmsg_type = RTM_NEWROUTE;
|
||||
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE | NLM_F_CREATE;
|
||||
nl->nlmsg_seq = global_nl_seq++;
|
||||
nl->nlmsg_pid = local_nl.nl_pid;
|
||||
|
||||
route_addr = (struct rtmsg *) NLMSG_DATA (nl);
|
||||
|
||||
route_addr->rtm_family = AF_INET;
|
||||
route_addr->rtm_table = RT_TABLE_MAIN;
|
||||
route_addr->rtm_protocol = RTPROT_STATIC;
|
||||
route_addr->rtm_scope = RT_SCOPE_UNIVERSE;
|
||||
route_addr->rtm_type = RTN_UNICAST;
|
||||
route_addr->rtm_dst_len = dest->prefix;
|
||||
|
||||
rta = (struct rtattr *) RTM_RTA (route_addr);
|
||||
rta->rta_type = RTA_GATEWAY;
|
||||
memcpy (RTA_DATA (rta), &gateway, sizeof (gateway));
|
||||
rta->rta_len = RTA_LENGTH (sizeof (gateway));
|
||||
nl->nlmsg_len = NLMSG_ALIGN (nl->nlmsg_len) + rta->rta_len;
|
||||
|
||||
len = sizeof (buffer) - nl->nlmsg_len;
|
||||
rta = (struct rtattr*) RTA_NEXT (rta, len);
|
||||
rta->rta_type = RTA_OIF;
|
||||
rta->rta_len = RTA_LENGTH (sizeof (int));
|
||||
*((int*)RTA_DATA(rta)) = interface->index;
|
||||
nl->nlmsg_len += rta->rta_len;
|
||||
|
||||
if (dest->prefix != 0) {
|
||||
/* Agregar el atributo destino */
|
||||
len = sizeof (buffer) - nl->nlmsg_len;
|
||||
rta = (struct rtattr*) RTA_NEXT (rta, len);
|
||||
rta->rta_type = RTA_DST;
|
||||
rta->rta_len = RTA_LENGTH (sizeof (struct in_addr));
|
||||
memcpy (RTA_DATA(rta), &dest->sin_addr, sizeof (struct in_addr));
|
||||
nl->nlmsg_len += rta->rta_len;
|
||||
}
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = nl->nlmsg_len;
|
||||
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = sizeof (buffer);
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = recvmsg(sock, &rtnl_msg, 0);
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
|
||||
if (nl->nlmsg_type == NLMSG_DONE) {
|
||||
printf ("Route ADD Msg type: DONE!\n");
|
||||
break;
|
||||
}
|
||||
if (nl->nlmsg_type == NLMSG_ERROR) {
|
||||
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
|
||||
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
|
||||
printf ("Route ADD Error tamaño truncado\n");
|
||||
} else if (l_err->error != 0) {
|
||||
// Error:
|
||||
printf ("Route ADD Error: %i\n", l_err->error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void routes_manual_del_v4 (int sock, Routev4 *route) {
|
||||
struct msghdr rtnl_msg;
|
||||
struct iovec io;
|
||||
struct sockaddr_nl kernel;
|
||||
char buffer[8192];
|
||||
int len;
|
||||
struct nlmsghdr *nl;
|
||||
struct rtmsg *route_addr;
|
||||
struct rtattr *rta;
|
||||
struct nlmsgerr *l_err;
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
memset (&kernel, 0, sizeof (kernel));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (&io, 0, sizeof (io));
|
||||
|
||||
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
|
||||
kernel.nl_groups = 0;
|
||||
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
nl->nlmsg_type = RTM_DELROUTE;
|
||||
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
nl->nlmsg_seq = global_nl_seq++;
|
||||
nl->nlmsg_pid = local_nl.nl_pid;
|
||||
|
||||
route_addr = (struct rtmsg *) NLMSG_DATA (nl);
|
||||
|
||||
route_addr->rtm_family = AF_INET;
|
||||
route_addr->rtm_scope = RT_SCOPE_NOWHERE;
|
||||
route_addr->rtm_type = route->type;
|
||||
route_addr->rtm_table = route->table;
|
||||
route_addr->rtm_dst_len = route->prefix;
|
||||
route_addr->rtm_protocol = 0;
|
||||
|
||||
if (route->prefix != 0) {
|
||||
rta = (struct rtattr *) RTM_RTA (route_addr);
|
||||
rta->rta_type = RTA_DST;
|
||||
rta->rta_len = RTA_LENGTH (sizeof (struct in_addr));
|
||||
memcpy (RTA_DATA(rta), &route->dest, sizeof (struct in_addr));
|
||||
nl->nlmsg_len += rta->rta_len;
|
||||
}
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = nl->nlmsg_len;
|
||||
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = sizeof (buffer);
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = recvmsg(sock, &rtnl_msg, 0);
|
||||
nl = (struct nlmsghdr *) buffer;
|
||||
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
|
||||
if (nl->nlmsg_type == NLMSG_DONE) {
|
||||
printf ("Route DEL Msg type: DONE!\n");
|
||||
break;
|
||||
}
|
||||
if (nl->nlmsg_type == NLMSG_ERROR) {
|
||||
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
|
||||
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
|
||||
printf ("Route DEL Error tamaño truncado\n");
|
||||
} else if (l_err->error != 0) {
|
||||
// Error:
|
||||
printf ("Route DEL Error: %i\n", l_err->error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void routes_add_or_update_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h) {
|
||||
struct rtmsg *route_addr;
|
||||
struct rtattr *attribute;
|
||||
size_t len;
|
||||
char ip_as_string[1024];
|
||||
Routev4 *new;
|
||||
struct in_addr dest;
|
||||
int prefix;
|
||||
struct in_addr gateway;
|
||||
unsigned index = 0;
|
||||
|
||||
memset (&dest, 0, sizeof (dest));
|
||||
memset (&gateway, 0, sizeof (gateway));
|
||||
|
||||
route_addr = NLMSG_DATA(h);
|
||||
|
||||
if (route_addr->rtm_type == RTN_BROADCAST || route_addr->rtm_type == RTN_LOCAL) {
|
||||
printf ("Omitiendo ruta local o broadcast\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (route_addr->rtm_family != AF_INET) {
|
||||
/* Por el momento, las direcciones IPv6 no son procesadas */
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("--------\n");
|
||||
printf ("Route list, family: %d\n", route_addr->rtm_family);
|
||||
printf ("Route Dest len: %d\n", route_addr->rtm_dst_len);
|
||||
printf ("Route Table id: %d\n", route_addr->rtm_table);
|
||||
printf ("Route type: %d\n", route_addr->rtm_type);
|
||||
printf ("Route flags: %d\n", route_addr->rtm_flags);
|
||||
printf ("Route protocol: %d\n", route_addr->rtm_protocol);
|
||||
|
||||
prefix = route_addr->rtm_dst_len;
|
||||
|
||||
len = RTM_PAYLOAD (h);
|
||||
//len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
|
||||
|
||||
for_each_rattr (attribute, RTM_RTA (route_addr), len) {
|
||||
//printf ("Attribute (addr): %d\n", attribute->rta_type);
|
||||
|
||||
if (attribute->rta_type == RTA_GATEWAY) {
|
||||
memcpy (&gateway, RTA_DATA (attribute), sizeof (struct in_addr));
|
||||
|
||||
inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string));
|
||||
printf ("Gw Address: %s\n", ip_as_string);
|
||||
} else if (attribute->rta_type == RTA_DST) {
|
||||
memcpy (&dest, RTA_DATA (attribute), sizeof (struct in_addr));
|
||||
|
||||
inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string));
|
||||
printf ("Destination Address: %s/%d\n", ip_as_string, route_addr->rtm_dst_len);
|
||||
} else if (attribute->rta_type == RTA_OIF) {
|
||||
index = *((int *) RTA_DATA (attribute));
|
||||
printf ("!!!!!!!!! Output interface: %i\n", index);
|
||||
} else if (attribute->rta_type == RTA_PREFSRC) {
|
||||
//printf (
|
||||
} else if (attribute->rta_type == RTA_TABLE) {
|
||||
|
||||
} else {
|
||||
printf ("ROUTE Attribute: %d\n", attribute->rta_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (route_addr->rtm_type == RTN_BROADCAST || route_addr->rtm_type == RTN_LOCAL) {
|
||||
printf ("Omitiendo ruta local o broadcast\n");
|
||||
return;
|
||||
}
|
||||
|
||||
new = _routes_search_ipv4 (handle, dest, prefix, index);
|
||||
|
||||
if (new == NULL) {
|
||||
printf ("Agregando Ruta a la lista de rutas\n");
|
||||
new = _routes_append_routev4_to_struct (handle, dest, prefix);
|
||||
}
|
||||
|
||||
/* Actualizar la gateway si hubo gateway en el mensaje */
|
||||
memcpy (&new->gateway, &gateway, sizeof (new->gateway));
|
||||
new->index = index;
|
||||
new->table = route_addr->rtm_table;
|
||||
new->type = route_addr->rtm_type;
|
||||
}
|
||||
|
||||
void routes_del_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h) {
|
||||
struct rtmsg *route_addr;
|
||||
Routev4 *route, *before;
|
||||
struct rtattr *attribute;
|
||||
size_t len;
|
||||
char ip_as_string[1024];
|
||||
struct in_addr dest;
|
||||
int prefix;
|
||||
int index;
|
||||
|
||||
memset (&dest, 0, sizeof (dest));
|
||||
|
||||
route_addr = NLMSG_DATA(h);
|
||||
|
||||
if (route_addr->rtm_type == RTN_BROADCAST || route_addr->rtm_type == RTN_LOCAL) {
|
||||
//printf ("Omitiendo ruta local o broadcast\n");
|
||||
//return;
|
||||
}
|
||||
|
||||
if (route_addr->rtm_family != AF_INET) {
|
||||
/* Por el momento, las direcciones IPv6 no son procesadas */
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("--------> ROUTE DEL <--------\n");
|
||||
printf ("Route list, family: %d\n", route_addr->rtm_family);
|
||||
printf ("Route Dest len: %d\n", route_addr->rtm_dst_len);
|
||||
printf ("Route Table id: %d\n", route_addr->rtm_table);
|
||||
printf ("Route type: %d\n", route_addr->rtm_type);
|
||||
printf ("Route flags: %d\n", route_addr->rtm_flags);
|
||||
printf ("Route protocol: %d\n", route_addr->rtm_protocol);
|
||||
|
||||
prefix = route_addr->rtm_dst_len;
|
||||
|
||||
//len = RTM_PAYLOAD (h);
|
||||
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
|
||||
|
||||
for (attribute = RTM_RTA (route_addr); RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
|
||||
//printf ("Attribute (addr): %d\n", attribute->rta_type);
|
||||
|
||||
if (attribute->rta_type == RTA_GATEWAY) {
|
||||
//memcpy (&gateway, RTA_DATA (attribute), sizeof (struct in_addr));
|
||||
|
||||
inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string));
|
||||
printf ("Gw Address: %s\n", ip_as_string);
|
||||
} else if (attribute->rta_type == RTA_DST) {
|
||||
memcpy (&dest, RTA_DATA (attribute), sizeof (struct in_addr));
|
||||
|
||||
inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string));
|
||||
printf ("Address: %s/%d\n", ip_as_string, route_addr->rtm_dst_len);
|
||||
} else if (attribute->rta_type == RTA_OIF) {
|
||||
index = *((int *) RTA_DATA (attribute));
|
||||
printf ("Output interface: %i\n", index);
|
||||
} else {
|
||||
printf ("ROUTE Attribute: %d\n", attribute->rta_type);
|
||||
}
|
||||
}
|
||||
|
||||
route = _routes_search_ipv4 (handle, dest, prefix, index);
|
||||
|
||||
if (route == NULL) {
|
||||
printf ("Me solicitaron eliminar una ruta y no existe\n");
|
||||
} else {
|
||||
if (route == handle->rtable_v4) {
|
||||
handle->rtable_v4 = route->next;
|
||||
} else {
|
||||
before = handle->rtable_v4;
|
||||
|
||||
while (before->next != route) {
|
||||
before = before->next;
|
||||
}
|
||||
|
||||
before->next = route->next;
|
||||
}
|
||||
|
||||
_routes_delete_by_chain (handle, route);
|
||||
|
||||
free (route);
|
||||
}
|
||||
}
|
||||
|
||||
void routes_list (NetworkInadorHandle *handle, int sock) {
|
||||
struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */
|
||||
struct iovec io;
|
||||
struct rtmsg *rt;
|
||||
struct sockaddr_nl kernel;
|
||||
char buffer[8192]; /* a large buffer */
|
||||
int len;
|
||||
|
||||
/* Para la respuesta */
|
||||
struct nlmsghdr *msg_ptr; /* pointer to current part */
|
||||
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (&kernel, 0, sizeof (kernel));
|
||||
memset (&buffer, 0, sizeof (buffer));
|
||||
|
||||
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
|
||||
kernel.nl_groups = 0;
|
||||
|
||||
msg_ptr = (struct nlmsghdr *) buffer;
|
||||
msg_ptr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
msg_ptr->nlmsg_type = RTM_GETROUTE;
|
||||
msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||
msg_ptr->nlmsg_seq = global_nl_seq++;
|
||||
msg_ptr->nlmsg_pid = local_nl.nl_pid;
|
||||
|
||||
rt = (struct rtmsg*) NLMSG_DATA (msg_ptr);
|
||||
rt->rtm_family = AF_INET; /* Limitar la primer consulta a solo IPv4, por el momento */
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = msg_ptr->nlmsg_len;
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = sizeof (buffer);
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof (kernel);
|
||||
|
||||
while ((len = recvmsg(sock, &rtnl_msg, 0)) > 0) { /* read lots of data */
|
||||
msg_ptr = (struct nlmsghdr *) buffer;
|
||||
if (msg_ptr->nlmsg_type == NLMSG_DONE) break;
|
||||
|
||||
for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) {
|
||||
/* Procesar solo los mensajes de nueva interfaz */
|
||||
printf ("ROUTE Msg type: %i\n", msg_ptr->nlmsg_type);
|
||||
if (msg_ptr->nlmsg_type == RTM_NEWROUTE) {
|
||||
routes_add_or_update_rtm (handle, msg_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
src/routes.h
35
src/routes.h
|
@ -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
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* rta_aux.c
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2011 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Network-inador is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Network-inador; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_addr.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define NLMSG_TAIL(nmsg) \
|
||||
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
|
||||
int rta_addattr_l (struct nlmsghdr *n, int maxlen, int type, const void *data, int alen) {
|
||||
int len = RTA_LENGTH (alen);
|
||||
struct rtattr *rta;
|
||||
|
||||
if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rta = NLMSG_TAIL (n);
|
||||
rta->rta_type = type;
|
||||
rta->rta_len = len;
|
||||
memcpy (RTA_DATA (rta), data, alen);
|
||||
n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rtattr * rta_addattr_nest (struct nlmsghdr *n, int maxlen, int type) {
|
||||
struct rtattr *nest = NLMSG_TAIL (n);
|
||||
|
||||
rta_addattr_l (n, maxlen, type, NULL, 0);
|
||||
|
||||
return nest;
|
||||
}
|
||||
|
||||
int rta_addattr_nest_end (struct nlmsghdr *n, struct rtattr *nest) {
|
||||
nest->rta_len = (void *) NLMSG_TAIL (n) - (void *) nest;
|
||||
return n->nlmsg_len;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
39
src/utils.c
39
src/utils.c
|
@ -1,39 +0,0 @@
|
|||
#include <stdint.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
uint32_t utils_ip4_netmask_to_prefix (uint32_t netmask) {
|
||||
uint32_t prefix;
|
||||
uint8_t v;
|
||||
const uint8_t *p = (uint8_t *) &netmask;
|
||||
|
||||
if (p[3]) {
|
||||
prefix = 24;
|
||||
v = p[3];
|
||||
} else if (p[2]) {
|
||||
prefix = 16;
|
||||
v = p[2];
|
||||
} else if (p[1]) {
|
||||
prefix = 8;
|
||||
v = p[1];
|
||||
} else {
|
||||
prefix = 0;
|
||||
v = p[0];
|
||||
}
|
||||
|
||||
while (v) {
|
||||
prefix++;
|
||||
v <<= 1;
|
||||
}
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_ip4_prefix_to_netmask:
|
||||
* @prefix: a CIDR prefix
|
||||
*
|
||||
* Returns: the netmask represented by the prefix, in network byte order
|
||||
**/
|
||||
uint32_t utils_ip4_prefix_to_netmask (uint32_t prefix) {
|
||||
return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
|
||||
}
|
10
src/utils.h
10
src/utils.h
|
@ -1,10 +0,0 @@
|
|||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t utils_ip4_netmask_to_prefix (uint32_t netmask);
|
||||
uint32_t utils_ip4_prefix_to_netmask (uint32_t prefix);
|
||||
|
||||
#endif
|
||||
|
611
src/wireless.c
611
src/wireless.c
|
@ -1,611 +0,0 @@
|
|||
/*
|
||||
* wireless.c
|
||||
* This file is part of Network-inador
|
||||
*
|
||||
* Copyright (C) 2018 - Félix Arreola Rodríguez
|
||||
*
|
||||
* Network-inador is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Network-inador is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Network-inador; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_addr.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <linux/genetlink.h>
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include "wireless.h"
|
||||
#include "network-inador.h"
|
||||
#include "interfaces.h"
|
||||
#include "rta_aux.h"
|
||||
|
||||
static uint16_t nl80211_id = 0;
|
||||
static uint16_t scan_multicast_group_id = 0;
|
||||
|
||||
static void _wireless_find_ssid (uint8_t *ies, uint32_t ies_len, unsigned char *ssid, uint32_t *ssid_len) {
|
||||
#define WLAN_EID_SSID 0
|
||||
ssid[0] = 0;
|
||||
*ssid_len = 0;
|
||||
|
||||
while (ies_len > 2 && ies[0] != WLAN_EID_SSID) {
|
||||
ies_len -= ies[1] + 2;
|
||||
ies += ies[1] + 2;
|
||||
}
|
||||
if (ies_len < 2)
|
||||
return;
|
||||
if (ies_len < (uint32_t)(2 + ies[1]))
|
||||
return;
|
||||
|
||||
*ssid_len = ies[1];
|
||||
memcpy (ssid, ies + 2, ies[1]);
|
||||
}
|
||||
|
||||
static int _wireless_create_generic_netlink_socket (void) {
|
||||
int fd;
|
||||
struct sockaddr_nl local;
|
||||
|
||||
fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
|
||||
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&local, 0, sizeof(local)); /* fill-in local address information */
|
||||
local.nl_family = AF_NETLINK;
|
||||
local.nl_pid = 0;
|
||||
local.nl_groups = 0;
|
||||
|
||||
if (bind (fd, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
||||
perror("cannot bind, are you root ? if yes, check netlink/rtnetlink kernel support");
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static uint16_t _wireless_parse_family_id (struct nlmsghdr *msg_ptr) {
|
||||
struct genlmsghdr *ghdr;
|
||||
struct rtattr *attribute;
|
||||
int len;
|
||||
|
||||
uint16_t n80211_family;
|
||||
|
||||
struct rtattr *nest2_attr, *nest3_attr;
|
||||
int nest2_size, nest3_size;
|
||||
int sub2_len, sub3_len;
|
||||
|
||||
ghdr = NLMSG_DATA (msg_ptr);
|
||||
len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr));
|
||||
|
||||
attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN);
|
||||
|
||||
for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
|
||||
//printf ("Attribute: %d\n", attribute->rta_type);
|
||||
if (attribute->rta_type == CTRL_ATTR_FAMILY_ID) {
|
||||
memcpy (&n80211_family, RTA_DATA (attribute), 2);
|
||||
//printf ("El id del nl80211 es: %hu\n", n80211_family);
|
||||
} else if (attribute->rta_type == CTRL_ATTR_MCAST_GROUPS) {
|
||||
//printf ("_____________ Descubriendo la familia nl80211. Multicast groups: \n");
|
||||
int id_multicast_group;
|
||||
char multicast_group_name[512];
|
||||
|
||||
nest2_size = attribute->rta_len;
|
||||
nest2_attr = RTA_DATA (attribute);
|
||||
|
||||
while (nest2_size > sizeof (nest2_attr)) {
|
||||
sub2_len = nest2_attr->rta_len;
|
||||
if (sub2_len > nest2_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
nest3_size = nest2_attr->rta_len;
|
||||
nest3_attr = RTA_DATA (nest2_attr);
|
||||
|
||||
id_multicast_group = 0;
|
||||
multicast_group_name[0] = 0;
|
||||
|
||||
while (nest3_size > sizeof (nest3_attr)) {
|
||||
sub3_len = nest3_attr->rta_len;
|
||||
if (sub3_len > nest3_size) {
|
||||
//printf ("Los sub atributos se acabaron prematuramente\n");
|
||||
break;
|
||||
}
|
||||
//printf ("sub attributo type: %i, size: %d\n", nest3_attr->rta_type, nest3_attr->rta_len);
|
||||
if (nest3_attr->rta_type == CTRL_ATTR_MCAST_GRP_ID) {
|
||||
memcpy (&id_multicast_group, RTA_DATA (nest3_attr), sizeof (id_multicast_group));
|
||||
} else if (nest3_attr->rta_type == CTRL_ATTR_MCAST_GRP_NAME) {
|
||||
strncpy (multicast_group_name, RTA_DATA (nest3_attr), sizeof (multicast_group_name));
|
||||
}
|
||||
|
||||
nest3_size -= RTA_ALIGN (sub3_len);
|
||||
nest3_attr = (struct rtattr *) (((char *) nest3_attr) + RTA_ALIGN (sub3_len));
|
||||
}
|
||||
|
||||
if (strcmp (multicast_group_name, "scan") == 0) {
|
||||
scan_multicast_group_id = id_multicast_group;
|
||||
//printf ("ID del grupo multicast SCAN: %i\n", id_multicast_group);
|
||||
}
|
||||
|
||||
nest2_size -= RTA_ALIGN (sub2_len);
|
||||
nest2_attr = (struct rtattr *) (((char *) nest2_attr) + RTA_ALIGN (sub2_len));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n80211_family;
|
||||
}
|
||||
|
||||
static void _wireless_parse_message_get_iface (struct nlmsghdr *msg_ptr, Interface *iface) {
|
||||
struct genlmsghdr *ghdr;
|
||||
struct rtattr *attribute;
|
||||
int len;
|
||||
int wiphy;
|
||||
|
||||
/* Anexar la estructura wireless al objeto interfaz */
|
||||
WirelessInfo *winfo;
|
||||
|
||||
winfo = (WirelessInfo *) malloc (sizeof (WirelessInfo));
|
||||
|
||||
if (winfo == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset (winfo, 0, sizeof (winfo));
|
||||
|
||||
iface->wireless = winfo;
|
||||
|
||||
ghdr = NLMSG_DATA (msg_ptr);
|
||||
len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr));
|
||||
|
||||
attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN);
|
||||
|
||||
for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
|
||||
printf ("Wireless Attribute: %d\n", attribute->rta_type);
|
||||
if (attribute->rta_type == NL80211_ATTR_WIPHY) {
|
||||
memcpy (&wiphy, RTA_DATA (attribute), 4);
|
||||
iface->wireless->wiphy = wiphy;
|
||||
}
|
||||
/*switch(attribute->rta_type) {
|
||||
default:
|
||||
printf ("Del interface RTA Attribute \"%hu\" no procesado\n", attribute->rta_type);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
static void _wireless_parse_scan (NetworkInadorHandle *handle, struct nlmsghdr *msg_ptr) {
|
||||
struct genlmsghdr *ghdr;
|
||||
struct rtattr *attribute;
|
||||
int len;
|
||||
int iface = -1;
|
||||
|
||||
ghdr = NLMSG_DATA (msg_ptr);
|
||||
len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr));
|
||||
|
||||
|
||||
attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN);
|
||||
|
||||
for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
|
||||
//printf ("Wireless scan Attribute: %d\n", attribute->rta_type);
|
||||
if (attribute->rta_type == NL80211_ATTR_IFINDEX) {
|
||||
memcpy (&iface, RTA_DATA (attribute), 4);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ejecutar el GET Scan */
|
||||
if (iface != -1) {
|
||||
wireless_do_get_scan (handle, iface);
|
||||
}
|
||||
}
|
||||
|
||||
static void _wireless_parse_station (struct nlmsghdr *msg_ptr, Interface *iface) {
|
||||
struct genlmsghdr *ghdr;
|
||||
struct rtattr *attribute;
|
||||
int len;
|
||||
char bss_info[1024];
|
||||
int has_bss = 0;
|
||||
int bss_len;
|
||||
|
||||
ghdr = NLMSG_DATA (msg_ptr);
|
||||
len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr));
|
||||
|
||||
attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN);
|
||||
|
||||
for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
|
||||
//printf ("Wireless scan Attribute: %d\n", attribute->rta_type);
|
||||
if (attribute->rta_type == NL80211_ATTR_BSS) {
|
||||
has_bss = 1;
|
||||
bss_len = attribute->rta_len;
|
||||
|
||||
memcpy (bss_info, RTA_DATA (attribute), bss_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_bss == 0) {
|
||||
/* No hay BSS info */
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("Imprimiendo BSS Attrs:\n");
|
||||
attribute = (struct rtattr *) bss_info;
|
||||
for (; RTA_OK (attribute, bss_len); attribute = RTA_NEXT (attribute, len)) {
|
||||
|
||||
if (attribute->rta_type == NL80211_BSS_BSSID) {
|
||||
char *mac = RTA_DATA (attribute);
|
||||
//printf ("MAC access point: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
} else if (attribute->rta_type == NL80211_BSS_INFORMATION_ELEMENTS) {
|
||||
char essid[64];
|
||||
essid[0] = 0;
|
||||
int essid_len = 0;
|
||||
_wireless_find_ssid (RTA_DATA (attribute), attribute->rta_len, essid, &essid_len);
|
||||
essid[essid_len] = 0;
|
||||
printf ("Essid: %s\n", essid);
|
||||
} else if (attribute->rta_type == NL80211_BSS_STATUS) {
|
||||
int status;
|
||||
memcpy (&status, RTA_DATA (attribute), 4);
|
||||
printf ("-> Bss estatus: %i\n", status);
|
||||
} else {
|
||||
printf ("BSS Scan Attribute: %d\n", attribute->rta_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wireless_do_get_scan (NetworkInadorHandle *handle, int ifindex) {
|
||||
printf ("DO Scan for iface: %i\n", ifindex);
|
||||
struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */
|
||||
struct iovec io;
|
||||
struct genlmsghdr *ghdr;
|
||||
struct rtattr *rta;
|
||||
struct sockaddr_nl kernel;
|
||||
char buffer[8192]; /* a large buffer */
|
||||
int len;
|
||||
Interface *iface;
|
||||
|
||||
/* Localizar el iface por el índice */
|
||||
iface = interfaces_locate_by_index (handle->interfaces, ifindex);
|
||||
|
||||
if (iface == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Para la respuesta */
|
||||
struct nlmsgerr *l_err;
|
||||
struct nlmsghdr *msg_ptr; /* pointer to current part */
|
||||
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (handle->netlink_sock_request_generic, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (&kernel, 0, sizeof (kernel));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
|
||||
kernel.nl_groups = 0;
|
||||
|
||||
msg_ptr = (struct nlmsghdr *) buffer;
|
||||
msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct genlmsghdr));
|
||||
msg_ptr->nlmsg_type = nl80211_id;
|
||||
msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
|
||||
msg_ptr->nlmsg_seq = global_nl_seq++;
|
||||
msg_ptr->nlmsg_pid = local_nl.nl_pid;
|
||||
|
||||
ghdr = (struct genlmsghdr *) NLMSG_DATA (msg_ptr);
|
||||
ghdr->cmd = NL80211_CMD_GET_SCAN;
|
||||
ghdr->version = 0;
|
||||
|
||||
rta_addattr_l (msg_ptr, sizeof (buffer), NL80211_ATTR_IFINDEX, &ifindex, 4);
|
||||
//rta_addattr_l (msg_ptr, sizeof (buffer), NL80211_ATTR_IFINDEX, &iface->wiphy, 4);
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = msg_ptr->nlmsg_len;
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = sendmsg (handle->netlink_sock_request_generic, (struct msghdr *) &rtnl_msg, 0);
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = sizeof (buffer);
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof (kernel);
|
||||
|
||||
len = recvmsg (handle->netlink_sock_request_generic, &rtnl_msg, 0);
|
||||
|
||||
if (len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg_ptr = (struct nlmsghdr *) buffer;
|
||||
printf ("Procesando mensajes de solicitud de escaneo\n");
|
||||
for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) {
|
||||
if (msg_ptr->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *l_err;
|
||||
l_err = (struct nlmsgerr*) NLMSG_DATA (msg_ptr);
|
||||
printf ("DO Scan message error, num: %i\n", l_err->error);
|
||||
break;
|
||||
} else if (msg_ptr->nlmsg_type == NLMSG_DONE) {
|
||||
printf ("DO Scan, end of DUMP\n");
|
||||
break;
|
||||
} else if (msg_ptr->nlmsg_type == nl80211_id) {
|
||||
ghdr = NLMSG_DATA (msg_ptr);
|
||||
|
||||
//printf ("DO SCAN! Generic command: %i\n", ghdr->cmd);
|
||||
if (ghdr->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
|
||||
_wireless_parse_station (msg_ptr, iface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean _wireless_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) {
|
||||
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
|
||||
int sock;
|
||||
|
||||
sock = g_io_channel_unix_get_fd (source);
|
||||
|
||||
char reply[8192]; /* a large buffer */
|
||||
struct sockaddr_nl kernel;
|
||||
int len;
|
||||
|
||||
struct iovec io;
|
||||
/* Para la respuesta */
|
||||
struct nlmsghdr *msg_ptr; /* pointer to current part */
|
||||
struct msghdr rtnl_reply; /* generic msghdr structure */
|
||||
struct iovec io_reply;
|
||||
struct genlmsghdr *ghdr;
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset(&io_reply, 0, sizeof(io_reply));
|
||||
memset(&rtnl_reply, 0, sizeof(rtnl_reply));
|
||||
|
||||
io.iov_base = reply;
|
||||
io.iov_len = sizeof (reply);
|
||||
rtnl_reply.msg_iov = &io;
|
||||
rtnl_reply.msg_iovlen = 1;
|
||||
rtnl_reply.msg_name = &kernel;
|
||||
rtnl_reply.msg_namelen = sizeof(kernel);
|
||||
|
||||
len = recvmsg(sock, &rtnl_reply, 0);
|
||||
|
||||
if (len == 0) {
|
||||
printf ("Lectura de eventos regresó 0\n");
|
||||
return FALSE;
|
||||
} else if (len < 0) {
|
||||
perror ("Error en recvmsg\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
msg_ptr = (struct nlmsghdr *) reply;
|
||||
|
||||
for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) {
|
||||
printf ("Msg type: %i\n", msg_ptr->nlmsg_type);
|
||||
if (msg_ptr->nlmsg_type == nl80211_id) {
|
||||
ghdr = NLMSG_DATA (msg_ptr);
|
||||
|
||||
printf ("Generic command: %i\n", ghdr->cmd);
|
||||
if (ghdr->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
|
||||
_wireless_parse_scan (handle, msg_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void wireless_init (NetworkInadorHandle *handle) {
|
||||
struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */
|
||||
struct iovec io;
|
||||
struct genlmsghdr *ghdr;
|
||||
struct rtattr *rta;
|
||||
struct sockaddr_nl kernel;
|
||||
char buffer[8192]; /* a large buffer */
|
||||
int len;
|
||||
GIOChannel *channel;
|
||||
|
||||
/* Para la respuesta */
|
||||
struct nlmsgerr *l_err;
|
||||
struct nlmsghdr *msg_ptr; /* pointer to current part */
|
||||
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
/* Crear un netlink de la familia generica para nuestras peticiones */
|
||||
handle->netlink_sock_request_generic = _wireless_create_generic_netlink_socket ();
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (handle->netlink_sock_request_generic, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (&kernel, 0, sizeof (kernel));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
|
||||
kernel.nl_groups = 0;
|
||||
|
||||
msg_ptr = (struct nlmsghdr *) buffer;
|
||||
msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct genlmsghdr));
|
||||
msg_ptr->nlmsg_type = GENL_ID_CTRL;
|
||||
msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
msg_ptr->nlmsg_seq = global_nl_seq++;
|
||||
msg_ptr->nlmsg_pid = local_nl.nl_pid;
|
||||
|
||||
ghdr = (struct genlmsghdr *) NLMSG_DATA (msg_ptr);
|
||||
ghdr->cmd = CTRL_CMD_GETFAMILY;
|
||||
ghdr->version = 1;
|
||||
|
||||
len = strlen (NL80211_GENL_NAME) + 1;
|
||||
rta_addattr_l (msg_ptr, sizeof (buffer), CTRL_ATTR_FAMILY_NAME, NL80211_GENL_NAME, len);
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = msg_ptr->nlmsg_len;
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
sendmsg (handle->netlink_sock_request_generic, (struct msghdr *) &rtnl_msg, 0);
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = sizeof (buffer);
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof (kernel);
|
||||
|
||||
/*len = recvmsg (handle->netlink_sock_request_generic, &rtnl_msg, 0);
|
||||
msg_ptr = (struct nlmsghdr *) buffer;
|
||||
_wireless_parse_family_id (msg_ptr);
|
||||
|
||||
len = recvmsg (handle->netlink_sock_request_generic, &rtnl_msg, 0);
|
||||
msg_ptr = (struct nlmsghdr *) buffer;*/
|
||||
while ((len = recvmsg(handle->netlink_sock_request_generic, &rtnl_msg, 0)) > 0) { /* read lots of data */
|
||||
msg_ptr = (struct nlmsghdr *) buffer;
|
||||
if (msg_ptr->nlmsg_type == NLMSG_DONE) break;
|
||||
if (msg_ptr->nlmsg_type == NLMSG_ERROR) break;
|
||||
|
||||
if (msg_ptr->nlmsg_type == GENL_ID_CTRL) {
|
||||
nl80211_id = _wireless_parse_family_id (msg_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generar otro socket netlink generic para eventos */
|
||||
int sock_for_wireless_events;
|
||||
int group;
|
||||
|
||||
sock_for_wireless_events = _wireless_create_generic_netlink_socket ();
|
||||
|
||||
group = scan_multicast_group_id;
|
||||
setsockopt (sock_for_wireless_events, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof (group));
|
||||
|
||||
/* Instalar un GIOChannel */
|
||||
channel = g_io_channel_unix_new (sock_for_wireless_events);
|
||||
|
||||
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _wireless_events_handle_read, handle);
|
||||
}
|
||||
|
||||
//void test_wireless
|
||||
void wireless_check_is_wireless_interface (NetworkInadorHandle *handle, Interface *iface) {
|
||||
struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */
|
||||
struct iovec io;
|
||||
struct genlmsghdr *ghdr;
|
||||
struct rtattr *rta;
|
||||
struct sockaddr_nl kernel;
|
||||
char buffer[8192]; /* a large buffer */
|
||||
int len;
|
||||
|
||||
/* Para la respuesta */
|
||||
struct nlmsgerr *l_err;
|
||||
struct nlmsghdr *msg_ptr; /* pointer to current part */
|
||||
|
||||
struct sockaddr_nl local_nl;
|
||||
socklen_t local_size;
|
||||
|
||||
/* Recuperar el puerto local del netlink */
|
||||
local_size = sizeof (local_nl);
|
||||
getsockname (handle->netlink_sock_request_generic, (struct sockaddr *) &local_nl, &local_size);
|
||||
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (&kernel, 0, sizeof (kernel));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
|
||||
kernel.nl_groups = 0;
|
||||
|
||||
msg_ptr = (struct nlmsghdr *) buffer;
|
||||
msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct genlmsghdr));
|
||||
msg_ptr->nlmsg_type = nl80211_id;
|
||||
msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
msg_ptr->nlmsg_seq = global_nl_seq++;
|
||||
msg_ptr->nlmsg_pid = local_nl.nl_pid;
|
||||
|
||||
ghdr = (struct genlmsghdr *) NLMSG_DATA (msg_ptr);
|
||||
ghdr->cmd = NL80211_CMD_GET_INTERFACE;
|
||||
ghdr->version = 0;
|
||||
|
||||
rta_addattr_l (msg_ptr, sizeof (buffer), NL80211_ATTR_IFINDEX, &iface->index, 4);
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = msg_ptr->nlmsg_len;
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof(kernel);
|
||||
|
||||
sendmsg (handle->netlink_sock_request_generic, (struct msghdr *) &rtnl_msg, 0);
|
||||
|
||||
/* Esperar la respuesta */
|
||||
memset (&io, 0, sizeof (io));
|
||||
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
io.iov_base = buffer;
|
||||
io.iov_len = sizeof (buffer);
|
||||
rtnl_msg.msg_iov = &io;
|
||||
rtnl_msg.msg_iovlen = 1;
|
||||
rtnl_msg.msg_name = &kernel;
|
||||
rtnl_msg.msg_namelen = sizeof (kernel);
|
||||
|
||||
while ((len = recvmsg(handle->netlink_sock_request_generic, &rtnl_msg, 0)) > 0) { /* read lots of data */
|
||||
msg_ptr = (struct nlmsghdr *) buffer;
|
||||
if (msg_ptr->nlmsg_type == NLMSG_DONE) break;
|
||||
if (msg_ptr->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *l_err;
|
||||
l_err = (struct nlmsgerr*) NLMSG_DATA (msg_ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg_ptr->nlmsg_type == nl80211_id) {
|
||||
_wireless_parse_message_get_iface (msg_ptr, iface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
Loading…
Reference in New Issue