Agrego código del cliente de DHCP

master
Félix Arreola Rodríguez 2018-08-23 13:31:27 -05:00
parent 3fffcddaf9
commit 854405b9d2
28 changed files with 4139 additions and 27 deletions

1
.gitignore vendored
View File

@ -19,6 +19,7 @@ config.log
config.status config.status
.deps .deps
src/network-inador src/network-inador
src/dhcpc/nidhcpc
*.o *.o
stamp-h1 stamp-h1

View File

@ -48,6 +48,7 @@ AC_CONFIG_FILES([
Makefile Makefile
src/Makefile src/Makefile
po/Makefile.in po/Makefile.in
src/dhcpc/Makefile
]) ])
# data/Makefile # data/Makefile

View File

@ -2,13 +2,15 @@
bin_PROGRAMS = network-inador bin_PROGRAMS = network-inador
network_inador_SOURCES = network-inador.c network-inador.h \ network_inador_SOURCES = network-inador.c network-inador.h \
events.c events.h \ netlink-events.c netlink-events.h \
interfaces.c interfaces.h \ interfaces.c interfaces.h \
manager.c manager.h \ manager.c manager.h \
utils.c utils.h \ utils.c utils.h \
bridge.c bridge.h \ bridge.c bridge.h \
rta_aux.c rta_aux.h \ rta_aux.c rta_aux.h \
routes.c routes.h routes.c routes.h \
manager-events.c manager-events.h \
dhcp.c dhcp.h
#network_inador_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) #network_inador_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS)
network_inador_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) network_inador_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS)
@ -16,3 +18,4 @@ network_inador_CFLAGS = $(GLIB_CFLAGS) $(AM_CFLAGS)
network_inador_LDADD = $(GLIB_LIBS) network_inador_LDADD = $(GLIB_LIBS)
LDADD = $(LIBINTL) LDADD = $(LIBINTL)
SUBDIRS = dhcpc

View File

@ -2,7 +2,7 @@
* bridge.c * bridge.c
* This file is part of Network-inador * This file is part of Network-inador
* *
* Copyright (C) 2011 - Félix Arreola Rodríguez * Copyright (C) 2018 - Félix Arreola Rodríguez
* *
* Network-inador is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
* bridge.h * bridge.h
* This file is part of Network-inador * This file is part of Network-inador
* *
* Copyright (C) 2011 - Félix Arreola Rodríguez * Copyright (C) 2018 - Félix Arreola Rodríguez
* *
* Network-inador is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

277
src/dhcp.c 100644
View File

@ -0,0 +1,277 @@
/*
* 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"
#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 */
}
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);
}
}

28
src/dhcp.h 100644
View File

@ -0,0 +1,28 @@
/*
* 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);
#endif

View File

@ -0,0 +1,17 @@
# 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)

441
src/dhcpc/common.c 100644
View File

@ -0,0 +1,441 @@
/* 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
);
}

317
src/dhcpc/common.h 100644
View File

@ -0,0 +1,317 @@
/* 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 100644

File diff suppressed because it is too large Load Diff

39
src/dhcpc/dhcpc.h 100644
View File

@ -0,0 +1,39 @@
/* 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

128
src/dhcpc/dhcpd.h 100644
View File

@ -0,0 +1,128 @@
/* 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

499
src/dhcpc/extra.c 100644
View File

@ -0,0 +1,499 @@
#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;
}

198
src/dhcpc/extra.h 100644
View File

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

View File

@ -0,0 +1,40 @@
#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;
}

194
src/dhcpc/packet.c 100644
View File

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

View File

@ -0,0 +1,86 @@
/* 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;
}

122
src/dhcpc/socket.c 100644
View File

@ -0,0 +1,122 @@
/* vi: set sw=4 ts=4: */
/*
* DHCP server client/server socket creation
*
* udhcp client/server
* Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
* Chris Trew <ctrew@moreton.com.au>
*
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "extra.h"
#include "common.h"
int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac)
{
/* char buffer instead of bona-fide struct avoids aliasing warning */
char ifr_buf[sizeof(struct ifreq)];
struct ifreq *const ifr = (void *)ifr_buf;
int fd;
struct sockaddr_in *our_ip;
memset(ifr, 0, sizeof(*ifr));
fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
ifr->ifr_addr.sa_family = AF_INET;
strncpy_IFNAMSIZ(ifr->ifr_name, interface);
if (nip) {
if (ioctl_or_perror(fd, SIOCGIFADDR, ifr)
) {
close(fd);
return -1;
}
our_ip = (struct sockaddr_in *) &ifr->ifr_addr;
*nip = our_ip->sin_addr.s_addr;
log1("IP %s", inet_ntoa(our_ip->sin_addr));
}
if (ifindex) {
if (ioctl_or_perror(fd, SIOCGIFINDEX, ifr) != 0) {
close(fd);
return -1;
}
log1("Adapter index %d", ifr->ifr_ifindex);
*ifindex = ifr->ifr_ifindex;
}
if (mac) {
if (ioctl_or_perror(fd, SIOCGIFHWADDR, ifr) != 0) {
close(fd);
return -1;
}
memcpy(mac, ifr->ifr_hwaddr.sa_data, 6);
log1("MAC %02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
close(fd);
return 0;
}
/* 1. None of the callers expects it to ever fail */
/* 2. ip was always INADDR_ANY */
int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf)
{
int fd;
struct sockaddr_in addr;
char *colon;
log1("Opening listen socket on *:%d %s", port, inf);
fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
setsockopt_reuseaddr(fd);
if (setsockopt_broadcast(fd) == -1) {
fprintf (stderr, "SO_BROADCAST");
exit (EXIT_FAILURE);
}
/* SO_BINDTODEVICE doesn't work on ethernet aliases (ethN:M) */
colon = strrchr(inf, ':');
if (colon)
*colon = '\0';
if (setsockopt_bindtodevice(fd, inf)) {
exit (EXIT_FAILURE); /* warning is already printed */
}
if (colon)
*colon = ':';
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
/* addr.sin_addr.s_addr = ip; - all-zeros is INADDR_ANY */
xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
return fd;
}

View File

@ -2,7 +2,7 @@
* interfaces.c * interfaces.c
* This file is part of Network-inador * This file is part of Network-inador
* *
* Copyright (C) 2011 - Félix Arreola Rodríguez * Copyright (C) 2018 - Félix Arreola Rodríguez
* *
* Network-inador is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -42,6 +42,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "interfaces.h" #include "interfaces.h"
#include "manager-events.h"
Interface * interfaces_locate_by_index (Interface *list, int index); Interface * interfaces_locate_by_index (Interface *list, int index);
static IPv4 * _interfaces_append_ipv4_to_struct (Interface *interface, struct in_addr address, uint32_t prefix); static IPv4 * _interfaces_append_ipv4_to_struct (Interface *interface, struct in_addr address, uint32_t prefix);
@ -183,7 +184,7 @@ void interfaces_add_or_update_rtnl_link (NetworkInadorHandle *handle, struct nlm
struct rtattr *attribute; struct rtattr *attribute;
int len; int len;
Interface *new, *last; Interface *new, *last;
int was_new = 0;
iface = NLMSG_DATA(h); iface = NLMSG_DATA(h);
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
@ -208,6 +209,8 @@ void interfaces_add_or_update_rtnl_link (NetworkInadorHandle *handle, struct nlm
last->next = new; last->next = new;
} }
was_new = 1;
} }
if (iface->ifi_family == AF_BRIDGE) { if (iface->ifi_family == AF_BRIDGE) {
@ -443,6 +446,7 @@ void interfaces_add_or_update_ipv4 (NetworkInadorHandle *handle, struct nlmsghdr
if (new == NULL) { if (new == NULL) {
printf ("Agregando IP a la lista de IP's\n"); printf ("Agregando IP a la lista de IP's\n");
new = _interfaces_append_ipv4_to_struct (iface, ip, prefix); new = _interfaces_append_ipv4_to_struct (iface, ip, prefix);
manager_events_notify_ipv4_address_added (iface, new);
} }
new->flags = addr->ifa_flags; new->flags = addr->ifa_flags;

View File

@ -2,7 +2,7 @@
* interfaces.h * interfaces.h
* This file is part of Network-inador * This file is part of Network-inador
* *
* Copyright (C) 2011 - Félix Arreola Rodríguez * Copyright (C) 2018 - Félix Arreola Rodríguez
* *
* Network-inador is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -0,0 +1,195 @@
/*
* manager-events.c
* This file is part of Network-inador
*
* Copyright (C) 2018 - Félix Arreola Rodríguez
*
* Network-inador is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Network-inador is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Network-inador; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/wireless.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <glib.h>
#include "network-inador.h"
#include "manager-events.h"
#define EVENTS_SOCKET_PATH "/tmp/network-inador.events"
#define MANAGER_EVENTS_MAX_CLIENT 50
static int _manager_events_clients[MANAGER_EVENTS_MAX_CLIENT];
static int _manager_events_client_count = 0;
static gboolean _manager_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) {
char buffer[128];
int sock;
int ret;
int g;
sock = g_io_channel_unix_get_fd (source);
ret = read (sock, buffer, sizeof (buffer));
if (ret == 0) {
/* El socket del cliente se cerró */
for (g = 0; g < _manager_events_client_count; g++) {
if (_manager_events_clients[g] == sock) {
/* Te encontré */
if (_manager_events_client_count - 1 == g) {
/* Es el último socket del arreglo */
_manager_events_clients[g] = 0;
_manager_events_client_count--;
} else {
/* Recorrer el último en posición de éste */
_manager_events_clients[g] = _manager_events_clients[_manager_events_client_count - 1];
_manager_events_clients[_manager_events_client_count - 1] = 0;
_manager_events_client_count--;
}
break;
}
}
close (sock);
} else {
/* Procesar data o errores de lectura */
}
}
static gboolean _manager_events_handle_new_conn (GIOChannel *source, GIOCondition condition, gpointer data) {
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
int sock;
int new_c;
GIOChannel *channel;
sock = g_io_channel_unix_get_fd (source);
new_c = accept (sock, NULL, NULL);
if (new_c < 0) {
printf ("Error al aceptar cliente\n");
return TRUE;
}
if (fcntl (new_c, F_SETFD, FD_CLOEXEC) < 0) {
printf ("Error set close-on-exec");
}
if (_manager_events_client_count == MANAGER_EVENTS_MAX_CLIENT) {
/* Rechazar el cliente por estar al máximo de capacidad */
close (new_c);
return TRUE;
}
channel = g_io_channel_unix_new (new_c);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_events_handle_read, handle);
/* Agregar a la lista de clientes */
_manager_events_clients [_manager_events_client_count] = new_c;
_manager_events_client_count++;
return TRUE;
}
void manager_events_notify_ipv4_address_added (Interface *iface, IPv4 *address) {
char buffer[128];
int size;
int g;
buffer[0] = 0;
buffer[1] = MANAGER_EVENT_IPV4_ADDED;
buffer[2] = iface->index;
memcpy (&buffer[3], &address->sin_addr, sizeof (address->sin_addr));
buffer[7] = address->prefix;
size = 8;
for (g = 0; g < _manager_events_client_count; g++) {
write (_manager_events_clients [g], buffer, size);
}
}
void manager_events_setup (NetworkInadorHandle *handle) {
int sock;
struct sockaddr_un socket_name;
GIOChannel *channel;
sock = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sock < 0) {
perror ("Failed to create AF_UNIX socket");
return;
}
memset (_manager_events_clients, 0, sizeof (_manager_events_clients));
memset (&socket_name, 0, sizeof (struct sockaddr_un));
socket_name.sun_family = AF_UNIX;
strncpy (socket_name.sun_path, EVENTS_SOCKET_PATH, sizeof (socket_name.sun_path) - 1);
unlink (EVENTS_SOCKET_PATH);
if (bind (sock, (struct sockaddr *) &socket_name, sizeof (struct sockaddr_un)) < 0) {
perror ("Bind");
close (sock);
return;
}
if (listen (sock, 20)) {
perror ("Listen");
close (sock);
unlink (EVENTS_SOCKET_PATH);
return;
}
/* TODO: Aplicar permisos aquí */
chmod (EVENTS_SOCKET_PATH, 0666);
channel = g_io_channel_unix_new (sock);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_events_handle_new_conn, handle);
}

View File

@ -0,0 +1,37 @@
/*
* manager-events.h
* This file is part of Network-inador
*
* Copyright (C) 2018 - Félix Arreola Rodríguez
*
* Network-inador is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Network-inador is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Network-inador; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef __MANAGER_EVENTS_H__
#define __MANAGER_EVENTS_H__
#include "network-inador.h"
enum {
MANAGER_EVENT_IPV4_ADDED = 1,
MANAGER_EVENT_IPV4_REMOVED,
};
void manager_events_notify_ipv4_address_added (Interface *iface, IPv4 *address);
void manager_events_setup (NetworkInadorHandle *handle);
#endif

View File

@ -39,11 +39,13 @@
#include "interfaces.h" #include "interfaces.h"
#include "network-inador.h" #include "network-inador.h"
#define SOCKET_PATH "/tmp/network-inador.socket" #define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
enum { enum {
MANAGER_COMMAND_REQUEST = 0, MANAGER_EVENT = 0,
MANAGER_COMMAND_LIST_IFACES = 0,
MANAGER_COMMAND_REQUEST = 1,
MANAGER_COMMAND_LIST_IFACES = 1,
MANAGER_COMMAND_BRING_UP_IFACE, MANAGER_COMMAND_BRING_UP_IFACE,
MANAGER_COMMAND_BRING_DOWN_IFACE, MANAGER_COMMAND_BRING_DOWN_IFACE,
@ -55,6 +57,7 @@ enum {
MANAGER_COMMAND_LIST_IPV4, MANAGER_COMMAND_LIST_IPV4,
MANAGER_COMMAND_RUN_DHCP_CLIENT, MANAGER_COMMAND_RUN_DHCP_CLIENT,
MANAGER_COMMAND_STOP_DHCP_CLIENT,
MANAGER_COMMAND_LIST_ROUTES, MANAGER_COMMAND_LIST_ROUTES,
@ -475,6 +478,12 @@ static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition
break; break;
case MANAGER_COMMAND_REMOVE_IPV4: case MANAGER_COMMAND_REMOVE_IPV4:
_manager_handle_interface_del_ipv4 (handle, &request); _manager_handle_interface_del_ipv4 (handle, &request);
break;
case MANAGER_COMMAND_RUN_DHCP_CLIENT:
break;
case MANAGER_COMMAND_STOP_DHCP_CLIENT:
break; break;
case MANAGER_COMMAND_LIST_IPV4: case MANAGER_COMMAND_LIST_IPV4:
_manager_send_list_ipv4 (handle, &request); _manager_send_list_ipv4 (handle, &request);
@ -506,9 +515,9 @@ int manager_setup_socket (NetworkInadorHandle *handle) {
memset (&socket_name, 0, sizeof (struct sockaddr_un)); memset (&socket_name, 0, sizeof (struct sockaddr_un));
socket_name.sun_family = AF_UNIX; socket_name.sun_family = AF_UNIX;
strncpy (socket_name.sun_path, SOCKET_PATH, sizeof (socket_name.sun_path) - 1); strncpy (socket_name.sun_path, COMMAND_SOCKET_PATH, sizeof (socket_name.sun_path) - 1);
unlink (SOCKET_PATH); unlink (COMMAND_SOCKET_PATH);
if (bind (sock, (struct sockaddr *) &socket_name, sizeof (struct sockaddr_un)) < 0) { if (bind (sock, (struct sockaddr *) &socket_name, sizeof (struct sockaddr_un)) < 0) {
perror ("Bind"); perror ("Bind");
@ -517,11 +526,11 @@ int manager_setup_socket (NetworkInadorHandle *handle) {
} }
/* TODO: Aplicar permisos aquí */ /* TODO: Aplicar permisos aquí */
chmod (SOCKET_PATH, 0666); chmod (COMMAND_SOCKET_PATH, 0666);
channel = g_io_channel_unix_new (sock); channel = g_io_channel_unix_new (sock);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI, _manager_client_data, handle); g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_client_data, handle);
return 0; return 0;
} }

View File

@ -1,5 +1,5 @@
/* /*
* events.c * netlink-events.c
* This file is part of Network-inador * This file is part of Network-inador
* *
* Copyright (C) 2018 - Félix Arreola Rodríguez * Copyright (C) 2018 - Félix Arreola Rodríguez
@ -45,12 +45,12 @@
#include <glib.h> #include <glib.h>
#include "events.h" #include "netlink-events.h"
#include "network-inador.h" #include "network-inador.h"
#include "interfaces.h" #include "interfaces.h"
#include "routes.h" #include "routes.h"
static gboolean _events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) { static gboolean _netlink_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) {
NetworkInadorHandle *handle = (NetworkInadorHandle *) data; NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
int sock; int sock;
@ -116,11 +116,11 @@ static gboolean _events_handle_read (GIOChannel *source, GIOCondition condition,
return TRUE; return TRUE;
} }
void events_setup_loop (NetworkInadorHandle *handle, int sock) { void netlink_events_setup_loop (NetworkInadorHandle *handle, int sock) {
GIOChannel *channel; GIOChannel *channel;
channel = g_io_channel_unix_new (sock); channel = g_io_channel_unix_new (sock);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI, _events_handle_read, handle); g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _netlink_events_handle_read, handle);
} }

View File

@ -1,8 +1,8 @@
/* /*
* events.h * netlink-events.h
* This file is part of Network-inador * This file is part of Network-inador
* *
* Copyright (C) 2011 - Félix Arreola Rodríguez * Copyright (C) 2018 - Félix Arreola Rodríguez
* *
* Network-inador is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -20,12 +20,12 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
#ifndef __EVENTS_H__ #ifndef __NETLINK_EVENTS_H__
#define __EVENTS_H__ #define __NETLINK_EVENTS_H__
#include "network-inador.h" #include "network-inador.h"
void events_setup_loop (NetworkInadorHandle *handle, int sock); void netlink_events_setup_loop (NetworkInadorHandle *handle, int sock);
#endif #endif

View File

@ -42,10 +42,12 @@
#include "network-inador.h" #include "network-inador.h"
#include "interfaces.h" #include "interfaces.h"
#include "events.h" #include "netlink-events.h"
#include "manager.h" #include "manager.h"
#include "bridge.h" #include "bridge.h"
#include "routes.h" #include "routes.h"
#include "manager-events.h"
#include "dhcp.h"
static GMainLoop *loop = NULL; static GMainLoop *loop = NULL;
@ -78,7 +80,6 @@ int main (int argc, char *argv[]) {
int nl_sock; int nl_sock;
int nl_watch; int nl_watch;
signal (SIGPIPE, SIG_IGN);
#if !defined(GLIB_VERSION_2_36) #if !defined(GLIB_VERSION_2_36)
g_type_init (); g_type_init ();
@ -95,11 +96,13 @@ int main (int argc, char *argv[]) {
handle.netlink_sock_request = nl_sock; handle.netlink_sock_request = nl_sock;
nl_watch = create_ntlink_socket (-1); nl_watch = create_ntlink_socket (-1);
manager_events_setup (&handle);
interfaces_list_all (&handle, nl_sock); interfaces_list_all (&handle, nl_sock);
routes_list (&handle, nl_sock); routes_list (&handle, nl_sock);
events_setup_loop (&handle, nl_watch); netlink_events_setup_loop (&handle, nl_watch);
manager_setup_socket (&handle); manager_setup_socket (&handle);

View File

@ -29,6 +29,33 @@
#include <linux/if.h> #include <linux/if.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <unistd.h>
#include <glib.h>
/* Para almacenar la información de DHCP */
enum {
IFACE_NO_DHCP_RUNNING = 0,
IFACE_DHCP_CLIENT,
};
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 { typedef struct _IPv4 {
struct in_addr sin_addr; struct in_addr sin_addr;
uint32_t prefix; uint32_t prefix;
@ -63,6 +90,8 @@ typedef struct _Interface {
IPv4 *v4_address; IPv4 *v4_address;
DHCPStateInfo dhcp_info;
struct _Interface *next; struct _Interface *next;
} Interface; } Interface;