remerge with busybox

This commit is contained in:
Russ Dill 2003-12-18 22:35:01 +00:00
parent 4d1bfe0b76
commit 9b98f2c1ab
32 changed files with 666 additions and 454 deletions

View File

@ -9,5 +9,6 @@ Other Credits:
--------------
Moreton Bay (http://www.moretonbay.com/)
Lineo (http://opensource.lineo.com)
Vladimir Oleynik <dzo@simtrea.ru> Size optimizations

View File

@ -1,4 +1,6 @@
0.9.9 (pending)
+ Various other size optimizations (Vladimir)
+ Change strerror(errno) to %m (Vladimir N. Oleynik <dzo@simtreas.ru>)
+ Fixed a little endian problem in mton (Bastian Blank <waldi@debian.org>)
+ Fixed a arpping alignment problem (Rui He <rhe@3eti.com>)
+ Added sanity check for max_leases (udhcp bug #1285) (me)
@ -32,7 +34,7 @@
udhcp bug#1256
+ Fixed reading of client id (David Poole <davep@portsmith.com>)
+ change sys_errlist[] to strerror() as it aparently doesn't exist
(andersee <andersee@codepoet.org>)
(Erik Andersen <andersee@codepoet.org>)
+ fixed get_raw_packet so it returns -2 on non fatal errors
(Ted Lemon <Ted.Lemon@nominum.com>)
+ Improved (hopefully) NAKing behavior (me)

View File

@ -8,22 +8,22 @@ USRSHAREDIR=${prefix}/share
# Uncomment this to get a shared binary. Call as udhcpd for the server,
# and udhcpc for the client
#COMBINED_BINARY=1
COMBINED_BINARY=1
# Uncomment this for extra output and to compile with debugging symbols
#DEBUG=1
#UDHCP_DEBUG=1
# Uncomment this to output messages to syslog, otherwise, messages go to stdout
CFLAGS += -DSYSLOG
#CFLAGS += -DUDHCP_SYSLOG
#CROSS_COMPILE=arm-uclibc-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)gcc
INSTALL = install
OBJS_SHARED = options.o socket.o packet.o pidfile.o
OBJS_SHARED = common.o options.o packet.o pidfile.o signalpipe.o socket.o
DHCPD_OBJS = dhcpd.o arpping.o files.o leases.o serverpacket.o
DHCPC_OBJS = dhcpc.o clientpacket.o script.o
DHCPC_OBJS = dhcpc.o clientpacket.o clientsocket.o script.o
ifdef COMBINED_BINARY
EXEC1 = udhcpd
@ -44,14 +44,14 @@ BOOT_PROGRAMS = udhcpc
DAEMONS = udhcpd
COMMANDS = dumpleases
ifdef SYSLOG
CFLAGS += -DSYSLOG
ifdef UDHCP_SYSLOG
CFLAGS += -DUDHCP_SYSLOG
endif
CFLAGS += -W -Wall -Wstrict-prototypes
CFLAGS += -W -Wall -Wstrict-prototypes -D_GNU_SOURCE
ifdef DEBUG
CFLAGS += -g -DDEBUG
ifdef UDHCP_DEBUG
CFLAGS += -g -DUDHCP_DEBUG
STRIP=true
else
CFLAGS += -Os -fomit-frame-pointer

13
README
View File

@ -11,19 +11,22 @@ compile time options
The Makefile contains three of the compile time options:
DEBUG: If DEBUG is defined, udhcpd will output extra debugging
output, compile with -g, and not fork to the background when run.
SYSLOG: If SYSLOG is defined, udhcpd will log all its messages
syslog, otherwise, it will attempt to log them to stdout.
UDHCP_DEBUG: If UDHCP_DEBUG is defined, udhcpd will output extra
debugging output, compile with -g, and not fork to the background when
run.
UDHCP_SYSLOG: If UDHCP_SYSLOG is defined, udhcpd will log all its
messages syslog, otherwise, it will attempt to log them to stdout.
COMBINED_BINARY: If COMBINED_BINARY is define, one binary, udhcpd,
is created. If called as udhcpd, the dhcp server will be started.
If called as udhcpc, the dhcp client will be started.
dhcpd.h contains the other two compile time options:
dhcpd.h contains the other three compile time options:
LEASE_TIME: The default lease time if not specified in the config
file.
LEASES_FILE: The default file for storing leases.
DHCPD_CONFIG_FILE: The defualt config file to use.

View File

@ -5,22 +5,19 @@
* by Yoichi Hariguchi <yoichi@fore.com>
*/
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "dhcpd.h"
#include "debug.h"
#include "arpping.h"
#include "common.h"
/* args: yiaddr - what IP to ping
* ip - our ip
@ -47,7 +44,11 @@ int arpping(u_int32_t yiaddr, u_int32_t ip, unsigned char *mac, char *interface)
if ((s = socket (PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) == -1) {
#ifdef IN_BUSYBOX
LOG(LOG_ERR, bb_msg_can_not_create_raw_socket);
#else
LOG(LOG_ERR, "Could not open raw socket");
#endif
return -1;
}
@ -84,7 +85,7 @@ int arpping(u_int32_t yiaddr, u_int32_t ip, unsigned char *mac, char *interface)
FD_SET(s, &fdset);
tm.tv_sec = timeout;
if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0) {
DEBUG(LOG_ERR, "Error on ARPING request: %s", strerror(errno));
DEBUG(LOG_ERR, "Error on ARPING request: %m");
if (errno != EINTR) rv = 0;
} else if (FD_ISSET(s, &fdset)) {
if (recv(s, &arp, sizeof(arp), 0) < 0 ) rv = 0;

View File

@ -35,17 +35,14 @@
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "dhcpd.h"
#include "packet.h"
#include "clientpacket.h"
#include "options.h"
#include "dhcpc.h"
#include "debug.h"
#include "common.h"
/* Create a random xid */
@ -58,8 +55,7 @@ unsigned long random_xid(void)
fd = open("/dev/urandom", 0);
if (fd < 0 || read(fd, &seed, sizeof(seed)) < 0) {
LOG(LOG_WARNING, "Could not load seed from /dev/urandom: %s",
strerror(errno));
LOG(LOG_WARNING, "Could not load seed from /dev/urandom: %m");
seed = time(0);
}
if (fd >= 0) close(fd);
@ -95,9 +91,9 @@ static void add_requests(struct dhcpMessage *packet)
int i, len = 0;
packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
for (i = 0; options[i].code; i++)
if (options[i].flags & OPTION_REQ)
packet->options[end + OPT_DATA + len++] = options[i].code;
for (i = 0; dhcp_options[i].code; i++)
if (dhcp_options[i].flags & OPTION_REQ)
packet->options[end + OPT_DATA + len++] = dhcp_options[i].code;
packet->options[end + OPT_LEN] = len;
packet->options[end + OPT_DATA + len] = DHCP_END;
@ -250,4 +246,3 @@ int get_raw_packet(struct dhcpMessage *payload, int fd)
return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
}

View File

@ -1,6 +1,8 @@
#ifndef _CLIENTPACKET_H
#define _CLIENTPACKET_H
#include "packet.h"
unsigned long random_xid(void);
int send_discover(unsigned long xid, unsigned long requested);
int send_selecting(unsigned long xid, unsigned long server, unsigned long requested);

62
clientsocket.c Normal file
View File

@ -0,0 +1,62 @@
/*
* clientsocket.c -- DHCP client socket creation
*
* udhcp client
*
* 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 <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <features.h>
#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#endif
#include "clientsocket.h"
#include "common.h"
int raw_socket(int ifindex)
{
int fd;
struct sockaddr_ll sock;
DEBUG(LOG_INFO, "Opening raw socket on ifindex %d", ifindex);
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
DEBUG(LOG_ERR, "socket call failed: %m");
return -1;
}
sock.sll_family = AF_PACKET;
sock.sll_protocol = htons(ETH_P_IP);
sock.sll_ifindex = ifindex;
if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
DEBUG(LOG_ERR, "bind call failed: %m");
close(fd);
return -1;
}
return fd;
}

7
clientsocket.h Normal file
View File

@ -0,0 +1,7 @@
/* clientsocket.h */
#ifndef _CLIENTSOCKET_H
#define _CLIENTSOCKET_H
int raw_socket(int ifindex);
#endif

156
common.c Normal file
View File

@ -0,0 +1,156 @@
/* common.c
*
* Functions for debugging and logging as well as some other
* simple helper functions.
*
* Russ Dill <Russ.Dill@asu.edu> 2001-2003
* Rewrited by Vladimir Oleynik <dzo@simtreas.ru> (C) 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 <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <paths.h>
#include <sys/socket.h>
#include <stdarg.h>
#include "common.h"
#include "pidfile.h"
static int daemonized;
/*
* This function makes sure our first socket calls
* aren't going to fd 1 (printf badness...) and are
* not later closed by daemon()
*/
static inline void sanitize_fds(void)
{
int zero;
if ((zero = open(_PATH_DEVNULL, O_RDWR, 0)) < 0) return;
while (zero < 3) zero = dup(zero);
close(zero);
}
void background(const char *pidfile)
{
#ifdef __uClinux__
LOG(LOG_ERR, "Cannot background in uclinux (yet)");
#else /* __uClinux__ */
int pid_fd;
if (!pidfile) return;
pid_fd = pidfile_acquire(pidfile); /* hold lock during fork. */
if (daemon(0, 0) == -1) {
perror("fork");
exit(1);
}
daemonized++;
pidfile_write_release(pid_fd);
#endif /* __uClinux__ */
}
#ifdef UDHCP_SYSLOG
void udhcp_logging(int level, const char *fmt, ...)
{
va_list p;
va_list p2;
va_start(p, fmt);
__va_copy(p2, p);
if(!daemonized) {
vprintf(fmt, p);
putchar('\n');
}
vsyslog(level, fmt, p2);
va_end(p);
}
void start_log_and_pid(const char *client_server, const char *pidfile)
{
int pid_fd;
/* Make sure our syslog fd isn't overwritten */
sanitize_fds();
/* do some other misc startup stuff while we are here to save bytes */
pid_fd = pidfile_acquire(pidfile);
pidfile_write_release(pid_fd);
/* equivelent of doing a fflush after every \n */
setlinebuf(stdout);
openlog(client_server, LOG_PID | LOG_CONS, LOG_LOCAL0);
udhcp_logging(LOG_INFO, "%s (v%s) started", client_server, VERSION);
}
#else
static char *syslog_level_msg[] = {
[LOG_EMERG] = "EMERGENCY!",
[LOG_ALERT] = "ALERT!",
[LOG_CRIT] = "critical!",
[LOG_WARNING] = "warning",
[LOG_ERR] = "error",
[LOG_INFO] = "info",
[LOG_DEBUG] = "debug"
};
void udhcp_logging(int level, const char *fmt, ...)
{
va_list p;
va_start(p, fmt);
if(!daemonized) {
printf("%s, ", syslog_level_msg[level]);
vprintf(fmt, p);
putchar('\n');
}
va_end(p);
}
void start_log_and_pid(const char *client_server, const char *pidfile)
{
int pid_fd;
/* Make sure our syslog fd isn't overwritten */
sanitize_fds();
/* do some other misc startup stuff while we are here to save bytes */
pid_fd = pidfile_acquire(pidfile);
pidfile_write_release(pid_fd);
/* equivelent of doing a fflush after every \n */
setlinebuf(stdout);
udhcp_logging(LOG_INFO, "%s (v%s) started", client_server, VERSION);
}
#endif

55
common.h Normal file
View File

@ -0,0 +1,55 @@
/* common.h
*
* Russ Dill <Russ.Dill@asu.edu> Soptember 2001
* Rewrited by Vladimir Oleynik <dzo@simtreas.ru> (C) 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.
*/
#ifndef _COMMON_H
#define _COMMON_H
#include "version.h"
#include "libbb_udhcp.h"
#ifndef UDHCP_SYSLOG
enum syslog_levels {
LOG_EMERG = 0,
LOG_ALERT,
LOG_CRIT,
LOG_WARNING,
LOG_ERR,
LOG_INFO,
LOG_DEBUG
};
#else
#include <syslog.h>
#endif
void background(const char *pidfile);
void start_log_and_pid(const char *client_server, const char *pidfile);
void background(const char *pidfile);
void udhcp_logging(int level, const char *fmt, ...);
#define LOG(level, str, args...) udhcp_logging(level, str, ## args)
#ifdef UDHCP_DEBUG
# define DEBUG(level, str, args...) LOG(level, str, ## args)
#else
# define DEBUG(level, str, args...) do {;} while(0)
#endif
#endif

41
debug.h
View File

@ -1,41 +0,0 @@
#ifndef _DEBUG_H
#define _DEBUG_H
#include "libbb_udhcp.h"
#include <stdio.h>
#ifdef SYSLOG
#include <syslog.h>
#endif
#ifdef SYSLOG
# define LOG(level, str, args...) do { printf(str, ## args); \
printf("\n"); \
syslog(level, str, ## args); } while(0)
# define OPEN_LOG(name) openlog(name, 0, 0)
#define CLOSE_LOG() closelog()
#else
# define LOG_EMERG "EMERGENCY!"
# define LOG_ALERT "ALERT!"
# define LOG_CRIT "critical!"
# define LOG_WARNING "warning"
# define LOG_ERR "error"
# define LOG_INFO "info"
# define LOG_DEBUG "debug"
# define LOG(level, str, args...) do { printf("%s, ", level); \
printf(str, ## args); \
printf("\n"); } while(0)
# define OPEN_LOG(name) do {;} while(0)
#define CLOSE_LOG() do {;} while(0)
#endif
#ifdef DEBUG
# undef DEBUG
# define DEBUG(level, str, args...) LOG(level, str, ## args)
# define DEBUGGING
#else
# define DEBUG(level, str, args...) do {;} while(0)
#endif
#endif

97
dhcpc.c
View File

@ -19,9 +19,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/file.h>
#include <unistd.h>
#include <getopt.h>
@ -40,11 +38,11 @@
#include "dhcpc.h"
#include "options.h"
#include "clientpacket.h"
#include "packet.h"
#include "clientsocket.h"
#include "script.h"
#include "socket.h"
#include "debug.h"
#include "pidfile.h"
#include "common.h"
#include "signalpipe.h"
static int state;
static unsigned long requested_ip; /* = 0 */
@ -52,15 +50,12 @@ static unsigned long server_addr;
static unsigned long timeout;
static int packet_num; /* = 0 */
static int fd = -1;
static int signal_pipe[2];
#define LISTEN_NONE 0
#define LISTEN_KERNEL 1
#define LISTEN_RAW 2
static int listen_mode;
#define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script"
struct client_config_t client_config = {
/* Default options. */
abort_if_no_lease: 0,
@ -135,6 +130,7 @@ static void perform_renew(void)
state = INIT_SELECTING;
break;
case INIT_SELECTING:
break;
}
/* start things over */
@ -169,38 +165,11 @@ static void perform_release(void)
}
/* Exit and cleanup */
static void exit_client(int retval)
static void client_background(void)
{
pidfile_delete(client_config.pidfile);
CLOSE_LOG();
exit(retval);
}
/* Signal handler */
static void signal_handler(int sig)
{
if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
LOG(LOG_ERR, "Could not send signal: %s",
strerror(errno));
}
}
static void background(void)
{
int pid_fd;
pid_fd = pidfile_acquire(client_config.pidfile); /* hold lock during fork. */
while (pid_fd >= 0 && pid_fd < 3) pid_fd = dup(pid_fd); /* don't let daemon close it */
if (daemon(0, 0) == -1) {
perror("fork");
exit_client(1);
}
background(client_config.pidfile);
client_config.foreground = 1; /* Do not fork again. */
client_config.background_if_no_lease = 0;
pidfile_write_release(pid_fd);
}
@ -219,12 +188,11 @@ int main(int argc, char *argv[])
int c, len;
struct dhcpMessage packet;
struct in_addr temp_addr;
int pid_fd;
time_t now;
int max_fd;
int sig;
static struct option arg_options[] = {
static const struct option arg_options[] = {
{"clientid", required_argument, 0, 'c'},
{"foreground", no_argument, 0, 'f'},
{"background", no_argument, 0, 'b'},
@ -237,7 +205,6 @@ int main(int argc, char *argv[])
{"request", required_argument, 0, 'r'},
{"script", required_argument, 0, 's'},
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, '?'},
{0, 0, 0, 0}
};
@ -292,22 +259,19 @@ int main(int argc, char *argv[])
break;
case 'v':
printf("udhcpcd, version %s\n\n", VERSION);
exit_client(0);
return 0;
break;
default:
show_usage();
}
}
OPEN_LOG("udhcpc");
LOG(LOG_INFO, "udhcp client (v%s) started", VERSION);
pid_fd = pidfile_acquire(client_config.pidfile);
pidfile_write_release(pid_fd);
/* Start the log, sanitize fd's, and write a pid file */
start_log_and_pid("udhcpc", client_config.pidfile);
if (read_interface(client_config.interface, &client_config.ifindex,
NULL, client_config.arp) < 0)
exit_client(1);
return 1;
if (!client_config.clientid) {
client_config.clientid = xmalloc(6 + 3);
@ -317,11 +281,8 @@ int main(int argc, char *argv[])
memcpy(client_config.clientid + 3, client_config.arp, 6);
}
/* setup signal handlers */
socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
signal(SIGUSR1, signal_handler);
signal(SIGUSR2, signal_handler);
signal(SIGTERM, signal_handler);
/* setup the signal pipe */
udhcp_sp_setup();
state = INIT_SELECTING;
run_script(NULL, "deconfig");
@ -331,7 +292,6 @@ int main(int argc, char *argv[])
tv.tv_sec = timeout - time(0);
tv.tv_usec = 0;
FD_ZERO(&rfds);
if (listen_mode != LISTEN_NONE && fd < 0) {
if (listen_mode == LISTEN_KERNEL)
@ -339,16 +299,14 @@ int main(int argc, char *argv[])
else
fd = raw_socket(client_config.ifindex);
if (fd < 0) {
LOG(LOG_ERR, "FATAL: couldn't listen on socket, %s", strerror(errno));
exit_client(0);
LOG(LOG_ERR, "FATAL: couldn't listen on socket, %m");
return 0;
}
}
if (fd >= 0) FD_SET(fd, &rfds);
FD_SET(signal_pipe[0], &rfds);
max_fd = udhcp_sp_fd_set(&rfds, fd);
if (tv.tv_sec > 0) {
DEBUG(LOG_INFO, "Waiting on select...\n");
max_fd = signal_pipe[0] > fd ? signal_pipe[0] : fd;
DEBUG(LOG_INFO, "Waiting on select...");
retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
} else retval = 0; /* If we already timed out, fall through */
@ -367,12 +325,13 @@ int main(int argc, char *argv[])
timeout = now + ((packet_num == 2) ? 4 : 2);
packet_num++;
} else {
run_script(NULL, "leasefail");
if (client_config.background_if_no_lease) {
LOG(LOG_INFO, "No lease, forking to background.");
background();
client_background();
} else if (client_config.abort_if_no_lease) {
LOG(LOG_INFO, "No lease, failing.");
exit_client(1);
return 1;
}
/* wait to try again */
packet_num = 0;
@ -450,7 +409,7 @@ int main(int argc, char *argv[])
else len = get_raw_packet(&packet, fd);
if (len == -1 && errno != EINTR) {
DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
DEBUG(LOG_INFO, "error on read, %m, reopening socket");
change_mode(listen_mode); /* just close and reopen */
}
if (len < 0) continue;
@ -514,9 +473,9 @@ int main(int argc, char *argv[])
state = BOUND;
change_mode(LISTEN_NONE);
if (client_config.quit_after_lease)
exit_client(0);
return 0;
if (!client_config.foreground)
background();
client_background();
} else if (*message == DHCPNAK) {
/* return to init state */
@ -534,12 +493,7 @@ int main(int argc, char *argv[])
break;
/* case BOUND, RELEASED: - ignore all packets */
}
} else if (retval > 0 && FD_ISSET(signal_pipe[0], &rfds)) {
if (read(signal_pipe[0], &sig, sizeof(sig)) < 0) {
DEBUG(LOG_ERR, "Could not read signal: %s",
strerror(errno));
continue; /* probably just EINTR */
}
} else if (retval > 0 && (sig = udhcp_sp_read(&rfds))) {
switch (sig) {
case SIGUSR1:
perform_renew();
@ -549,7 +503,7 @@ int main(int argc, char *argv[])
break;
case SIGTERM:
LOG(LOG_INFO, "Received SIGTERM");
exit_client(0);
return 0;
}
} else if (retval == -1 && errno == EINTR) {
/* a signal was caught */
@ -561,4 +515,3 @@ int main(int argc, char *argv[])
}
return 0;
}

View File

@ -2,6 +2,9 @@
#ifndef _DHCPC_H
#define _DHCPC_H
#define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script"
/* allow libbb_udhcp.h to redefine DEFAULT_SCRIPT */
#include "libbb_udhcp.h"
#define INIT_SELECTING 0

102
dhcpd.c
View File

@ -25,12 +25,9 @@
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
@ -39,40 +36,19 @@
#include <time.h>
#include <sys/time.h>
#include "debug.h"
#include "dhcpd.h"
#include "arpping.h"
#include "socket.h"
#include "options.h"
#include "files.h"
#include "leases.h"
#include "packet.h"
#include "serverpacket.h"
#include "pidfile.h"
#include "common.h"
#include "signalpipe.h"
/* globals */
struct dhcpOfferedAddr *leases;
struct server_config_t server_config;
static int signal_pipe[2];
/* Exit and cleanup */
static void exit_server(int retval)
{
pidfile_delete(server_config.pidfile);
CLOSE_LOG();
exit(retval);
}
/* Signal handler */
static void signal_handler(int sig)
{
if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
LOG(LOG_ERR, "Could not send signal: %s",
strerror(errno));
}
}
#ifdef COMBINED_BINARY
@ -92,22 +68,14 @@ int main(int argc, char *argv[])
unsigned long timeout_end;
struct option_set *option;
struct dhcpOfferedAddr *lease;
int pid_fd;
int max_sock;
int sig;
unsigned long num_ips;
OPEN_LOG("udhcpd");
LOG(LOG_INFO, "udhcp server (v%s) started", VERSION);
memset(&server_config, 0, sizeof(struct server_config_t));
if (argc < 2)
read_config(DHCPD_CONF_FILE);
else read_config(argv[1]);
read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]);
pid_fd = pidfile_acquire(server_config.pidfile);
pidfile_write_release(pid_fd);
/* Start the log, sanitize fd's, and write a pid file */
start_log_and_pid("udhcpd", server_config.pidfile);
if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
memcpy(&server_config.lease, option->data + 2, 4);
@ -118,51 +86,41 @@ int main(int argc, char *argv[])
/* Sanity check */
num_ips = ntohl(server_config.end) - ntohl(server_config.start);
if (server_config.max_leases > num_ips) {
LOG(LOG_ERR, "max_leases value (%lu) not sane, setting to %lu instead",
LOG(LOG_ERR, "max_leases value (%lu) not sane, "
"setting to %lu instead",
server_config.max_leases, num_ips);
server_config.max_leases = num_ips;
}
leases = xmalloc(sizeof(struct dhcpOfferedAddr) * server_config.max_leases);
memset(leases, 0, sizeof(struct dhcpOfferedAddr) * server_config.max_leases);
leases = xcalloc(server_config.max_leases, sizeof(struct dhcpOfferedAddr));
read_leases(server_config.lease_file);
if (read_interface(server_config.interface, &server_config.ifindex,
&server_config.server, server_config.arp) < 0)
exit_server(1);
return 1;
#ifndef DEBUGGING
pid_fd = pidfile_acquire(server_config.pidfile); /* hold lock during fork. */
if (daemon(0, 0) == -1) {
perror("fork");
exit_server(1);
}
pidfile_write_release(pid_fd);
#ifndef UDHCP_DEBUG
background(server_config.pidfile); /* hold lock during fork. */
#endif
socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
signal(SIGUSR1, signal_handler);
signal(SIGTERM, signal_handler);
/* Setup the signal pipe */
udhcp_sp_setup();
timeout_end = time(0) + server_config.auto_time;
while(1) { /* loop until universe collapses */
if (server_socket < 0)
if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) {
LOG(LOG_ERR, "FATAL: couldn't create server socket, %s", strerror(errno));
exit_server(0);
LOG(LOG_ERR, "FATAL: couldn't create server socket, %m");
return 2;
}
FD_ZERO(&rfds);
FD_SET(server_socket, &rfds);
FD_SET(signal_pipe[0], &rfds);
max_sock = udhcp_sp_fd_set(&rfds, server_socket);
if (server_config.auto_time) {
tv.tv_sec = timeout_end - time(0);
tv.tv_usec = 0;
}
if (!server_config.auto_time || tv.tv_sec > 0) {
max_sock = server_socket > signal_pipe[0] ? server_socket : signal_pipe[0];
retval = select(max_sock + 1, &rfds, NULL, NULL,
server_config.auto_time ? &tv : NULL);
} else retval = 0; /* If we already timed out, fall through */
@ -176,25 +134,23 @@ int main(int argc, char *argv[])
continue;
}
if (FD_ISSET(signal_pipe[0], &rfds)) {
if (read(signal_pipe[0], &sig, sizeof(sig)) < 0)
continue; /* probably just EINTR */
switch (sig) {
case SIGUSR1:
LOG(LOG_INFO, "Received a SIGUSR1");
write_leases();
/* why not just reset the timeout, eh */
timeout_end = time(0) + server_config.auto_time;
continue;
case SIGTERM:
LOG(LOG_INFO, "Received a SIGTERM");
exit_server(0);
}
switch (udhcp_sp_read(&rfds)) {
case SIGUSR1:
LOG(LOG_INFO, "Received a SIGUSR1");
write_leases();
/* why not just reset the timeout, eh */
timeout_end = time(0) + server_config.auto_time;
continue;
case SIGTERM:
LOG(LOG_INFO, "Received a SIGTERM");
return 0;
case 0: break; /* no signal */
default: continue; /* signal or error (probably EINTR) */
}
if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
if (bytes == -1 && errno != EINTR) {
DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
DEBUG(LOG_INFO, "error on read, %m, reopening socket");
close(server_socket);
server_socket = -1;
}

181
files.c
View File

@ -11,14 +11,20 @@
#include <ctype.h>
#include <netdb.h>
#include "debug.h"
#include "dhcpd.h"
#include "files.h"
#include "options.h"
#include "leases.h"
#include "common.h"
/*
* Domain names may have 254 chars, and string options can be 254
* chars long. However, 80 bytes will be enough for most, and won't
* hog up memory. If you have a special application, change it
*/
#define READ_CONFIG_BUF_SIZE 80
/* on these functions, make sure you datatype matches */
static int read_ip(char *line, void *arg)
static int read_ip(const char *line, void *arg)
{
struct in_addr *addr = arg;
struct hostent *host;
@ -33,7 +39,7 @@ static int read_ip(char *line, void *arg)
}
static int read_str(char *line, void *arg)
static int read_str(const char *line, void *arg)
{
char **dest = arg;
@ -44,7 +50,7 @@ static int read_str(char *line, void *arg)
}
static int read_u32(char *line, void *arg)
static int read_u32(const char *line, void *arg)
{
u_int32_t *dest = arg;
char *endptr;
@ -53,7 +59,7 @@ static int read_u32(char *line, void *arg)
}
static int read_yn(char *line, void *arg)
static int read_yn(const char *line, void *arg)
{
char *dest = arg;
int retval = 1;
@ -69,87 +75,84 @@ static int read_yn(char *line, void *arg)
/* read a dhcp option and add it to opt_list */
static int read_opt(char *line, void *arg)
static int read_opt(const char *const_line, void *arg)
{
struct option_set **opt_list = arg;
char *opt, *val, *endptr;
struct dhcp_option *option = NULL;
int retval = 0, length = 0;
char buffer[255];
u_int16_t result_u16;
u_int32_t result_u32;
int i;
struct dhcp_option *option;
int retval = 0, length;
char buffer[8];
char *line;
u_int16_t *result_u16 = (u_int16_t *) buffer;
u_int32_t *result_u32 = (u_int32_t *) buffer;
/* Cheat, the only const line we'll actually get is "" */
line = (char *) const_line;
if (!(opt = strtok(line, " \t="))) return 0;
for (i = 0; options[i].code; i++)
if (!strcmp(options[i].name, opt))
option = &(options[i]);
if (!option) return 0;
for (option = dhcp_options; option->code; option++)
if (!strcasecmp(option->name, opt))
break;
if (!option->code) return 0;
do {
val = strtok(NULL, ", \t");
if (val) {
length = option_lengths[option->flags & TYPE_MASK];
retval = 0;
switch (option->flags & TYPE_MASK) {
case OPTION_IP:
retval = read_ip(val, buffer);
break;
case OPTION_IP_PAIR:
retval = read_ip(val, buffer);
if (!(val = strtok(NULL, ", \t/-"))) retval = 0;
if (retval) retval = read_ip(val, buffer + 4);
break;
case OPTION_STRING:
length = strlen(val);
if (length > 0) {
if (length > 254) length = 254;
memcpy(buffer, val, length);
retval = 1;
}
break;
case OPTION_BOOLEAN:
retval = read_yn(val, buffer);
break;
case OPTION_U8:
buffer[0] = strtoul(val, &endptr, 0);
retval = (endptr[0] == '\0');
break;
case OPTION_U16:
result_u16 = htons(strtoul(val, &endptr, 0));
memcpy(buffer, &result_u16, 2);
retval = (endptr[0] == '\0');
break;
case OPTION_S16:
result_u16 = htons(strtol(val, &endptr, 0));
memcpy(buffer, &result_u16, 2);
retval = (endptr[0] == '\0');
break;
case OPTION_U32:
result_u32 = htonl(strtoul(val, &endptr, 0));
memcpy(buffer, &result_u32, 4);
retval = (endptr[0] == '\0');
break;
case OPTION_S32:
result_u32 = htonl(strtol(val, &endptr, 0));
memcpy(buffer, &result_u32, 4);
retval = (endptr[0] == '\0');
break;
default:
break;
if (!(val = strtok(NULL, ", \t"))) break;
length = option_lengths[option->flags & TYPE_MASK];
retval = 0;
opt = buffer; /* new meaning for variable opt */
switch (option->flags & TYPE_MASK) {
case OPTION_IP:
retval = read_ip(val, buffer);
break;
case OPTION_IP_PAIR:
retval = read_ip(val, buffer);
if (!(val = strtok(NULL, ", \t/-"))) retval = 0;
if (retval) retval = read_ip(val, buffer + 4);
break;
case OPTION_STRING:
length = strlen(val);
if (length > 0) {
if (length > 254) length = 254;
opt = val;
retval = 1;
}
if (retval)
attach_option(opt_list, option, buffer, length);
};
} while (val && retval && option->flags & OPTION_LIST);
break;
case OPTION_BOOLEAN:
retval = read_yn(val, buffer);
break;
case OPTION_U8:
buffer[0] = strtoul(val, &endptr, 0);
retval = (endptr[0] == '\0');
break;
case OPTION_U16:
*result_u16 = htons(strtoul(val, &endptr, 0));
retval = (endptr[0] == '\0');
break;
case OPTION_S16:
*result_u16 = htons(strtol(val, &endptr, 0));
retval = (endptr[0] == '\0');
break;
case OPTION_U32:
*result_u32 = htonl(strtoul(val, &endptr, 0));
retval = (endptr[0] == '\0');
break;
case OPTION_S32:
*result_u32 = htonl(strtol(val, &endptr, 0));
retval = (endptr[0] == '\0');
break;
default:
break;
}
if (retval)
attach_option(opt_list, option, opt, length);
} while (retval && option->flags & OPTION_LIST);
return retval;
}
static struct config_keyword keywords[] = {
/* keyword[14] handler variable address default[20] */
static const struct config_keyword keywords[] = {
/* keyword handler variable address default */
{"start", read_ip, &(server_config.start), "192.168.0.20"},
{"end", read_ip, &(server_config.end), "192.168.0.254"},
{"interface", read_str, &(server_config.interface), "eth0"},
@ -173,11 +176,14 @@ static struct config_keyword keywords[] = {
};
int read_config(char *file)
int read_config(const char *file)
{
FILE *in;
char buffer[80], orig[80], *token, *line;
int i;
char buffer[READ_CONFIG_BUF_SIZE], *token, *line;
#ifdef UDHCP_DEBUG
char orig[READ_CONFIG_BUF_SIZE];
#endif
int i, lm = 0;
for (i = 0; keywords[i].keyword[0]; i++)
if (keywords[i].def[0])
@ -188,16 +194,16 @@ int read_config(char *file)
return 0;
}
while (fgets(buffer, 80, in)) {
while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) {
lm++;
if (strchr(buffer, '\n')) *(strchr(buffer, '\n')) = '\0';
strncpy(orig, buffer, 80);
#ifdef UDHCP_DEBUG
strcpy(orig, buffer);
#endif
if (strchr(buffer, '#')) *(strchr(buffer, '#')) = '\0';
token = buffer + strspn(buffer, " \t");
if (*token == '\0') continue;
line = token + strcspn(token, " \t=");
if (*line == '\0') continue;
*line = '\0';
line++;
if (!(token = strtok(buffer, " \t"))) continue;
if (!(line = strtok(NULL, ""))) continue;
/* eat leading whitespace */
line = line + strspn(line, " \t=");
@ -208,7 +214,8 @@ int read_config(char *file)
for (i = 0; keywords[i].keyword[0]; i++)
if (!strcasecmp(token, keywords[i].keyword))
if (!keywords[i].handler(line, keywords[i].var)) {
LOG(LOG_ERR, "unable to parse '%s'", orig);
LOG(LOG_ERR, "Failure parsing line %d of %s", lm, file);
DEBUG(LOG_ERR, "unable to parse '%s'", orig);
/* reset back to the default value */
keywords[i].handler(keywords[i].def, keywords[i].var);
}
@ -258,7 +265,7 @@ void write_leases(void)
}
void read_leases(char *file)
void read_leases(const char *file)
{
FILE *fp;
unsigned int i = 0;

10
files.h
View File

@ -3,15 +3,15 @@
#define _FILES_H
struct config_keyword {
char keyword[14];
int (*handler)(char *line, void *var);
const char *keyword;
int (* const handler)(const char *line, void *var);
void *var;
char def[30];
const char *def;
};
int read_config(char *file);
int read_config(const char *file);
void write_leases(void);
void read_leases(char *file);
void read_leases(const char *file);
#endif

View File

@ -9,12 +9,13 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include "debug.h"
#include "dhcpd.h"
#include "files.h"
#include "options.h"
#include "leases.h"
#include "arpping.h"
#include "common.h"
unsigned char blank_chaddr[] = {[0 ... 15] = 0};
@ -102,6 +103,21 @@ struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr)
}
/* check is an IP is taken, if it is, add it to the lease table */
static int check_ip(u_int32_t addr)
{
struct in_addr temp;
if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) {
temp.s_addr = addr;
LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds",
inet_ntoa(temp), server_config.conflict_time);
add_lease(blank_chaddr, addr, server_config.conflict_time);
return 1;
} else return 0;
}
/* find an assignable address, it check_expired is true, we check all the expired leases as well.
* Maybe this should try expired leases by age... */
u_int32_t find_address(int check_expired)
@ -133,19 +149,3 @@ u_int32_t find_address(int check_expired)
}
return 0;
}
/* check is an IP is taken, if it is, add it to the lease table */
int check_ip(u_int32_t addr)
{
struct in_addr temp;
if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) {
temp.s_addr = addr;
LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds",
inet_ntoa(temp), server_config.conflict_time);
add_lease(blank_chaddr, addr, server_config.conflict_time);
return 1;
} else return 0;
}

View File

@ -18,7 +18,6 @@ struct dhcpOfferedAddr *oldest_expired_lease(void);
struct dhcpOfferedAddr *find_lease_by_chaddr(u_int8_t *chaddr);
struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr);
u_int32_t find_address(int check_expired);
int check_ip(u_int32_t addr);
#endif

View File

@ -1,5 +1,13 @@
/* libbb_udhcp.h - busybox compatability wrapper */
/* bit of a hack, do this no matter what the order of the includes.
* (for busybox) */
#ifdef CONFIG_INSTALL_NO_USR
#undef DEFUALT_SCRIPT
#define DEFAULT_SCRIPT "/share/udhcpc/default.script"
#endif
#ifndef _LIBBB_UDHCP_H
#define _LIBBB_UDHCP_H
@ -7,22 +15,16 @@
#include "busybox.h"
#ifdef CONFIG_FEATURE_UDHCP_SYSLOG
#define SYSLOG
#define UDHCP_SYSLOG
#endif
#ifdef CONFIG_FEATURE_UDHCP_DEBUG
#define DEBUG
#define UDHCP_DEBUG
#endif
#define COMBINED_BINARY
#include "version.h"
#ifdef CONFIG_INSTALL_NO_USR
#define DEFAULT_SCRIPT "/share/udhcpc/default.script"
#else
#define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script"
#endif
#define xfopen bb_xfopen
#else /* ! BB_VER */
@ -36,8 +38,6 @@
#define xmalloc malloc
#define xcalloc calloc
#define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script"
static inline FILE *xfopen(const char *file, const char *mode)
{
FILE *fp;

View File

@ -3,19 +3,17 @@
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "dhcpd.h"
#include "files.h"
#include "options.h"
#include "leases.h"
#include "common.h"
/* supported options are easily added here */
struct dhcp_option options[] = {
struct dhcp_option dhcp_options[] = {
/* name[10] flags code */
{"subnet", OPTION_IP | OPTION_REQ, 0x01},
{"timezone", OPTION_S32, 0x02},
@ -160,9 +158,9 @@ int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t da
u16 = (u_int16_t *) &aligned;
u32 = &aligned;
for (i = 0; options[i].code; i++)
if (options[i].code == code) {
length = option_lengths[options[i].flags & TYPE_MASK];
for (i = 0; dhcp_options[i].code; i++)
if (dhcp_options[i].code == code) {
length = option_lengths[dhcp_options[i].flags & TYPE_MASK];
}
if (!length) {

View File

@ -27,7 +27,7 @@ struct dhcp_option {
unsigned char code;
};
extern struct dhcp_option options[];
extern struct dhcp_option dhcp_options[];
extern int option_lengths[];
unsigned char *get_option(struct dhcpMessage *packet, int code);

View File

@ -15,9 +15,9 @@
#include <errno.h>
#include "packet.h"
#include "debug.h"
#include "dhcpd.h"
#include "options.h"
#include "common.h"
void init_header(struct dhcpMessage *packet, char type)
@ -123,7 +123,7 @@ int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port
struct udp_dhcp_packet packet;
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
DEBUG(LOG_ERR, "socket call failed: %m");
return -1;
}
@ -136,7 +136,7 @@ int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port
dest.sll_halen = 6;
memcpy(dest.sll_addr, dest_arp, 6);
if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
DEBUG(LOG_ERR, "bind call failed: %m");
close(fd);
return -1;
}
@ -159,7 +159,7 @@ int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port
result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest));
if (result <= 0) {
DEBUG(LOG_ERR, "write on socket failed: %s", strerror(errno));
DEBUG(LOG_ERR, "write on socket failed: %m");
}
close(fd);
return result;
@ -200,4 +200,3 @@ int kernel_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_p
close(fd);
return result;
}

View File

@ -23,25 +23,35 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "debug.h"
#include "pidfile.h"
#include "common.h"
int pidfile_acquire(char *pidfile)
static char *saved_pidfile;
static void pidfile_delete(void)
{
if (saved_pidfile) unlink(saved_pidfile);
}
int pidfile_acquire(const char *pidfile)
{
int pid_fd;
if (pidfile == NULL) return -1;
if (!pidfile) return -1;
pid_fd = open(pidfile, O_CREAT | O_WRONLY, 0644);
if (pid_fd < 0) {
LOG(LOG_ERR, "Unable to open pidfile %s: %s\n",
pidfile, strerror(errno));
LOG(LOG_ERR, "Unable to open pidfile %s: %m\n", pidfile);
} else {
lockf(pid_fd, F_LOCK, 0);
if (!saved_pidfile)
atexit(pidfile_delete);
saved_pidfile = (char *) pidfile;
}
return pid_fd;
}
@ -61,9 +71,5 @@ void pidfile_write_release(int pid_fd)
}
void pidfile_delete(char *pidfile)
{
if (pidfile) unlink(pidfile);
}

View File

@ -20,7 +20,6 @@
*/
int pidfile_acquire(char *pidfile);
int pidfile_acquire(const char *pidfile);
void pidfile_write_release(int pid_fd);
void pidfile_delete(char *pidfile);

View File

@ -28,17 +28,14 @@
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include "options.h"
#include "dhcpd.h"
#include "dhcpc.h"
#include "packet.h"
#include "options.h"
#include "debug.h"
#include "common.h"
/* get a rough idea of how long an option will be (rounding up...) */
static int max_option_length[] = {
static const int max_option_length[] = {
[OPTION_IP] = sizeof("255.255.255.255 "),
[OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
[OPTION_STRING] = 1,
@ -51,10 +48,10 @@ static int max_option_length[] = {
};
static int upper_length(int length, struct dhcp_option *option)
static inline int upper_length(int length, int opt_index)
{
return max_option_length[option->flags & TYPE_MASK] *
(length / option_lengths[option->flags & TYPE_MASK]);
return max_option_length[opt_index] *
(length / option_lengths[opt_index]);
}
@ -135,20 +132,6 @@ static void fill_options(char *dest, unsigned char *option, struct dhcp_option *
}
static char *find_env(const char *prefix, char *defaultstr)
{
extern char **environ;
char **ptr;
const int len = strlen(prefix);
for (ptr = environ; *ptr != NULL; ptr++) {
if (strncmp(prefix, *ptr, len) == 0)
return *ptr;
}
return defaultstr;
}
/* put all the paramaters into an environment */
static char **fill_envp(struct dhcpMessage *packet)
{
@ -162,43 +145,40 @@ static char **fill_envp(struct dhcpMessage *packet)
if (packet == NULL)
num_options = 0;
else {
for (i = 0; options[i].code; i++)
if (get_option(packet, options[i].code))
for (i = 0; dhcp_options[i].code; i++)
if (get_option(packet, dhcp_options[i].code))
num_options++;
if (packet->siaddr) num_options++;
if ((temp = get_option(packet, DHCP_OPTION_OVER)))
over = *temp;
if (!(over & FILE_FIELD) && packet->file[0]) num_options++;
if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++;
if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++;
}
envp = xmalloc((num_options + 5) * sizeof(char *));
envp = xcalloc(sizeof(char *), num_options + 5);
j = 0;
envp[j++] = xmalloc(sizeof("interface=") + strlen(client_config.interface));
sprintf(envp[0], "interface=%s", client_config.interface);
envp[j++] = find_env("PATH", "PATH=/bin:/usr/bin:/sbin:/usr/sbin");
envp[j++] = find_env("HOME", "HOME=/");
asprintf(&envp[j++], "interface=%s", client_config.interface);
asprintf(&envp[j++], "%s=%s", "PATH",
getenv("PATH") ? : "/bin:/usr/bin:/sbin:/usr/sbin");
asprintf(&envp[j++], "%s=%s", "HOME", getenv("HOME") ? : "/");
if (packet == NULL) {
envp[j++] = NULL;
return envp;
}
if (packet == NULL) return envp;
envp[j] = xmalloc(sizeof("ip=255.255.255.255"));
sprintip(envp[j++], "ip=", (unsigned char *) &packet->yiaddr);
for (i = 0; options[i].code; i++) {
if (!(temp = get_option(packet, options[i].code)))
for (i = 0; dhcp_options[i].code; i++) {
if (!(temp = get_option(packet, dhcp_options[i].code)))
continue;
envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2], &options[i]) + strlen(options[i].name) + 2);
fill_options(envp[j++], temp, &options[i]);
envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2],
dhcp_options[i].flags & TYPE_MASK) + strlen(dhcp_options[i].name) + 2);
fill_options(envp[j++], temp, &dhcp_options[i]);
/* Fill in a subnet bits option for things like /24 */
if (options[i].code == DHCP_SUBNET) {
envp[j] = xmalloc(sizeof("mask=32"));
if (dhcp_options[i].code == DHCP_SUBNET) {
memcpy(&subnet, temp, 4);
sprintf(envp[j++], "mask=%d", mton(&subnet));
asprintf(&envp[j++], "mask=%d", mton(&subnet));
}
}
if (packet->siaddr) {
@ -208,16 +188,13 @@ static char **fill_envp(struct dhcpMessage *packet)
if (!(over & FILE_FIELD) && packet->file[0]) {
/* watch out for invalid packets */
packet->file[sizeof(packet->file) - 1] = '\0';
envp[j] = xmalloc(sizeof("boot_file=") + strlen(packet->file));
sprintf(envp[j++], "boot_file=%s", packet->file);
asprintf(&envp[j++], "boot_file=%s", packet->file);
}
if (!(over & SNAME_FIELD) && packet->sname[0]) {
/* watch out for invalid packets */
packet->sname[sizeof(packet->sname) - 1] = '\0';
envp[j] = xmalloc(sizeof("sname=") + strlen(packet->sname));
sprintf(envp[j++], "sname=%s", packet->sname);
asprintf(&envp[j++], "sname=%s", packet->sname);
}
envp[j] = NULL;
return envp;
}
@ -232,7 +209,7 @@ void run_script(struct dhcpMessage *packet, const char *name)
return;
/* call script */
pid = fork();
pid = vfork();
if (pid) {
waitpid(pid, NULL, 0);
return;
@ -242,11 +219,12 @@ void run_script(struct dhcpMessage *packet, const char *name)
/* close fd's? */
/* exec script */
#ifndef __uClinux__
DEBUG(LOG_INFO, "execle'ing %s", client_config.script);
#endif /* __uClinux__ */
execle(client_config.script, client_config.script,
name, NULL, envp);
LOG(LOG_ERR, "script %s failed: %s",
client_config.script, strerror(errno));
LOG(LOG_ERR, "script %s failed: %m", client_config.script);
exit(1);
}
}

View File

@ -25,11 +25,10 @@
#include <string.h>
#include <time.h>
#include "packet.h"
#include "debug.h"
#include "serverpacket.h"
#include "dhcpd.h"
#include "options.h"
#include "leases.h"
#include "common.h"
/* send a packet to giaddr using the kernel ip stack */
static int send_packet_to_relay(struct dhcpMessage *payload)
@ -258,6 +257,3 @@ int send_inform(struct dhcpMessage *oldpacket)
return send_packet(&packet, 0);
}

View File

@ -1,6 +1,7 @@
#ifndef _SERVERPACKET_H
#define _SERVERPACKET_H
#include "packet.h"
int sendOffer(struct dhcpMessage *oldpacket);
int sendNAK(struct dhcpMessage *oldpacket);

78
signalpipe.c Normal file
View File

@ -0,0 +1,78 @@
/* signalpipe.c
*
* Signal pipe infastructure. A reliable way of delivering signals.
*
* Russ Dill <Russ.Dill@asu.edu> Decemeber 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 <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include "signalpipe.h"
#include "common.h"
static int signal_pipe[2];
static void signal_handler(int sig)
{
if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0)
DEBUG(LOG_ERR, "Could not send signal: %m");
}
/* Call this before doing anything else. Sets up the socket pair
* and installs the signal handler */
void udhcp_sp_setup(void)
{
socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
signal(SIGUSR1, signal_handler);
signal(SIGUSR2, signal_handler);
signal(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[0], rfds);
if (extra_fd >= 0) FD_SET(extra_fd, rfds);
return signal_pipe[0] > extra_fd ? signal_pipe[0] : 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(fd_set *rfds)
{
int sig;
if (!FD_ISSET(signal_pipe[0], rfds))
return 0;
if (read(signal_pipe[0], &sig, sizeof(sig)) < 0)
return -1;
return sig;
}

22
signalpipe.h Normal file
View File

@ -0,0 +1,22 @@
/* signalpipe.h
*
* 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.
*/
void udhcp_sp_setup(void);
int udhcp_sp_fd_set(fd_set *rfds, int extra_fd);
int udhcp_sp_read(fd_set *rfds);

View File

@ -41,7 +41,8 @@
#include <linux/if_ether.h>
#endif
#include "debug.h"
#include "socket.h"
#include "common.h"
int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp)
{
@ -60,8 +61,7 @@ int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char
*addr = our_ip->sin_addr.s_addr;
DEBUG(LOG_INFO, "%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr));
} else {
LOG(LOG_ERR, "SIOCGIFADDR failed, is the interface up and configured?: %s",
strerror(errno));
LOG(LOG_ERR, "SIOCGIFADDR failed, is the interface up and configured?: %m");
return -1;
}
}
@ -70,7 +70,7 @@ int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char
DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex);
*ifindex = ifr.ifr_ifindex;
} else {
LOG(LOG_ERR, "SIOCGIFINDEX failed!: %s", strerror(errno));
LOG(LOG_ERR, "SIOCGIFINDEX failed!: %m");
return -1;
}
if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
@ -78,11 +78,11 @@ int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char
DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
} else {
LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %s", strerror(errno));
LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %m");
return -1;
}
} else {
LOG(LOG_ERR, "socket failed!: %s", strerror(errno));
LOG(LOG_ERR, "socket failed!: %m");
return -1;
}
close(fd);
@ -97,9 +97,9 @@ int listen_socket(unsigned int ip, int port, char *inf)
struct sockaddr_in addr;
int n = 1;
DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s\n", ip, port, inf);
DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s", ip, port, inf);
if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
DEBUG(LOG_ERR, "socket call failed: %m");
return -1;
}
@ -130,28 +130,3 @@ int listen_socket(unsigned int ip, int port, char *inf)
return fd;
}
int raw_socket(int ifindex)
{
int fd;
struct sockaddr_ll sock;
DEBUG(LOG_INFO, "Opening raw socket on ifindex %d\n", ifindex);
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
DEBUG(LOG_ERR, "socket call failed: %s", strerror(errno));
return -1;
}
sock.sll_family = AF_PACKET;
sock.sll_protocol = htons(ETH_P_IP);
sock.sll_ifindex = ifindex;
if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
DEBUG(LOG_ERR, "bind call failed: %s", strerror(errno));
close(fd);
return -1;
}
return fd;
}

View File

@ -4,6 +4,5 @@
int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp);
int listen_socket(unsigned int ip, int port, char *inf);
int raw_socket(int ifindex);
#endif