mirror of
https://git.busybox.net/udhcp
synced 2025-05-08 22:09:45 +08:00
updates for 0.9.4
This commit is contained in:
parent
94b1de2e09
commit
b29c784729
@ -1,5 +1,10 @@
|
||||
0.9.4 (pending)
|
||||
0.9.4 (010827)
|
||||
+ Force broadcast to broken clients that request unicast (ie, MSFT 98)
|
||||
+ Make install rules (Adam J. Richter <adam@yggdrasil.com>)
|
||||
+ One scripts, instead of many (Adam)
|
||||
+ Removed script paramater info files (env vars only) (Adam)
|
||||
+ Controlling of forking behavior in client (Adam)
|
||||
+ General script.c/dhcpc.c cleanups (Adam)
|
||||
|
||||
0.9.3 (010820)
|
||||
+ Increased debugging verbosity (me)
|
||||
|
36
Makefile
36
Makefile
@ -1,5 +1,11 @@
|
||||
# udhcp makefile
|
||||
|
||||
prefix=/usr
|
||||
SBINDIR=/sbin
|
||||
USRSBINDIR=${prefix}/sbin
|
||||
USRBINDIR=${prefix}/bin
|
||||
USRSHAREDIR=${prefix}/share
|
||||
|
||||
# Uncomment this to get a shared binary. Call as udhcpd for the server,
|
||||
# and udhcpc for the client
|
||||
#COMBINED_BINARY=1
|
||||
@ -8,13 +14,14 @@
|
||||
#DEBUG=1
|
||||
|
||||
# Uncomment this to output messages to syslog, otherwise, messages go to stdout
|
||||
#CFLAGS += -DSYSLOG
|
||||
CFLAGS += -DSYSLOG
|
||||
|
||||
#CROSS_COMPILE=arm-uclibc-
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
LD = $(CROSS_COMPILE)gcc
|
||||
INSTALL = install
|
||||
|
||||
VER := 0.9.3
|
||||
VER := 0.9.4
|
||||
|
||||
|
||||
OBJS_SHARED = options.o socket.o packet.o
|
||||
@ -36,6 +43,10 @@ endif
|
||||
EXEC3 = dumpleases
|
||||
OBJS3 = dumpleases.o
|
||||
|
||||
BOOT_PROGRAMS = udhcpc
|
||||
DAEMONS = udhcpd
|
||||
COMMANDS = dumpleases
|
||||
|
||||
ifdef SYSLOG
|
||||
CFLAGS += -DSYSLOG
|
||||
endif
|
||||
@ -46,10 +57,14 @@ ifdef DEBUG
|
||||
CFLAGS += -g -DDEBUG
|
||||
else
|
||||
CFLAGS += -Os -fomit-frame-pointer
|
||||
STRIP=-s
|
||||
endif
|
||||
|
||||
all: $(EXEC1) $(EXEC2) $(EXEC3)
|
||||
|
||||
$(OBJS1) $(OBJS2) $(OBJS3): *.h Makefile
|
||||
$(EXEC1) $(EXEC2) $(EXEC3): Makefile
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
@ -63,8 +78,21 @@ $(EXEC3): $(OBJS3)
|
||||
$(LD) $(LDFLAGS) $(OBJS3) -o $(EXEC3)
|
||||
|
||||
|
||||
install: all
|
||||
|
||||
$(INSTALL) $(STRIP) $(DAEMONS) $(USRSBINDIR)
|
||||
$(INSTALL) $(STRIP) $(COMMANDS) $(USRBINDIR)
|
||||
ifdef COMBINED_BINARY
|
||||
ln -sf $(USRSBINDIR)/$(DAEMONS) $(SBINDIR)/$(BOOT_PROGRAMS)
|
||||
else
|
||||
$(INSTALL) $(STRIP) $(BOOT_PROGRAMS) $(SBINDIR)
|
||||
endif
|
||||
mkdir -p $(USRSHAREDIR)/udhcpc
|
||||
for name in bound deconfig renew script ; do \
|
||||
$(INSTALL) samples/sample.$$name \
|
||||
$(USRSHAREDIR)/udhcpc/default.$$name ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
-rm -f udhcpd udhcpc dumpleases *.o core
|
||||
|
||||
$(OBJS1) $(OBJS2) $(OBJS3): *.h Makefile
|
||||
$(EXEC1) $(EXEC2) $(EXEC3): Makefile
|
48
README
48
README
@ -1,11 +1,14 @@
|
||||
Moreton Bay Server README
|
||||
udhcp server/client package readme
|
||||
-------------------------
|
||||
|
||||
The Moreton Bay DHCP Server is designed deliberately to be a small,
|
||||
lean, DHCP server. It does however, strive to be a fully functional,
|
||||
and compliant server.
|
||||
The udhcp server/client package is primarily geared towards embedded
|
||||
systems. It does however, strive to be fully functional, and RFC
|
||||
compliant.
|
||||
|
||||
The Moreton Bay DHCP Server employs a number of simple config files:
|
||||
udhcp server (udhcpd)
|
||||
--------------------
|
||||
|
||||
The udhcp server employs a number of simple config files:
|
||||
|
||||
udhcpd.leased
|
||||
------------
|
||||
@ -62,30 +65,30 @@ options for the udhcp client are:
|
||||
If the requested IP address cannot be obtained, the client accepts the
|
||||
address that the server offers.
|
||||
|
||||
When an event occurs, udhcpc calls one one of the scripts. The scripts
|
||||
aro by default contained in /etc/udhcpc/ but this can be changed via the
|
||||
command line arguments. The three scripts that are called are:
|
||||
When an event occurs, udhcpc calls the action script. The script by
|
||||
default is /usr/share/udhcpc/default.script but this can be changed via
|
||||
the command line arguments. The three possible arguments to the script
|
||||
are:
|
||||
|
||||
<prefix>deconfig: This script is called when udhcpc starts, and
|
||||
deconfig: This argument is used when udhcpc starts, and
|
||||
when a leases is lost. The script should put the interface in an
|
||||
up, but deconfigured state, ie: ifconfig $interface 0.0.0.0.
|
||||
|
||||
<prefix>bound: This script is called when udhcpc moves from an
|
||||
bound: This argument is used when udhcpc moves from an
|
||||
unbound, to a bound state. All of the paramaters are set in
|
||||
enviromental variables, as well as written to a file,
|
||||
<dir>/<prefix>info (ie, /etc/udhcpc/ext.info). This script should
|
||||
configure the interface, and set any other relavent parameter
|
||||
(default gateway, dns server, etc).
|
||||
enviromental variables, The script should configure the interface,
|
||||
and set any other relavent parameters (default gateway, dns server,
|
||||
etc).
|
||||
|
||||
<prefix>renew: This script is called when a DHCP lease is renewed.
|
||||
All of the paramaters are set in enviromental variables, as well
|
||||
as written to the info file. This is called when the interface is
|
||||
already configured, so the ip address will not change, however,
|
||||
the other DHCP paramaters, such as the default gateway, subnet mask,
|
||||
and dns server may change.
|
||||
renew: This argument is used when a DHCP lease is renewed. All of
|
||||
the paramaters are set in enviromental variables. This argument is
|
||||
used when the interface is already configured, so the IP address,
|
||||
will not change, however, the other DHCP paramaters, such as the
|
||||
default gateway, subnet mask, and dns server may change.
|
||||
|
||||
The paramaters for the config file and enviromental variables are as follows:
|
||||
The paramaters for enviromental variables are as follows:
|
||||
|
||||
$1 - What action the script should perform
|
||||
interface - The interface this was obtained on
|
||||
ip - The obtained IP
|
||||
subnet - The assigend subnet mask
|
||||
@ -144,6 +147,3 @@ dhcpd.h contains the other two compile time options:
|
||||
|
||||
|
||||
|
||||
Have fun!
|
||||
-Moreton Bay DHCP Server development team.
|
||||
|
||||
|
3
TODO
3
TODO
@ -1,11 +1,12 @@
|
||||
TODO
|
||||
----
|
||||
+ Make sure get_raw_packet only accepts packets on the specified interface
|
||||
+ FIXED: little/big endian issue probable cause for segmentation fault on i86 platform
|
||||
+ N/A: makeiplist basic functionality works.. more user friendly interface required
|
||||
+ REPLACED: browseiplist incomplete
|
||||
+ better standard linux distro support
|
||||
+ make config file a command line option
|
||||
+ make forking a command line option
|
||||
+ IMPLEMENTED: make forking a command line option
|
||||
+ make sure packet generation works on a wide varitey of arches
|
||||
+ Interoperability testing
|
||||
+ Hooks within the DHCP server
|
4
debug.h
4
debug.h
@ -8,7 +8,9 @@
|
||||
|
||||
|
||||
#ifdef SYSLOG
|
||||
# define LOG(level, str, args...) syslog(level, str, ## args)
|
||||
# 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
|
||||
|
213
dhcpc.c
213
dhcpc.c
@ -22,6 +22,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
@ -45,36 +46,55 @@
|
||||
#include "debug.h"
|
||||
|
||||
static int state;
|
||||
static unsigned long requested_ip = 0;
|
||||
static unsigned long requested_ip; /* = 0 */
|
||||
static unsigned long server_addr;
|
||||
static unsigned long timeout;
|
||||
static int packet_num = 0;
|
||||
static int packet_num; /* = 0 */
|
||||
static int pid_fd;
|
||||
|
||||
#define LISTEN_NONE 0
|
||||
#define LISTEN_KERNEL 1
|
||||
#define LISTEN_RAW 2
|
||||
static int listen_mode = LISTEN_RAW;
|
||||
|
||||
struct client_config_t client_config;
|
||||
#define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script"
|
||||
|
||||
struct client_config_t client_config = {
|
||||
/* Default options. */
|
||||
abort_if_no_lease: 0,
|
||||
foreground: 0,
|
||||
interface: "eth0",
|
||||
pidfile: NULL,
|
||||
script: DEFAULT_SCRIPT,
|
||||
clientid: NULL,
|
||||
hostname: NULL,
|
||||
ifindex: 0,
|
||||
arp: "\0\0\0\0\0\0", /* appease gcc-3.0 */
|
||||
};
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
printf("Usage: udhcpcd [OPTIONS]\n\n");
|
||||
printf(" -d, --dir=PATH Path containing DHCP client scripts (default: /etc/udhcpc/)\n");
|
||||
printf(" -p, --prefix=PREFIX Prefix to add to scripts (default: none)\n");
|
||||
printf(" -i, --interface=INTERFACE Interface to use (default: eth0)\n");
|
||||
printf(" -r, --request=IP IP address to request (default: none)\n");
|
||||
printf(" -c, --clientid=CLIENTID Client identifier\n");
|
||||
printf(" -H, --hostname=HOSTNAME Client hostname\n");
|
||||
printf(" -v, --version Display version\n");
|
||||
|
||||
printf(
|
||||
"Usage: udhcpcd [OPTIONS]\n\n"
|
||||
" -c, --clientid=CLIENTID Client identifier\n"
|
||||
" -H, --hostname=HOSTNAME Client hostname\n"
|
||||
" -f, --foreground Do not fork after getting lease\n"
|
||||
" -i, --interface=INTERFACE Interface to use (default: eth0)\n"
|
||||
" -n, --now Exit with failure if lease cannot be\n"
|
||||
" immediately negotiated.\n"
|
||||
" -p, --pidfile=file Store process ID of daemon in file\n"
|
||||
" -r, --request=IP IP address to request (default: none)\n"
|
||||
" -s, --script=file Run file at dhcp events (default:\n"
|
||||
" " DEFAULT_SCRIPT ")\n"
|
||||
" -v, --version Display version\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* SIGUSR1 handler (renew) */
|
||||
static void renew_requested(int pid)
|
||||
static void renew_requested(int sig)
|
||||
{
|
||||
pid = 0;
|
||||
sig = 0;
|
||||
LOG(LOG_INFO, "Received SIGUSR1");
|
||||
if (state == BOUND || state == RENEWING || state == REBINDING ||
|
||||
state == RELEASED) {
|
||||
@ -95,14 +115,14 @@ static void renew_requested(int pid)
|
||||
|
||||
|
||||
/* SIGUSR2 handler (release) */
|
||||
static void release_requested(int pid)
|
||||
static void release_requested(int sig)
|
||||
{
|
||||
pid = 0;
|
||||
sig = 0;
|
||||
LOG(LOG_INFO, "Received SIGUSR2");
|
||||
/* send release packet */
|
||||
if (state == BOUND || state == RENEWING || state == REBINDING) {
|
||||
send_release(server_addr, requested_ip); /* unicast */
|
||||
script_deconfig();
|
||||
run_script(NULL, "deconfig");
|
||||
}
|
||||
|
||||
listen_mode = 0;
|
||||
@ -110,6 +130,61 @@ static void release_requested(int pid)
|
||||
timeout = 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
static void pidfile_acquire(void)
|
||||
{
|
||||
if (client_config.pidfile == NULL) return;
|
||||
|
||||
pid_fd = open(client_config.pidfile, O_CREAT | O_WRONLY, 0644);
|
||||
if (pid_fd < 0) {
|
||||
LOG(LOG_ERR, "Unable to open pidfile %s: %s\n",
|
||||
client_config.pidfile, strerror(errno));
|
||||
} else {
|
||||
lockf(pid_fd, F_LOCK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void pidfile_write_release(void)
|
||||
{
|
||||
FILE *out;
|
||||
|
||||
if (client_config.pidfile == NULL || pid_fd < 0) return;
|
||||
|
||||
if ((out = fdopen(pid_fd, "w")) != NULL) {
|
||||
fprintf(out, "%d\n", getpid());
|
||||
fclose(out);
|
||||
}
|
||||
lockf(pid_fd, F_UNLCK, 0);
|
||||
close(pid_fd);
|
||||
}
|
||||
|
||||
|
||||
static void background(void)
|
||||
{
|
||||
if (!client_config.foreground) {
|
||||
pidfile_acquire(); /* hold lock during fork. */
|
||||
switch(fork()) {
|
||||
case -1:
|
||||
perror("fork");
|
||||
exit(1);
|
||||
/*NOTREACHED*/
|
||||
case 0:
|
||||
break; /* child continues */
|
||||
default:
|
||||
exit(0); /* parent exits */
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
setsid();
|
||||
client_config.foreground = 1; /* Do not fork again. */
|
||||
pidfile_write_release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef COMBINED_BINARY
|
||||
int udhcpc(int argc, char *argv[])
|
||||
#else
|
||||
@ -128,49 +203,26 @@ int main(int argc, char *argv[])
|
||||
struct in_addr temp_addr;
|
||||
|
||||
static struct option options[] = {
|
||||
{"dir", 1, 0, 'd'},
|
||||
{"prefix", 1, 0, 'p'},
|
||||
{"interface", 1, 0, 'i'},
|
||||
{"request", 1, 0, 'r'},
|
||||
{"clientid", 1, 0, 'c'},
|
||||
{"hostname", 1, 0, 'H'},
|
||||
{"version", 0, 0, 'v'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{"clientid", required_argument, 0, 'c'},
|
||||
{"foreground", no_argument, 0, 'f'},
|
||||
{"hostname", required_argument, 0, 'H'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"interface", required_argument, 0, 'i'},
|
||||
{"now", no_argument, 0, 'n'},
|
||||
{"pidfile", required_argument, 0, 'p'},
|
||||
{"request", required_argument, 0, 'r'},
|
||||
{"script", required_argument, 0, 's'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* default options */
|
||||
|
||||
client_config.dir = strdup("/etc/udhcpc/");
|
||||
client_config.prefix = strdup("");
|
||||
strcpy(client_config.interface, "eth0");
|
||||
client_config.clientid = NULL;
|
||||
|
||||
/* get options */
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
c = getopt_long(argc, argv, "d:p:i:r:c:H:vh", options, &option_index);
|
||||
c = getopt_long(argc, argv, "c:fH:hi:np:r:s:v", options, &option_index);
|
||||
if (c == -1) break;
|
||||
|
||||
switch (c) {
|
||||
case 'd':
|
||||
if (client_config.dir) free(client_config.dir);
|
||||
client_config.dir = malloc(strlen(optarg + 2));
|
||||
strcpy(client_config.dir, optarg);
|
||||
if (optarg[strlen(optarg) - 1] != '/')
|
||||
strcat(client_config.dir, "/");
|
||||
break;
|
||||
case 'p':
|
||||
if (client_config.prefix) free(client_config.prefix);
|
||||
client_config.prefix = strdup(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
strncpy(client_config.interface, optarg, 10);
|
||||
client_config.interface[9] = '\0';
|
||||
break;
|
||||
case 'r':
|
||||
requested_ip = inet_addr(optarg);
|
||||
break;
|
||||
case 'c':
|
||||
len = strlen(optarg) > 255 ? 255 : strlen(optarg);
|
||||
if (client_config.clientid) free(client_config.clientid);
|
||||
@ -179,6 +231,9 @@ int main(int argc, char *argv[])
|
||||
client_config.clientid[OPT_LEN] = len;
|
||||
strncpy(client_config.clientid + 2, optarg, len);
|
||||
break;
|
||||
case 'f':
|
||||
client_config.foreground = 1;
|
||||
break;
|
||||
case 'H':
|
||||
len = strlen(optarg) > 255 ? 255 : strlen(optarg);
|
||||
if (client_config.hostname) free(client_config.hostname);
|
||||
@ -187,14 +242,36 @@ int main(int argc, char *argv[])
|
||||
client_config.hostname[OPT_LEN] = len;
|
||||
strncpy(client_config.hostname + 2, optarg, len);
|
||||
break;
|
||||
case 'v': printf("udhcpcd, version %s\n\n", VERSION); break;
|
||||
case 'h': print_usage(); return 0;
|
||||
case 'h':
|
||||
print_usage();
|
||||
return 0;
|
||||
case 'i':
|
||||
client_config.interface = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
client_config.abort_if_no_lease = 1;
|
||||
break;
|
||||
case 'p':
|
||||
client_config.pidfile = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
requested_ip = inet_addr(optarg);
|
||||
break;
|
||||
case 's':
|
||||
client_config.script = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
printf("udhcpcd, version %s\n\n", VERSION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OPEN_LOG("udhcpc");
|
||||
LOG(LOG_INFO, "Moreton Bay DHCP Client (v%s) started", VERSION);
|
||||
|
||||
|
||||
pidfile_acquire();
|
||||
pidfile_write_release();
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) {
|
||||
strcpy(ifr.ifr_name, client_config.interface);
|
||||
if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
|
||||
@ -225,15 +302,7 @@ int main(int argc, char *argv[])
|
||||
signal(SIGUSR2, release_requested);
|
||||
|
||||
state = INIT_SELECTING;
|
||||
script_deconfig();
|
||||
|
||||
#ifndef DEBUGGING
|
||||
if (fork()) return 0;
|
||||
else {
|
||||
close(0);
|
||||
setsid();
|
||||
}
|
||||
#endif
|
||||
run_script(NULL, "deconfig");
|
||||
|
||||
for (;;) {
|
||||
if (fd > 0) {
|
||||
@ -276,6 +345,11 @@ int main(int argc, char *argv[])
|
||||
timeout = time(0) + ((packet_num == 2) ? 10 : 2);
|
||||
packet_num++;
|
||||
} else {
|
||||
if (client_config.abort_if_no_lease) {
|
||||
LOG(LOG_INFO,
|
||||
"No lease, failing.");
|
||||
exit(1);
|
||||
}
|
||||
/* wait to try again */
|
||||
packet_num = 0;
|
||||
timeout = time(0) + 60;
|
||||
@ -327,7 +401,7 @@ int main(int argc, char *argv[])
|
||||
/* timed out, enter init state */
|
||||
state = INIT_SELECTING;
|
||||
LOG(LOG_INFO, "Lease lost, entering init state");
|
||||
script_deconfig();
|
||||
run_script(NULL, "deconfig");
|
||||
timeout = time(0);
|
||||
packet_num = 0;
|
||||
listen_mode = LISTEN_RAW;
|
||||
@ -406,17 +480,18 @@ int main(int argc, char *argv[])
|
||||
start = time(0);
|
||||
timeout = t1 + start;
|
||||
requested_ip = packet.yiaddr;
|
||||
if (state == RENEWING || state == REBINDING)
|
||||
script_renew(&packet);
|
||||
else script_bound(&packet);
|
||||
run_script(&packet,
|
||||
((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
|
||||
|
||||
state = BOUND;
|
||||
listen_mode = LISTEN_NONE;
|
||||
background();
|
||||
|
||||
} else if (*message == DHCPNAK) {
|
||||
/* return to init state */
|
||||
LOG(LOG_INFO, "Received DHCP NAK");
|
||||
if (state != REQUESTING) script_deconfig();
|
||||
if (state != REQUESTING)
|
||||
run_script(NULL, "deconfig");
|
||||
state = INIT_SELECTING;
|
||||
timeout = time(0);
|
||||
requested_ip = 0;
|
||||
|
8
dhcpc.h
8
dhcpc.h
@ -24,9 +24,11 @@
|
||||
|
||||
|
||||
struct client_config_t {
|
||||
char *dir; /* Path containing DHCP client scripts */
|
||||
char *prefix; /* Prefix to add to scripts */
|
||||
char interface[10]; /* The name of the interface to use */
|
||||
char foreground; /* Do not fork */
|
||||
char abort_if_no_lease; /* Abort if no lease */
|
||||
char *interface; /* The name of the interface to use */
|
||||
char *pidfile; /* Optionally store the process ID */
|
||||
char *script; /* User script to run at dhcp events */
|
||||
char *clientid; /* Optional client id to use */
|
||||
char *hostname; /* Optional hostname to use */
|
||||
int ifindex; /* Index number of the interface to use */
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "dhcpd.h"
|
||||
|
23
options.h
23
options.h
@ -5,15 +5,18 @@
|
||||
#include "packet.h"
|
||||
|
||||
#define TYPE_MASK 0x0F
|
||||
#define OPTION_IP 0x01
|
||||
#define OPTION_IP_PAIR 0x02
|
||||
#define OPTION_STRING 0x03
|
||||
#define OPTION_BOOLEAN 0x04
|
||||
#define OPTION_U8 0x05
|
||||
#define OPTION_U16 0x06
|
||||
#define OPTION_S16 0x07
|
||||
#define OPTION_U32 0x08
|
||||
#define OPTION_S32 0x09
|
||||
|
||||
enum {
|
||||
OPTION_IP=1,
|
||||
OPTION_IP_PAIR,
|
||||
OPTION_STRING,
|
||||
OPTION_BOOLEAN,
|
||||
OPTION_U8,
|
||||
OPTION_U16,
|
||||
OPTION_S16,
|
||||
OPTION_U32,
|
||||
OPTION_S32
|
||||
};
|
||||
|
||||
#define OPTION_LIST 0x80
|
||||
|
||||
@ -33,4 +36,4 @@ int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t da
|
||||
struct option_set *find_option(struct option_set *opt_list, char code);
|
||||
void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -2,10 +2,8 @@ The files in this dir are:
|
||||
|
||||
udhcpd.conf: A sample udhpcd configuration file.
|
||||
|
||||
sample.script
|
||||
sample.deconfig
|
||||
sample.bound
|
||||
sample.renew : sample scripts for the udhcpc client, to use
|
||||
them, invoke udhcpc with: "udhcpc -p sample."
|
||||
and copy the files to /etc/udhcpc/
|
||||
|
||||
sample.info: A sample paramater file generated by udhcpc
|
||||
sample.renew : sample scripts for the udhcpc client.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Sample udhcpc renew script
|
||||
|
||||
RESOLV_CONF="/etc/udhcpc/resolv.conf"
|
||||
RESOLV_CONF="/etc/resolv.conf"
|
||||
|
||||
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
|
||||
[ -n "$subnet" ] && NETMASK="netmask $subnet"
|
||||
|
@ -1,9 +0,0 @@
|
||||
interface eth0
|
||||
ip 192.168.10.22
|
||||
subnet 255.255.255.0
|
||||
router 192.168.10.2
|
||||
dns 192.168.10.2 192.168.10.10
|
||||
wins 192.168.10.10
|
||||
lease 36000
|
||||
dhcptype 5
|
||||
serverid 192.168.10.11
|
7
samples/sample.script
Normal file
7
samples/sample.script
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Currently, we only dispatch according to command. However, a more
|
||||
# elaborate system might dispatch by command and interface or do some
|
||||
# common initialization first, especially if more dhcp event notifications
|
||||
# are added.
|
||||
|
||||
exec /usr/share/udhcpc/default.$1
|
224
script.c
224
script.c
@ -45,28 +45,28 @@ static int max_option_length(char *option, struct dhcp_option *type)
|
||||
switch (type->flags & TYPE_MASK) {
|
||||
case OPTION_IP:
|
||||
case OPTION_IP_PAIR:
|
||||
size = (option[OPT_LEN - 2] / 4) * strlen("255.255.255.255 ");
|
||||
size = (option[OPT_LEN - 2] / 4) * sizeof("255.255.255.255 ");
|
||||
break;
|
||||
case OPTION_STRING:
|
||||
size = option[OPT_LEN - 2] + 1;
|
||||
break;
|
||||
case OPTION_BOOLEAN:
|
||||
size = option[OPT_LEN - 2] * strlen("yes ");
|
||||
size = option[OPT_LEN - 2] * sizeof("yes ");
|
||||
break;
|
||||
case OPTION_U8:
|
||||
size = option[OPT_LEN - 2] * strlen("255 ");
|
||||
size = option[OPT_LEN - 2] * sizeof("255 ");
|
||||
break;
|
||||
case OPTION_U16:
|
||||
size = (option[OPT_LEN - 2] / 2) * strlen("65535 ");
|
||||
size = (option[OPT_LEN - 2] / 2) * sizeof("65535 ");
|
||||
break;
|
||||
case OPTION_S16:
|
||||
size = (option[OPT_LEN - 2] / 2) * strlen("-32768 ");
|
||||
size = (option[OPT_LEN - 2] / 2) * sizeof("-32768 ");
|
||||
break;
|
||||
case OPTION_U32:
|
||||
size = (option[OPT_LEN - 2] / 4) * strlen("4294967295 ");
|
||||
size = (option[OPT_LEN - 2] / 4) * sizeof("4294967295 ");
|
||||
break;
|
||||
case OPTION_S32:
|
||||
size = (option[OPT_LEN - 2] / 4) * strlen("-2147483684 ");
|
||||
size = (option[OPT_LEN - 2] / 4) * sizeof("-2147483684 ");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -74,126 +74,105 @@ static int max_option_length(char *option, struct dhcp_option *type)
|
||||
}
|
||||
|
||||
|
||||
/* Fill dest with the text of option 'option' */
|
||||
static void fill_options(char *dest, char *option, struct dhcp_option *type)
|
||||
/* Fill dest with the text of option 'option'. */
|
||||
static void fill_options(char *dest, unsigned char *option, struct dhcp_option *type_p)
|
||||
{
|
||||
int pos;
|
||||
int type, optlen;
|
||||
u_int16_t val_u16;
|
||||
int16_t val_s16;
|
||||
u_int32_t val_u32;
|
||||
int32_t val_s32;
|
||||
struct in_addr in;
|
||||
|
||||
if ((type->flags & TYPE_MASK) == OPTION_STRING) {
|
||||
strncpy(dest, option, option[OPT_LEN - 2]);
|
||||
dest[(int) option[OPT_LEN - 2]] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
dest[0] = '\0';
|
||||
|
||||
for (pos = 0; pos < option[OPT_LEN - 2]; pos += option_lengths[type->flags & TYPE_MASK]) {
|
||||
if (pos) strcat(dest, " ");
|
||||
switch (type->flags & TYPE_MASK) {
|
||||
case OPTION_IP:
|
||||
memcpy(&in.s_addr, option + pos, 4);
|
||||
strcat(dest, inet_ntoa(in));
|
||||
break;
|
||||
int len = option[OPT_LEN - 2];
|
||||
|
||||
dest += sprintf(dest, "%s=", type_p->name);
|
||||
|
||||
type = type_p->flags & TYPE_MASK;
|
||||
optlen = option_lengths[type];
|
||||
for(;;) {
|
||||
switch (type) {
|
||||
case OPTION_IP: /* Works regardless of host byte order. */
|
||||
dest += sprintf(dest, "%d.%d.%d.%d",
|
||||
option[0], option[1],
|
||||
option[2], option[3]);
|
||||
break;
|
||||
case OPTION_IP_PAIR:
|
||||
memcpy(&in.s_addr, option + pos, 4);
|
||||
strcat(dest, inet_ntoa(in));
|
||||
memcpy(&in.s_addr, option + pos + 4, 4);
|
||||
strcat(dest, inet_ntoa(in));
|
||||
dest += sprintf(dest, "%d.%d.%d.%d, %d.%d.%d.%d",
|
||||
option[0], option[1],
|
||||
option[2], option[3],
|
||||
option[4], option[5],
|
||||
option[6], option[7]);
|
||||
break;
|
||||
case OPTION_BOOLEAN:
|
||||
strcat(dest, option[pos] ? "yes" : "no");
|
||||
dest += sprintf(dest, *option ? "yes" : "no");
|
||||
break;
|
||||
case OPTION_U8:
|
||||
sprintf(dest + strlen(dest), "%u", option[pos]);
|
||||
dest += sprintf(dest, "%u", *option);
|
||||
break;
|
||||
case OPTION_U16:
|
||||
memcpy(&val_u16, option + pos, 2);
|
||||
sprintf(dest + strlen(dest), "%u", ntohs(val_u16));
|
||||
memcpy(&val_u16, option, 2);
|
||||
dest += sprintf(dest, "%u", ntohs(val_u16));
|
||||
break;
|
||||
case OPTION_S16:
|
||||
memcpy(&val_s16, option + pos, 2);
|
||||
sprintf(dest + strlen(dest), "%d", ntohs(val_s16));
|
||||
memcpy(&val_s16, option, 2);
|
||||
dest += sprintf(dest, "%d", ntohs(val_s16));
|
||||
break;
|
||||
case OPTION_U32:
|
||||
memcpy(&val_u32, option + pos, 4);
|
||||
sprintf(dest + strlen(dest), "%lu", (unsigned long) ntohl(val_u32));
|
||||
memcpy(&val_u32, option, 4);
|
||||
dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32));
|
||||
break;
|
||||
case OPTION_S32:
|
||||
memcpy(&val_s32, option + pos, 4);
|
||||
sprintf(dest + strlen(dest), "%ld", (long) ntohl(val_s32));
|
||||
memcpy(&val_s32, option, 4);
|
||||
dest += sprintf(dest, "%ld", (long) ntohl(val_s32));
|
||||
break;
|
||||
case OPTION_STRING:
|
||||
memcpy(dest, option, len);
|
||||
dest[len] = '\0';
|
||||
return; /* Short circuit this case */
|
||||
}
|
||||
option += optlen;
|
||||
len -= optlen;
|
||||
if (len <= 0) break;
|
||||
*(dest++) = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* write out the paramaters to a file */
|
||||
static void write_pars(struct dhcpMessage *packet)
|
||||
{
|
||||
char file[strlen(client_config.dir) +
|
||||
(client_config.prefix ? strlen(client_config.prefix) : 0) +
|
||||
strlen("info") + 1];
|
||||
|
||||
int i;
|
||||
char *temp, *buff;
|
||||
FILE *fp;
|
||||
struct in_addr addr;
|
||||
|
||||
strcpy(file, client_config.dir);
|
||||
if (client_config.prefix) strcat(file, client_config.prefix);
|
||||
strcat(file, "info");
|
||||
|
||||
if (!(fp = fopen(file, "w"))) {
|
||||
LOG(LOG_ERR, "Could not open %s for writing", file);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "interface %s\n", client_config.interface);
|
||||
addr.s_addr = packet->yiaddr;
|
||||
fprintf(fp, "ip %s\n", inet_ntoa(addr));
|
||||
for (i = 0; options[i].code; i++) {
|
||||
if ((temp = get_option(packet, options[i].code))) {
|
||||
buff = malloc(max_option_length(temp, &options[i]));
|
||||
fill_options(buff, temp, &options[i]);
|
||||
fprintf(fp, "%s %s\n", options[i].name, buff);
|
||||
free(buff);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
|
||||
/* put all the paramaters into an environment */
|
||||
static char **fill_envp(struct dhcpMessage *packet)
|
||||
{
|
||||
int num_options = 0;
|
||||
int i, j;
|
||||
struct in_addr addr;
|
||||
unsigned char *addr;
|
||||
char **envp, *temp;
|
||||
|
||||
for (i = 0; options[i].code; i++)
|
||||
if (get_option(packet, options[i].code))
|
||||
num_options++;
|
||||
if (packet == NULL)
|
||||
num_options = 0;
|
||||
else {
|
||||
for (i = 0; options[i].code; i++)
|
||||
if (get_option(packet, options[i].code))
|
||||
num_options++;
|
||||
}
|
||||
|
||||
envp = malloc((num_options + 3) * sizeof(char *));
|
||||
envp = malloc((num_options + 5) * sizeof(char *));
|
||||
envp[0] = malloc(strlen("interface=") + strlen(client_config.interface) + 1);
|
||||
sprintf(envp[0], "interface=%s", client_config.interface);
|
||||
addr.s_addr = packet->yiaddr;
|
||||
envp[1] = malloc(strlen("ip=255.255.255.255"));
|
||||
sprintf(envp[1], "ip=%s", inet_ntoa(addr));
|
||||
for (i = 0, j = 2; options[i].code; i++) {
|
||||
envp[2] = getenv("PATH") ? getenv("PATH") : "PATH=/bin:/usr/bin:/sbin:/usr/sbin";
|
||||
envp[3] = getenv("HOME") ? getenv("HOME") : "HOME=/";
|
||||
|
||||
if (packet == NULL) {
|
||||
envp[4] = NULL;
|
||||
return envp;
|
||||
}
|
||||
|
||||
addr = (unsigned char*) &packet->yiaddr;
|
||||
sprintf (envp[1], "ip=%d.%d.%d.%d",
|
||||
addr[0], addr[1], addr[2], addr[3]);
|
||||
for (i = 0, j = 4; options[i].code; i++) {
|
||||
if ((temp = get_option(packet, options[i].code))) {
|
||||
envp[j] = malloc(max_option_length(temp, &options[i]) +
|
||||
strlen(options[i].name + 1));
|
||||
strcpy(envp[j], options[i].name);
|
||||
strcat(envp[j], "=");
|
||||
fill_options(envp[j] + strlen(envp[j]), temp, &options[i]);
|
||||
strlen(options[i].name) + 2);
|
||||
fill_options(envp[j], temp, &options[i]);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
@ -202,47 +181,17 @@ static char **fill_envp(struct dhcpMessage *packet)
|
||||
}
|
||||
|
||||
|
||||
/* Call the deconfic script */
|
||||
void script_deconfig(void)
|
||||
{
|
||||
int pid;
|
||||
char **envp;
|
||||
char file[255 + 5];
|
||||
|
||||
/* call script */
|
||||
pid = fork();
|
||||
if (pid) {
|
||||
waitpid(pid, NULL, 0);
|
||||
return;
|
||||
} else if (pid == 0) {
|
||||
envp = malloc(sizeof(char *) * 2);
|
||||
envp[0] = malloc(strlen("interface=") + strlen(client_config.interface) + 1);
|
||||
sprintf(envp[0], "interface=%s", client_config.interface);
|
||||
envp[1] = NULL;
|
||||
|
||||
/* close fd's? */
|
||||
|
||||
/* exec script */
|
||||
sprintf(file, "%s%sdeconfig", client_config.dir, client_config.prefix);
|
||||
DEBUG(LOG_INFO, "execle'ing %s", file);
|
||||
execle(file, "deconfig", NULL, envp);
|
||||
LOG(LOG_ERR, "script %s failed: %s", file, sys_errlist[errno]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Call a script with a par file and env vars */
|
||||
static void par_script(struct dhcpMessage *packet, char *name)
|
||||
void run_script(struct dhcpMessage *packet, const char *name)
|
||||
{
|
||||
int pid;
|
||||
char **envp;
|
||||
char file[255 + 5];
|
||||
|
||||
write_pars(packet);
|
||||
if (client_config.script == NULL)
|
||||
return;
|
||||
|
||||
/* call script */
|
||||
pid = fork();
|
||||
pid = fork();
|
||||
if (pid) {
|
||||
waitpid(pid, NULL, 0);
|
||||
return;
|
||||
@ -252,26 +201,11 @@ static void par_script(struct dhcpMessage *packet, char *name)
|
||||
/* close fd's? */
|
||||
|
||||
/* exec script */
|
||||
sprintf(file, "%s%s%s", client_config.dir, client_config.prefix, name);
|
||||
DEBUG(LOG_INFO, "execle'ing %s", file);
|
||||
execle(file, name, NULL, envp);
|
||||
LOG(LOG_ERR, "script %s failed: %s", file, sys_errlist[errno]);
|
||||
exit(0);
|
||||
DEBUG(LOG_INFO, "execle'ing %s", client_config.script);
|
||||
execle(client_config.script, client_config.script,
|
||||
name, NULL, envp);
|
||||
LOG(LOG_ERR, "script %s failed: %s",
|
||||
client_config.script, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* call the renew script */
|
||||
void script_renew(struct dhcpMessage *packet)
|
||||
{
|
||||
par_script(packet, "renew");
|
||||
}
|
||||
|
||||
|
||||
/* call the bound script */
|
||||
void script_bound(struct dhcpMessage *packet)
|
||||
{
|
||||
par_script(packet, "bound");
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user