Agrego código del cliente de DHCP
parent
3fffcddaf9
commit
854405b9d2
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue