Import of rewrite to 0.9.0

This commit is contained in:
Russ Dill 2001-07-21 00:46:19 +00:00
parent 9e89798760
commit 815b41096f
28 changed files with 1618 additions and 1318 deletions

11
AUTHORS
View File

@ -1,10 +1,9 @@
NETtel DHCP Server Authors
--------------------------
Matthew Ramsay <matthewr@moreton.com.au> (Moreton Bay)
Chris Trew <christ@moreton.com.au> (Moreton Bay)
Moreton Bay DHCP Server
-----------------------
Matthew Ramsay <matthewr@moreton.com.au>
Chris Trew <christ@moreton.com.au>
Russ Dill <Russ.Dill@asu.edu>
Other Credits:
--------------

View File

@ -1,6 +1,21 @@
0.9.0 (010720) Major rewrite, current changes, goals:
+ should not segfault on bogus packets.
+ Options can be read from sname and file fields.
+ supports all DHCP messages (release, decline, inform).
+ IP block is now specified by a range of IP's.
+ Leases file now contains lease time (relative, or absolute).
+ Just about any DHCP option is now supported.
+ DNS entries are no longer read from resolv.conf
+ Lease file can be written periodically when the process receives a SIGUSR1
+ arpping should be supported on all arches.
+ support for DHCP relays.
+ DHCP messages can be unicast if the client requests it.
+ many, many, many other things.
0.8.29 (000323)
+ stable(?) release
0.8.28 (000323)
+ removed alarm as it was causing server to go down
+ removed debugging

View File

@ -1,22 +1,39 @@
EXEC1 = udhcpd
OBJS1 = dhcpd.o arpping.o files.o leases.o options.o socket.o
EXEC = dhcpd
OBJS = dhcpd.o arpping.o socket.o options.o files.o debug.o nettel.o
EXEC2 = dumpleases
OBJS2 = dumpleases.o
ifdef BUILD_NETtel
CFLAGS += -DCONFIG_NETtel
endif
ifdef BUILD_NETtel1500
CFLAGS += -DCONFIG_NETtel
DEBUG=1
#CFLAGS += -DSYSLOG
VER := 0.9.0
CROSS_COMPILE=arm-uclibc-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)gcc
CFLAGS += -W -Wall -Wstrict-prototypes -DVERSION='"$(VER)"'
ifdef DEBUG
CFLAGS += -g -DDEBUG
else
CFLAGS += -Os -fomit-frame-pointer
endif
all: $(EXEC)
all: $(EXEC1) $(EXEC2) $(EXEC3)
.c.o:
$(CC) -c $(CFLAGS) $<
$(EXEC1): $(OBJS1)
$(LD) $(LDFLAGS) $(OBJS1) -o $(EXEC1)
$(EXEC2): $(OBJS2)
$(LD) $(LDFLAGS) $(OBJS2) -o $(EXEC2)
$(EXEC): $(OBJS)
$(LD) $(LDFLAGS) -o $@.elf $(OBJS) $(LDLIBS)
$(CONVERT)
clean:
-rm -f $(EXEC) *.elf *.gdb *.o
$(OBJS): dhcpd.h socket.h options.h files.h debug.h nettel.h
-rm -f $(EXEC1) $(EXEC2) *.elf *.o core
$(OBJS1): files.h debug.h options.h socket.h leases.h dhcpd.h arpping.h

View File

@ -1,31 +0,0 @@
EXEC1 = dhcpd
OBJS1 = dhcpd.o arpping.o
EXEC2 = tools/makeiplist
OBJS2 = tools/makeiplist.o
EXEC3 = tools/browseiplist
OBJS3 = tools/browseiplist.o
all: $(EXEC1) $(EXEC2) $(EXEC3)
$(EXEC1): $(OBJS1)
gcc $(OBJS1) -o $(EXEC1)
$(EXEC2): $(OBJS2)
gcc $(OBJS2) -o $(EXEC2)
$(EXEC3): $(OBJS3)
gcc $(OBJS3) -o $(EXEC3)
clean:
-rm -f $(EXEC1) $(EXEC2) $(EXEC3) *.elf *.o core
$(OBJS1): dhcpd.h arpping.h
$(OBJS2):
$(OBJS3):

View File

@ -1,15 +0,0 @@
EXEC = dhcpd
OBJS = dhcpd.o arpping.o
all: $(EXEC)
$(EXEC): $(OBJS)
$(LD) $(LDFLAGS) -o $@.elf $(OBJS) $(LDLIBS)
$(CONVERT)
clean:
-rm -f $(EXEC) *.elf *.o
$(OBJS): dhcpd.h

102
README
View File

@ -1,79 +1,67 @@
NETtel DHCP Server README
Moreton Bay Server README
-------------------------
The NETtel DHCP Server is designed to run on a NETtel (which
runs on Greg Ungerer's uClinux-coldfire kernel) but will easily
run on normal Linux distributions for PCs.
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 NETtel DHCP Server is designed deliberately to be a small,
lean, DHCP server. It does not implement the entire protocol
but only what is necessary to serve the following:
The Moreton Bay DHCP Server employs a number of simple config files:
IP address (and its subnet)
Gateway address
DNS Server address
WINS (NetBIOS Name Server)
The lease times are hard coded to 10 days (from memory :-)
The NETtel DHCP Server employs a number of simple config files:
dhcpd.iplist
udhcpd.leased
------------
Binary list of ip addresses that the server may offer. This list may
include ip addresses already leased out.
dhcpd.leased
------------
Binary list of leased ip addresses and their respective MAC address.
format:
The udhcpd.leases behavior is designed for an embedded system. The
file is written either every auto_time seconds, or when a SIGUSR1
is received. When the file is written, a script can be optionally
called to commit the file to flash. Lease times are stored in the
file by time remaining in lease (for systems without clock that works
when there is no power), or by the absolute time that it expires in
seconds from epoch. In the remainig format, expired leases are stored
as zero. The file is of the format:
16 byte MAC
8 byte ip address
4 byte ip address
u32 expire time
16 byte MAC
8 byte ip address
4 byte ip address
u32 expire time
.
etc.
example: hexdump dhcpd.leases
example: hexdump udhcpd.leases
0: 00 AB 00 00 00 00 00 00-00 FF 00 00 00 00 00 01 ................
10: CB 18 97 78 00 BB 00 00-00 00 00 00 00 AA 00 00 ...x............
20: 00 00 00 CC CB 18 97 79-00 80 5F 94 28 2A 00 00 .......y.._.(*..
30: 00 00 00 00 00 00 00 00-CB 18 97 7A ...........z
0000000 1000 c95a 27d9 0000 0000 0000 0000 0000
0000010 a8c0 150a 0d00 2d29 5000 23fc 8566 0000
0000020 0000 0000 0000 0000 a8c0 140a 0d00 4e29
0000030
dhcpd.conf
udhcpd.conf
----------
/etc/config> cat dhcpd.conf
subnet 255.255.255.0
router 203.24.151.121
wins 203.50.0.24
/etc/config>
---
DNS is grabbed from resolv.conf:
nameserver x.x.x.x
nameserver y.y.y.y
nameserver z.z.z.z
Up to 3 DNS servers are supported.
---
Q&A
Q. Isn't this all very complicated for a lease/ip pool?
A. yes.. but it saves space :-)
The format is fairly simple, there is a sample file with all the
available options and comments describing them in samples/udhcpd.conf
compile time options
-------------------
The Makefile contains two 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.
dhcpd.h contains the other two compile time options:
LEASE_TIME: The default lease time if not specified in the config
file.
DHCPD_CONFIG_FILE: What config file to use.
Have fun!
-Moreton Bay DHCP Server development team.

12
TODO
View File

@ -1,9 +1,9 @@
TODO
----
+ if the number of simultaneous clients reaches MAX_SIMUL_CLIENTS the offer_num
count will reset and previously OFFERed clients may be temporarily NAKed
until the count stabalises
+ little/big endian issue probable cause for segmentation fault on i86 platform
+ makeiplist basic functionality works.. more user friendly interface required
+ browseiplist incomplete
+ 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
+ make sure packet generation works on a wide varitey of arches

120
arpping.c
View File

@ -5,11 +5,23 @@
* 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"
#define DEBUG 0
/* local prototypes */
int arpCheck(u_long inaddr, struct ifinfo *ifbuf, long timeout);
@ -23,66 +35,17 @@ int openRawSocket (int *s, u_short type);
* -1 error
*/
int arpping(u_int32_t yiaddr) {
int rv;
struct ifinfo ifbuf;
int n;
static int nr = 0;
unsigned char *ep;
/*unsigned char ep[6] = {0x00,0xd0,0xcf,0x00,0x01,0x0f};*/
/*
u_int32_t yiaddr = 0xcb189701;
u_int32_t yiaddr = 0xcb189778;
*/
strcpy(ifbuf.ifname, "eth0");
ifbuf.addr = 0xcb1897aa; /* this addr appears to be irrelevant */
/* ifbuf.mask = 0xffffff00;
ifbuf.bcast = 0xcb1897ff; */
strcpy(ifbuf.ifname, config.interface);
ifbuf.addr = config.server;
ifbuf.mask = 0x0;
ifbuf.bcast = 0x0;
#if CONFIG_NETtel
/* rip the HW addr out of the flash :-)
* points to the memory where hwaddr is located */
ep = (unsigned char *) (0xf0006000);/* + (nr++ * 6));*/
#if 0
if ((ep[0] == 0xff) && (ep[1] == 0xff) && (ep[2] == 0xff) &&
(ep[3] == 0xff) && (ep[4] == 0xff) && (ep[5] == 0xff)) {
#if DEBUG
syslog(LOG_INFO, "DHCPD - oops! bad hwaddr (0xff)");
#endif
return -1;
} else if ((ep[0] == 0) && (ep[1] == 0) && (ep[2] == 0) &&
(ep[3] == 0) && (ep[4] == 0) && (ep[5] == 0)) {
#if DEBUG
syslog(LOG_INFO, "DHCPD - oops! bad hwaddr (0x00)");
#endif
return -1;
}
#endif
#endif
#if 0
printf("arpping hwaddr: ");
#endif
for(n=0;n<6;n++) {
#if 0
printf("%02x", ep[n]);
#endif
ifbuf.haddr[n] = ep[n];
}
#if 0
printf("\n");
#endif
memcpy(ifbuf.haddr, config.arp, 6);
ifbuf.flags = 0;
rv = arpCheck(yiaddr, &ifbuf, 3);
#if 0
printf("rv = %d (1=free, 0=used)\n", rv);
#endif
return rv;
return arpCheck(yiaddr, &ifbuf, 2);
}
@ -102,12 +65,7 @@ int arpCheck(u_long inaddr, struct ifinfo *ifbuf, long timeout) {
mkArpMsg(ARPOP_REQUEST, inaddr, NULL, ifbuf->addr, ifbuf->haddr, &arp);
bzero(&addr, sizeof(addr));
strcpy(addr.sa_data, ifbuf->ifname);
if ( sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0 ) {
#if 0
printf("sendto (arpCheck)");
#endif
rv = 0;
}
if ( sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0 ) rv = 0;
/* wait arp reply, and check it */
tm.tv_usec = 0;
@ -117,19 +75,14 @@ int arpCheck(u_long inaddr, struct ifinfo *ifbuf, long timeout) {
FD_SET(s, &fdset);
tm.tv_sec = timeout;
if ( select(s+1, &fdset, (fd_set *)NULL, (fd_set *)NULL, &tm) < 0 ) {
#if 0
printf("select (arpCheck)");
#endif
rv = 0;
}
if ( FD_ISSET(s, &fdset) ) {
if (recv(s, &arp, sizeof(arp), 0) < 0 ) {
#if 0
printf("recv (arpCheck)");
#endif
rv = 0;
}
if(arp.operation == htons(ARPOP_REPLY) && bcmp(arp.tHaddr, ifbuf->haddr, 6) == 0 && *((u_int *)arp.sInaddr) == inaddr ) {
DEBUG(LOG_ERR, "Error on ARPING request: %s", sys_errlist[errno]);
if (errno != EINTR) rv = 0;
} else if ( FD_ISSET(s, &fdset) ) {
if (recv(s, &arp, sizeof(arp), 0) < 0 ) rv = 0;
if(arp.operation == htons(ARPOP_REPLY) &&
bcmp(arp.tHaddr, ifbuf->haddr, 6) == 0 &&
*((u_int *)arp.sInaddr) == inaddr ) {
DEBUG(LOG_INFO, "Valid arp reply receved for this address");
rv = 0;
break;
}
@ -138,6 +91,7 @@ int arpCheck(u_long inaddr, struct ifinfo *ifbuf, long timeout) {
time(&prevTime);
}
close(s);
DEBUG(LOG_INFO, "%salid arp replies for this address", rv ? "No v" : "V");
return rv;
}
@ -155,9 +109,8 @@ void mkArpMsg(int opcode, u_long tInaddr, u_char *tHaddr,
*((u_int *)msg->sInaddr) = sInaddr; /* source IP address */
bcopy(sHaddr, msg->sHaddr, 6); /* source hardware address */
*((u_int *)msg->tInaddr) = tInaddr; /* target IP address */
if ( opcode == ARPOP_REPLY ) {
if ( opcode == ARPOP_REPLY )
bcopy(tHaddr, msg->tHaddr, 6); /* target hardware address */
}
}
@ -165,19 +118,14 @@ int openRawSocket (int *s, u_short type) {
int optval = 1;
if((*s = socket (AF_INET, SOCK_PACKET, htons (type))) == -1) {
#if 0
perror("socket");
printf("socket err\n");
#endif
LOG(LOG_ERR, "Could not open raw socket");
return -1;
}
if(setsockopt (*s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval)) == -1) {
#if 0
perror("setsockopt");
printf("setsockopt err\n");
#endif
LOG(LOG_ERR, "Could not setsocketopt on raw socket");
return -1;
}
}
return 0;
}

View File

@ -7,17 +7,10 @@
#define MAC_BCAST_ADDR "\xff\xff\xff\xff\xff\xff"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
struct arpMsg {

16
debug.c
View File

@ -1,16 +0,0 @@
/* debug.c -- DHCP server debug specific functions */
#include "debug.h"
#include <syslog.h>
#if DEBUG
void print_chaddr(u_int8_t *chaddr,char *title) {
syslog(LOG_INFO,"%s = %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x",
title,chaddr[0],chaddr[1],chaddr[2],chaddr[4],
chaddr[4],chaddr[5],chaddr[6],chaddr[7],
chaddr[8],chaddr[9],chaddr[10],chaddr[11],
chaddr[12],chaddr[13],chaddr[14],chaddr[15]);
}
#endif

45
debug.h
View File

@ -1,20 +1,33 @@
/* debug.h */
#ifndef _DEBUG_H
#define _DEBUG_H
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#define DEBUG 0
#if DEBUG
void print_chaddr(u_int8_t *chaddr, char *title);
#ifdef SYSLOG
#include <syslog.h>
#endif
#ifdef SYSLOG
# define LOG(level, str, args...) syslog(level, str, ## args)
#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)
#endif
#ifdef DEBUG
# undef DEBUG
# define DEBUG(level, str, args...) LOG(level, str, ## args)
# define DEBUGGING
#else
# define DEBUG(level, str, args...)
#endif
#endif

1019
dhcpd.c

File diff suppressed because it is too large Load Diff

112
dhcpd.h
View File

@ -1,37 +1,57 @@
/* dhcpd.h */
#ifndef _DHCPD_H
#define _DHCPD_H
#define VERSION "0.8.29"
#include <netinet/ip.h>
#include <netinet/udp.h>
/************************************/
/* Defaults _you_ may want to tweak */
/************************************/
#define MAX_SIMUL_CLIENTS 16 /* maximum number of simultaneous clients */
/* the period of time the client is allowed to use that address */
#define LEASE_TIME "\x00\x0d\x2f\x00"
#define LEASE_TIME (60*60*24*10) /* 10 days of seconds */
/* where to find the DHCP server files */
#define DHCPD_CONF_FILE "/etc/config/dhcpd.conf"
#define DHCPD_IPLIST_FILE "/etc/config/dhcpd.iplist"
#define DHCPD_LEASES_FILE "/etc/config/dhcpd.leases"
#define PID_FILE "/var/log/dhcpd.pid"
#define DHCPD_CONF_FILE "/etc/udhcpd.conf"
/*****************************************************************/
/* Do not modify below here unless you know what you are doing!! */
/*****************************************************************/
/* DHCP protocol -- see RFC */
#define LISTEN_PORT 67
#define SEND_PORT 68
/* DHCP protocol -- see RFC 2131 */
#define SERVER_PORT 67
#define CLIENT_PORT 68
#define MAGIC 0x63825363
#define DHCP_MAGIC 0x63825363
/* DHCP option codes (partial list) */
#define DHCP_PADDING 0x00
#define DHCP_SUBNET 0x01
#define DHCP_TIME_OFFSET 0x02
#define DHCP_ROUTER 0x03
#define DHCP_TIME_SERVER 0x04
#define DHCP_NAME_SERVER 0x05
#define DHCP_DNS_SERVER 0x06
#define DHCP_HOST_NAME 0x0c
#define DHCP_DOMAIN_NAME 0x0f
#define DHCP_WINS_SERVER 0x2c
#define DHCP_REQUESTED_IP 0x32
#define DHCP_LEASE_TIME 0x33
#define DHCP_OPTION_OVER 0x34
#define DHCP_MESSAGE_TYPE 0x35
#define DHCP_SERVER_ID 0x36
#define DHCP_PARAM_REQ 0x37
#define DHCP_MESSAGE 0x38
#define DHCP_MAX_SIZE 0x39
#define DHCP_T1 0x3a
#define DHCP_T2 0x3b
#define DHCP_VENDOR 0x3c
#define DHCP_CLIENT_ID 0x3d
#define DHCP_END 0xFF
#define BOOTREQUEST 1
#define BOOTREPLY 2
@ -45,16 +65,19 @@
#define DHCPACK 5
#define DHCPNAK 6
#define DHCPRELEASE 7
#define DHCPINFORM 8
#define BROADCAST_FLAG 0x8000
#define OPTION_FIELD 0
#define FILE_FIELD 1
#define SNAME_FIELD 2
/* miscellaneous defines */
#define IPLIST 0
#define LEASED 1
#define TRUE 1
#define FALSE 0
#define MAX_BUF_SIZE 20 /* max xxx.xxx.xxx.xxx-xxx\n */
#define MAX_IP_ADDR 254
#define ADD 1
#define DEL 2
#define MAC_BCAST_ADDR "\xff\xff\xff\xff\xff\xff"
struct dhcpMessage {
u_int8_t op;
@ -72,16 +95,55 @@ struct dhcpMessage {
u_int8_t sname[64];
u_int8_t file[128];
u_int32_t cookie;
#ifdef EMBED
u_int8_t options[128]; /* should be 308 but have to conserve space :-) */
#else
u_int8_t options[308];
#endif
u_int8_t options[308]; /* 312 - cookie */
};
struct udp_dhcp_packet {
struct iphdr ip;
struct udphdr udp;
struct dhcpMessage data;
};
struct dhcpOfferedAddr {
u_int8_t chaddr[16];
u_int32_t yiaddr;
u_int32_t yiaddr; /* network order */
u_int32_t expires; /* host order */
};
#define OPT_CODE 0
#define OPT_LEN 1
struct option_set {
unsigned char *data;
struct option_set *next;
};
struct server_config {
u_int32_t server; /* Our IP, in network order */
u_int32_t start; /* Start address of leases, network order */
u_int32_t end; /* End of leases, network order */
struct option_set *options; /* List of DHCP options loaded from the config file */
char *interface; /* The name of the interface to use */
int ifindex; /* Index number of the interface to use */
unsigned char arp[6]; /* Our arp address */
unsigned long lease; /* lease time in seconds (host order) */
unsigned long max_leases; /* maximum number of leases (including reserved address) */
char remaining; /* should the lease file be interpreted as lease time remaining, or
* as the time the lease expires */
unsigned long auto_time; /* how long should udhcpd wait before writing a config file.
* if this is zero, it will only write one on SIGUSR1 */
unsigned long decline_time; /* how long an address is reserved if a client returns a
* decline message */
unsigned long conflict_time; /* how long an arp conflict offender is leased for */
unsigned long offer_time; /* how long an offered address is reserved */
unsigned long min_lease; /* minimum lease a client can request*/
char *lease_file;
char *pid_file;
char *notify_file; /* What to run whenever leases are written */
};
extern struct server_config config;
extern struct dhcpOfferedAddr *leases;
#endif

105
dumpleases.c Normal file
View File

@ -0,0 +1,105 @@
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.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 <syslog.h>
#include <signal.h>
#include <errno.h>
#include <getopt.h>
#include <time.h>
#define REMAINING 0
#define ABSOLUTE 1
struct lease_t {
unsigned char chaddr[16];
u_int32_t yiaddr;
u_int32_t expires;
};
int main (int argc, char *argv[]) {
FILE *fp;
int i, c, mode = REMAINING;
unsigned long expires;
char file[255] = "/etc/udhcpd.leases";
struct lease_t lease;
struct in_addr addr;
static struct option options[] = {
{"absolute", 0, 0, 'a'},
{"remaining", 0, 0, 'r'},
{"file", 1, 0, 'f'},
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
while (1) {
int option_index = 0;
c = getopt_long(argc, argv, "arf:h", options, &option_index);
if (c == -1) break;
switch (c) {
case 'a': mode = ABSOLUTE; break;
case 'r': mode = REMAINING; break;
case 'f':
strncpy(file, optarg, 255);
file[254] = '\0';
break;
case 'h':
printf("Usage: dumpleases -f <file> -[ra]\n\n");
printf(" -f, --file=FILENAME Leases file to load\n");
printf(" -r, --remaining Interepret lease times as time reemaing\n");
printf(" -a, --absolute Interepret lease times as expire time\n");
break;
}
}
if (!(fp = fopen(file, "r"))) {
perror("could not open input file");
return 0;
}
printf("Mac Address IP-Address Expires %s\n", mode == REMAINING ? "in" : "at");
/* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */
while (fread(&lease, sizeof(lease), 1, fp)) {
for (i = 0; i < 6; i++) {
printf("%02x", lease.chaddr[i]);
if (i != 5) printf(":");
}
addr.s_addr = lease.yiaddr;
printf(" %-15s", inet_ntoa(addr));
expires = ntohl(lease.expires);
printf(" ");
if (mode == REMAINING) {
if (!expires) printf("expired\n");
else {
if (expires > 60*60*24) {
printf("%ld days, ", expires / (60*60*24));
expires %= 60*60*24;
}
if (expires > 60*60) {
printf("%ld hours, ", expires / (60*60));
expires %= 60*60;
}
if (expires > 60) {
printf("%ld minutes, ", expires / 60);
expires %= 60;
}
printf("%ld seconds\n", expires);
}
} else printf("%s", ctime(&expires));
}
fclose(fp);
return 0;
}

416
files.c
View File

@ -1,142 +1,302 @@
/* files.c -- DHCP server file manipulation */
/*
* files.c -- DHCP server file manipulation *
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*/
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "debug.h"
#include "dhcpd.h"
#include <stdio.h>
#include <syslog.h>
#include "files.h"
#include "options.h"
#include "leases.h"
int get_multiple_entries(char *hay, char *needle, char *tmp1, char *tmp2, char *tmp3) {
int num=0;
FILE *in;
int len;
char buffer[32], w[32], v[32];
/* supported options are easily added here */
struct dhcp_option options[] = {
/* name[10] flags code */
{"subnet", OPTION_IP, 0x01},
{"timezone", OPTION_S32, 0x02},
{"router", OPTION_IP | OPTION_LIST, 0x03},
{"timesvr", OPTION_IP | OPTION_LIST, 0x04},
{"namesvr", OPTION_IP | OPTION_LIST, 0x05},
{"dns", OPTION_IP | OPTION_LIST, 0x06},
{"logsvr", OPTION_IP | OPTION_LIST, 0x07},
{"cookiesvr", OPTION_IP | OPTION_LIST, 0x08},
{"lprsvr", OPTION_IP | OPTION_LIST, 0x09},
{"bootsize", OPTION_U16, 0x0d},
{"domain", OPTION_STRING, 0x0f},
{"swapsvr", OPTION_IP, 0x10},
{"rootpath", OPTION_STRING, 0x11},
{"mtu", OPTION_U16, 0x1a},
{"broadcast", OPTION_IP, 0x1c},
{"wins", OPTION_IP | OPTION_LIST, 0x2c},
{"lease", OPTION_U32, 0x33},
{" dhcptype", OPTION_U8, 0x35}, /* cannot be in config file */
{" serverid", OPTION_IP, 0x36}, /* ditto */
{"ntpsrv", OPTION_IP | OPTION_LIST, 0x3a},
{"tftp", OPTION_STRING, 0x42},
{"bootfile", OPTION_STRING, 0x43},
{"", 0x00, 0x00}
};
#if DEBUG
syslog(LOG_ERR, "get_multiple_entries of %s from %s", needle, hay);
#endif
if ((in = fopen(hay, "r")) == NULL)
return -1;
/* Lengths of the different option types */
int option_lengths[] = {
[OPTION_IP] = 4,
[OPTION_IP_PAIR] = 8,
[OPTION_BOOLEAN] = 1,
[OPTION_STRING] = 0,
[OPTION_U8] = 1,
[OPTION_U16] = 2,
[OPTION_S16] = 2,
[OPTION_U32] = 4,
[OPTION_S32] = 4
};
while((fgets(buffer, 32 - 1, in)) != NULL) {
/* check if it's what we want */
if((sscanf(buffer, "%s %s", w, v) >= 1) && (strcmp(w, needle) == 0)) {
if(num == 0) {
strcpy(tmp1, v);
num++;
} else if(num == 1) {
strcpy(tmp2, v);
num++;
} else if(num == 2) {
strcpy(tmp3, v);
num++;
}
}
}
fclose(in);
#if DEBUG
syslog(LOG_INFO, "num=%d, tmp=%s, tmp2=%s, tmp3=%s", num, tmp1, tmp2, tmp3);
#endif
return num;
/* on these functions, make sure you datatype matches */
static int read_ip(char *line, void *arg)
{
struct in_addr *addr = arg;
inet_aton(line, addr);
return 1;
}
/* opens up dhcpd.leases and looks for yiaddr.. returning
* 1 if it finds it, 0 if not. */
int check_if_already_leased(u_int32_t yiaddr) {
u_int32_t lease;
FILE *in;
int n = 0;
u_int8_t mac_addr[16];
u_int32_t ip_addr;
int num_ip_addr;
size_t items; /* return value for fread */
if((in = fopen(DHCPD_LEASES_FILE, "r")) == NULL) {
#if DEBUG
syslog(LOG_ERR, "dhcpd.leases not found -- no defined leases");
#endif
return 0;
}
/* Read in the mac - IP pair from the leases file */
while(TRUE) {
items = fread(&mac_addr, sizeof(mac_addr), 1, in);
if(items < 1)
break;
items = fread(&ip_addr, sizeof(ip_addr), 1, in);
if(items < 1)
break;
#if DEBUG
syslog(LOG_INFO,"got a valid MAC/IP pair from dhcpd.leases");
syslog(LOG_INFO,"ip_addr taken = %x", ip_addr);
#endif
/* check if yiaddr matches ip_addr */
if(ip_addr == yiaddr) {
/* ip already in lease file */
fclose(in);
return 1;
}
}
fclose(in);
return 0;
static int read_str(char *line, void *arg)
{
char **dest = arg;
if (*dest) free(*dest);
*dest = strdup(line);
return 1;
}
int addLeased(u_int32_t yiaddr, u_int8_t *chaddr) {
FILE *in;
#if DEBUG
syslog(LOG_INFO,"Writing new lease to lease file (IP = %08x)",yiaddr);
print_chaddr(chaddr,"MAC");
#endif
if ((in = fopen(DHCPD_LEASES_FILE, "a")) == NULL)
return -1;
fwrite(chaddr, 16, 1, in);
fwrite(&yiaddr, sizeof(u_int32_t), 1, in);
fclose(in);
return 0;
static int read_u32(char *line, void *arg)
{
u_int32_t *dest = arg;
*dest = strtoul(line, NULL, 0);
return 1;
}
/* This function opens up the file specified 'filename' and searches
* through the file for 'keyword'. If 'keyword' is found any string
* following it is stored in 'value'.. If 'value' is NULL we assume
* the function was called simply to determing if the keyword exists
* in the file.
*
* args: filename (IN) - config filename
* keyword (IN) - word to search for in config file
* value (OUT) - value of keyword (if value not NULL)
*
* retn: -1 on error,
* 0 if keyword not found,
* 1 if found
*/
int search_config_file(char *filename, char *keyword, char *value) {
FILE *in;
int len;
char buffer[32], w[32], v[32];
if ((in = fopen(filename, "r")) == NULL)
return -1;
while((fgets(buffer, 32 - 1, in)) != NULL) {
/* check if it's what we want */
if((sscanf(buffer, "%s %s", w, v) >= 1) && (strcmp(w, keyword) == 0)) {
/* found it :-) */
if(value == NULL) {
return 1;
} else {
strcpy(value, v);
fclose(in);
/* tell them we got it */
return 1;
}
}
}
fclose(in);
return 0;
static int read_yn(char *line, void *arg)
{
char *dest = arg;
if (!strcasecmp("yes", line) || !strcmp("1", line) || !strcasecmp("true", line))
*dest = 1;
else if (!strcasecmp("no", line) || !strcmp("0", line) || !strcasecmp("false", line))
*dest = 0;
else return 0;
return 1;
}
/* read a dhcp option and add it to opt_list */
static int read_opt(char *line, void *arg)
{
struct option_set **opt_list = arg;
char *opt, *val;
char fail;
struct dhcp_option *option = NULL;
int length = 0;
char buffer[255];
u_int16_t result_u16;
int16_t result_s16;
u_int16_t result_u32;
int16_t result_s32;
int i;
if (!(opt = strtok(line, " \t="))) return 0;
for (i = 0; options[i].code; i++)
if (!strcmp(options[i].name, opt)) {
option = &(options[i]);
break;
}
if (!option) return 0;
do {
val = strtok(NULL, ", \t");
if (val) {
fail = 0;
length = 0;
switch (option->flags & TYPE_MASK) {
case OPTION_IP:
read_ip(val, buffer);
break;
case OPTION_IP_PAIR:
read_ip(val, buffer);
if ((val = strtok(NULL, ", \t")))
read_ip(val, buffer + 4);
else fail = 1;
break;
case OPTION_STRING:
length = strlen(val);
if (length > 254) length = 254;
memcpy(buffer, val, length);
break;
case OPTION_BOOLEAN:
if (!read_yn(val, buffer)) fail = 1;
break;
case OPTION_U8:
buffer[0] = strtoul(val, NULL, 0);
break;
case OPTION_U16:
result_u16 = htons(strtoul(val, NULL, 0));
memcpy(buffer, &result_u16, 2);
break;
case OPTION_S16:
result_s16 = htons(strtol(val, NULL, 0));
memcpy(buffer, &result_s16, 2);
break;
case OPTION_U32:
result_u32 = htonl(strtoul(val, NULL, 0));
memcpy(buffer, &result_u32, 4);
break;
case OPTION_S32:
result_s32 = htonl(strtol(val, NULL, 0));
memcpy(buffer, &result_s32, 4);
break;
default:
break;
}
length += option_lengths[option->flags & TYPE_MASK];
if (!fail)
attach_option(opt_list, option, buffer, length);
} else fail = 1;
} while (!fail && option->flags & OPTION_LIST);
return 1;
}
static struct config_keyword keywords[] = {
/* keyword handler variable address default */
{"start", read_ip, &(config.start), "192.168.0.20"},
{"end", read_ip, &(config.end), "192.168.0.254"},
{"interface", read_str, &(config.interface), "eth0"},
{"option", read_opt, &(config.options), ""},
{"opt", read_opt, &(config.options), ""},
{"max_leases", read_u32, &(config.max_leases), "254"},
{"remaining", read_yn, &(config.remaining), "yes"},
{"auto_time", read_u32, &(config.auto_time), "7200"},
{"decline_time",read_u32, &(config.decline_time),"3600"},
{"conflict_time",read_u32,&(config.conflict_time),"3600"},
{"offer_time", read_u32, &(config.offer_time), "60"},
{"min_lease", read_u32, &(config.min_lease), "60"},
{"lease_file", read_str, &(config.lease_file), "/etc/udhcpd.leases"},
{"pid_file", read_str, &(config.pid_file), "/var/run/udhcpd.pid"},
{"notify_file", read_str, &(config.notify_file),""},
{"", NULL, NULL, ""}
};
int read_config(char *file)
{
FILE *in;
char buffer[80], *token, *line;
int i;
for (i = 0; strlen(keywords[i].keyword); i++)
if (strlen(keywords[i].def))
keywords[i].handler(keywords[i].def, keywords[i].var);
if (!(in = fopen(file, "r"))) {
DEBUG(LOG_ERR, "unable to open config file: %s", file);
return 0;
}
while (fgets(buffer, 80, in)) {
if (strchr(buffer, '\n')) *(strchr(buffer, '\n')) = '\0';
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++;
line = line + strspn(line, " \t=");
if (*line == '\0') continue;
for (i = 0; strlen(keywords[i].keyword); i++)
if (!strcasecmp(token, keywords[i].keyword))
keywords[i].handler(line, keywords[i].var);
}
fclose(in);
return 1;
}
/* the dummy var is here so this can be a signal handler */
void write_leases(int dummy)
{
FILE *fp;
unsigned int i;
char buf[255];
time_t curr = time(0);
unsigned long lease_time;
dummy = 0;
if (!(fp = fopen(config.lease_file, "w"))) {
LOG(LOG_ERR, "Unable to open %s for writing", config.lease_file);
return;
}
for (i = 0; i < config.max_leases; i++) {
if (leases[i].yiaddr != 0) {
if (config.remaining) {
if (lease_expired(&(leases[i])))
lease_time = 0;
else lease_time = leases[i].expires - curr;
} else lease_time = leases[i].expires;
lease_time = htonl(lease_time);
fwrite(leases[i].chaddr, 16, 1, fp);
fwrite(&(leases[i].yiaddr), 4, 1, fp);
fwrite(&lease_time, 4, 1, fp);
}
}
fclose(fp);
if (strlen(config.notify_file)) {
sprintf(buf, "%s %s", config.notify_file, config.lease_file);
system(buf);
}
}
void read_leases(char *file)
{
FILE *fp;
unsigned int i = 0;
time_t curr = time(0);
struct dhcpOfferedAddr lease;
if (!(fp = fopen(file, "r"))) {
LOG(LOG_ERR, "Unable to open %s for reading", file);
return;
}
while (i < config.max_leases && (fread(&lease, sizeof lease, 1, fp) == 1)) {
if (lease.yiaddr >= config.start && lease.yiaddr <= config.end) {
leases[i].yiaddr = lease.yiaddr;
leases[i].expires = ntohl(lease.expires);
if (config.remaining) leases[i].expires += curr;
memcpy(leases[i].chaddr, lease.chaddr, sizeof(lease.chaddr));
i++;
}
}
DEBUG(LOG_INFO, "Read %d leases", i);
if (i == config.max_leases) {
if (fgetc(fp) == EOF)
/* might be helpfull to drop expired leases */
LOG(LOG_WARNING, "Too many leases while loading %s\n", file);
}
fclose(fp);
}

39
files.h
View File

@ -1,7 +1,38 @@
/* files.h */
#ifndef _FILES_H
#define _FILES_H
int search_config_file(char *filename, char *keyword, char *value);
int addLeased(u_int32_t yiaddr, u_int8_t chaddr[16]);
int check_if_already_leased(u_int32_t yiaddr);
int get_multiple_entries(char *hay, char *needle, char *tmp1, char *tmp2, char *tmp3);
struct config_keyword {
char keyword[20];
int (*handler)(char *line, void *var);
void *var;
char def[40];
};
#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
#define OPTION_LIST 0x80
struct dhcp_option {
char name[10];
char flags;
char code;
};
extern struct dhcp_option options[];
extern int option_lengths[];
int read_config(char *file);
void write_leases(int dummy);
void read_leases(char *file);
#endif

94
leases.c Normal file
View File

@ -0,0 +1,94 @@
/*
* leases.c -- tools to manage DHCP leases
* Russ Dill <Russ.Dill@asu.edu> July 2001
*/
#include <time.h>
#include <string.h>
#include "debug.h"
#include "dhcpd.h"
#include "files.h"
#include "options.h"
#include "leases.h"
/* clear every lease out that chaddr OR yiaddr matches and is nonzero */
void clear_lease(u_int8_t *chaddr, u_int32_t yiaddr)
{
unsigned int i, blank_chaddr = 0, blank_yiaddr = 0;
for (i = 0; i < 16 && !chaddr[i]; i++);
if (i == 16) blank_chaddr = 1;
blank_yiaddr = (yiaddr == 0);
for (i = 0; i < config.max_leases; i++)
if ((!blank_chaddr && !memcmp(leases[i].chaddr, chaddr, 16)) ||
(!blank_yiaddr && leases[i].yiaddr == yiaddr)) {
memset(&(leases[i]), 0, sizeof(struct dhcpOfferedAddr));
}
}
/* add a lease into the table, clearing out any old ones */
struct dhcpOfferedAddr *add_lease(u_int8_t *chaddr, u_int32_t yiaddr, unsigned long lease)
{
struct dhcpOfferedAddr *oldest;
/* clean out any old ones */
clear_lease(chaddr, yiaddr);
oldest = oldest_expired_lease();
if (oldest) {
memcpy(oldest->chaddr, chaddr, 16);
oldest->yiaddr = yiaddr;
oldest->expires = time(0) + lease;
}
return oldest;
}
/* true if a lease has expired */
int lease_expired(struct dhcpOfferedAddr *lease)
{
return (lease->expires < (unsigned long) time(0));
}
/* Find the oldest expired lease, NULL if there are no expired leases */
struct dhcpOfferedAddr *oldest_expired_lease(void)
{
struct dhcpOfferedAddr *oldest = NULL;
unsigned long oldest_lease = time(0);
unsigned int i;
for (i = 0; i < config.max_leases; i++)
if (oldest_lease > leases[i].expires) {
oldest_lease = leases[i].expires;
oldest = &(leases[i]);
}
return oldest;
}
/* Find the first lease that matches chaddr, NULL if no match */
struct dhcpOfferedAddr *find_lease_by_chaddr(u_int8_t *chaddr)
{
unsigned int i;
for (i = 0; i < config.max_leases; i++)
if (!memcmp(leases[i].chaddr, chaddr, 16)) return &(leases[i]);
return NULL;
}
/* Find the first lease that matches yiaddr, NULL is no match */
struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr)
{
unsigned int i;
for (i = 0; i < config.max_leases; i++)
if (leases[i].yiaddr == yiaddr) return &(leases[i]);
return NULL;
}

13
leases.h Normal file
View File

@ -0,0 +1,13 @@
/* leases.h */
#ifndef _LEASES_H
#define _LEASES_H
void clear_lease(u_int8_t *chaddr, u_int32_t yiaddr);
struct dhcpOfferedAddr *add_lease(u_int8_t *chaddr, u_int32_t yiaddr, unsigned long lease);
int lease_expired(struct dhcpOfferedAddr *lease);
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);
#endif

View File

@ -1,58 +0,0 @@
/* nettel.c -- NETtel specific functions for the DHCP server */
#ifdef CONFIG_NETtel
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include "dhcpd.h"
int commitChanges() {
char value[5];
pid_t pid;
FILE *in;
/* get the pid of flatfsd */
if ((in = fopen("/var/log/flatfsd.pid", "r")) == NULL)
return -1;
if(fread(&pid, sizeof(pid_t), 1, in) <= 0) {
fclose(in);
return -1;
}
fclose(in);
if((kill(pid, 10)) == -1)
return -1;
return 0;
}
int route_add_host(int type) {
pid_t pid;
char *argv[16];
int s, argc = 0;
/* route add -host 255.255.255.255 eth0 */
if((pid = vfork()) == 0) { /* child */
argv[argc++] = "/bin/route";
if(type == ADD)
argv[argc++] = "add";
else if(type == DEL)
argv[argc++] = "del";
argv[argc++] = "-host";
argv[argc++] = "255.255.255.255";
argv[argc++] = "eth0";
argv[argc] = NULL;
execvp("/bin/route", argv);
exit(0);
} else if (pid > 0) {
waitpid(pid, &s, 0);
}
return 0;
}
#endif

View File

@ -1,5 +0,0 @@
/* nettel.h */
int commitChanges();
int route_add_host(int type);

260
options.c
View File

@ -1,102 +1,184 @@
/* options.c -- DHCP server option packet tools */
/*
* options.c -- DHCP server option packet tools
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*/
#include <stdio.h>
#include <stdlib.h>
#include "debug.h"
#include "dhcpd.h"
#include "files.h"
#include "options.h"
#include "leases.h"
/* add new option data to the options field terminating
* with an 0xff */
int addOption(unsigned char *optionptr, unsigned char code,
char datalength, char *data) {
endOption(&optionptr);
optionptr[0] = code;
if(code == 0xff)
return 0;
optionptr++;
optionptr[0] = datalength;
optionptr++;
memcpy(optionptr, data, datalength);
optionptr += datalength;
optionptr[0] = 0xff;
return 0;
/* get an option with bounds checking. */
unsigned char *get_option(struct dhcpMessage *packet, int code)
{
int i, length;
static char err[] = "bogus packet, option fields too long."; /* save a few bytes */
unsigned char *optionptr;
int over = 0, done = 0, curr = OPTION_FIELD;
optionptr = packet->options;
i = 0;
length = 308;
while (!done) {
if (i >= length) {
LOG(LOG_WARNING, err);
return NULL;
}
if (optionptr[i + OPT_CODE] == code) {
if (i + 1 + optionptr[i + OPT_LEN] >= length) {
LOG(LOG_WARNING, err);
return NULL;
}
return optionptr + i + 2;
}
switch (optionptr[i + OPT_CODE]) {
case DHCP_PADDING:
i++;
break;
case DHCP_OPTION_OVER:
if (i + 1 + optionptr[i + OPT_LEN] >= length) {
LOG(LOG_WARNING, err);
return NULL;
}
over = optionptr[i + 3];
i += optionptr[OPT_LEN] + 2;
break;
case DHCP_END:
if (curr == OPTION_FIELD && over & FILE_FIELD) {
optionptr = packet->file;
i = 0;
length = 128;
curr = FILE_FIELD;
} else if (curr == FILE_FIELD && over & SNAME_FIELD) {
optionptr = packet->sname;
i = 0;
length = 64;
curr = SNAME_FIELD;
} else done = 1;
break;
default:
i += optionptr[OPT_LEN + i] + 2;
}
}
return NULL;
}
int add_multiple_option(unsigned char *optionptr, unsigned char code,
char datalength, char *data1, char *data2, char *data3) {
endOption(&optionptr);
optionptr[0] = code;
if(code == 0xff)
return 0;
optionptr++;
optionptr[0] = datalength;
optionptr++;
if(data1 != NULL) {
memcpy(optionptr, data1, 0x04);
optionptr += 0x04;
if(data2 != NULL) {
memcpy(optionptr, data2, 0x04);
optionptr += 0x04;
if(data3 != NULL) {
memcpy(optionptr, data3, 0x04);
optionptr += 0x04;
}
}
}
optionptr[0] = 0xff;
return 0;
/* return the position of the 'end' option (no bounds checking) */
int end_option(unsigned char *optionptr)
{
int i = 0;
while (optionptr[i] != DHCP_END) {
if (optionptr[i] == DHCP_PADDING) i++;
else i += optionptr[i + OPT_LEN] + 2;
}
return i;
}
int addOptionMulti(unsigned char *optionptr, unsigned char code,
char datalength, char *data,int mul) {
int i;
endOption(&optionptr);
optionptr[0] = code;
if(code == 0xff)
return 0;
optionptr++;
optionptr[0] = (datalength * mul);
optionptr++;
for (i=0;i<mul;i++) {
memcpy(optionptr, data, datalength);
optionptr += datalength;
}
optionptr[0] = 0xff;
return 0;
/* add an option string to the options (an option string contains an option code,
* length, then data) */
int add_option_string(unsigned char *optionptr, unsigned char *string)
{
int i, end = end_option(optionptr);
/* end position + string length + option code/length + end option */
if (end + string[OPT_LEN] + 2 + 1 >= 308) {
for (i = 0; options[i].code && options[i].code != string[OPT_CODE]; i++);
LOG(LOG_ERR, "Option %s (0x%02x) did not fit into the packet!",
options[i].code ? options[i].name : "unknown", string[OPT_CODE]);
return 0;
}
DEBUG(LOG_INFO, "adding option %02x", string[OPT_CODE]);
memcpy(optionptr + end, string, string[OPT_LEN] + 2);
optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
return string[OPT_LEN] + 2;
}
/* update the option pointer to point to where the 0xff is */
int endOption(unsigned char **optionptr) {
unsigned char *tmpptr = *optionptr;
while(tmpptr[0] != 0xff) {
if(tmpptr[0] == 0x00)
continue;
tmpptr++;
tmpptr += tmpptr[0];
tmpptr++;
}
*optionptr = tmpptr;
return 0;
/* add an option that was loaded from dhcpd.conf to a packet */
int add_stored_option(unsigned char *optionptr, unsigned char code)
{
struct option_set *curr = config.options;
while (curr && curr->data[OPT_CODE] > code)
curr = curr->next;
if (curr && curr->data[OPT_CODE] == code) {
return add_option_string(optionptr, curr->data);
} else return 0;
}
/* add a one to four byte option to a packet */
int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t data)
{
char length = 0;
int i, end;
unsigned char *getOption(unsigned char *options, int option_val) {
while(options[0] != 0xff) {
if(options[0] == 0) {
options++;
continue;
}
if(options[0] == 0xff)
return NULL;
if(options[0] == option_val)
return options+2;
options++;
options += options[0];
options++;
}
return NULL; /* never executed */
for (i = 0; options[i].code; i++)
if (options[i].code == code) {
length = option_lengths[options[i].flags & TYPE_MASK];
break;
}
if (!length) return 0;
end = end_option(optionptr);
optionptr[end + OPT_CODE] = code;
optionptr[end + OPT_LEN] = length;
switch (length) {
case 1: optionptr[end + 2] = data; break;
case 2: *((u_int16_t *) &optionptr[end + 2]) = htons(data); break;
case 4: *((u_int32_t *) &optionptr[end + 2]) = htonl(data); break;
}
optionptr[end + length + 2] = DHCP_END;
return length;
}
/* find option 'code' in opt_list */
struct option_set *find_option(struct option_set *opt_list, char 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;
else return NULL;
}
/* add an option to the opt_list */
void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length)
{
struct option_set *existing, *new, **curr;
/* add it to an existing option */
if ((existing = find_option(*opt_list, option->code))) {
DEBUG(LOG_INFO, "Attaching option %s to existing member of list", option->name);
if (option->flags & OPTION_LIST) {
if (existing->data[OPT_LEN] + length <= 255) {
existing->data = realloc(existing->data,
existing->data[OPT_LEN] + length + 2);
memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
existing->data[OPT_LEN] += length;
} /* else, ignore the data, we could put this in a second option in the future */
} /* else, ignore the new data */
} else {
DEBUG(LOG_INFO, "Attaching option %s to list", option->name);
/* make a new option */
new = malloc(sizeof(struct option_set));
new->data = malloc(length + 2);
new->data[OPT_CODE] = option->code;
new->data[OPT_LEN] = length;
memcpy(new->data + 2, buffer, length);
curr = opt_list;
while (*curr && (*curr)->data[OPT_CODE] < option->code)
curr = &(*curr)->next;
new->next = *curr;
*curr = new;
}
}

View File

@ -1,10 +1,15 @@
/* options.h */
#ifndef _OPTIONS_H
#define _OPTIONS_H
unsigned char *getOption(unsigned char *options, int option_val);
int endOption(unsigned char **optionptr);
int addOption(unsigned char *optionptr, unsigned char code, char datalength, char *data);
int addOptionMulti(unsigned char *optionptr, unsigned char code,
char datalength, char *data,int mul);
int add_multiple_option(unsigned char *optionptr, unsigned char code,
char datalength, char *data1, char *data2, char *data3);
#include "files.h"
unsigned char *get_option(struct dhcpMessage *packet, int code);
int end_option(unsigned char *optionptr);
int add_option_string(unsigned char *optionptr, unsigned char *string);
int add_stored_option(unsigned char *optionptr, unsigned char code);
int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t data);
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

View File

@ -1,30 +0,0 @@
By default, on generic Linux systems, these files should be located in
/etc/ directory. You can change this by editing the #define in dhcpd.c
DHCPD_*_FILE
dhcpd.conf
----------
Sample DHCPD config file where the following entries are permitted:
subnet x.x.x.x
wins x.x.x.x
gateway x.x.x.x
dns x.x.x.x
dhcpd.iplist
------------
sample DHCPD IP list pool file (must be in binary format).
This sample file has the following addresses in the pool (and
was created with the 'makeiplist' tool):
192.168.111.33
192.168.111.34
192.168.111.35
192.168.111.36

View File

@ -1,4 +0,0 @@
subnet 255.255.255.0
router 192.168.111.1
dns 192.168.111.2
wins 192.168.111.3

View File

@ -1 +0,0 @@
<EFBFBD><EFBFBD>o!<21><>o"<22><>o#<23><>o$

107
samples/udhcpd.conf Normal file
View File

@ -0,0 +1,107 @@
# Sample udhcpd configuration file (/etc/udhcpd.conf)
# The start and end of the IP lease block
start 192.168.0.20 #default: 192.168.0.20
end 192.168.0.254 #default: 192.168.0.254
# The interface that udhcpd will use
interface eth0 #default: eth0
# The maximim number of leases (includes addressesd reserved
# by OFFER's, DECLINE's, and ARP conficts
#max_leases 254 #default: 254
# If remaining is true (default), udhcpd will store the time
# remaining for each lease in the udhcpd leases file. This is
# for embedded systems that cannot keep time between reboots.
# If you set remaining to no, the absolute time that the lease
# expires at will be stored in the dhcpd.leases file.
#remaining yes #default: yes
# The time period at which udhcpd will write out a dhcpd.leases
# file. If this is 0, udhcpd will never automatically write a
# lease file. (specified in seconds)
#auto_time 7200 #default: 7200 (2 hours)
# The amount of time that an IP will be reserved (leased) for if a
# DHCP decline message is received (seconds).
#decline_time 3600 #default: 3600 (1 hour)
# The amount of time that an IP will be reserved (leased) for if an
# ARP conflct occurs. (seconds
#conflict_time 3600 #default: 3600 (1 hour)
# How long an offered address is reserved (leased) in seconds
#offer_time 60 #default: 60 (1 minute)
# If a lease to be given is below this value, the full lease time is
# instead used (seconds).
#min_lease 60 #defult: 60
# The location of the leases file
#lease_file /etc/udhcpd.leases #defualt: /etc/udhcpd.leases
# The location of the pid file
#pid_file /var/run/udhcpd.pid #default: /var/run/udhcpd.pid
# Everytime udhcpd writes a leases file, the below script will be called.
# Useful for writing the lease file to flash every few hours.
#notify_file #default: (no script)
#notify_file dumpleases # <--- usefull for debugging
# The remainer of options are DHCP options and can be specifed with the
# keyword 'opt' or 'option'. If an option can take multiple items, such
# as the dns option, they can be listed on the same line, or multiple
# lines. The only option with a default is 'lease'.
#Examles
opt dns 192.168.10.2 192.168.10.10
option subnet 255.255.255.0
opt router 192.168.10.2
opt wins 192.168.10.10
option dns 129.219.13.81 # appened to above DNS servers for a total of 3
option domain local
option lease 864000 # 10 days of seconds
# Currently supported options, for more info, see files.c
#subnet
#timezone
#router
#timesvr
#namesvr
#dns
#logsvr
#cookiesvr
#lprsvr
#bootsize
#domain
#swapsvr
#rootpath
#mtu
#broadcast
#wins
#lease
#ntpsrv
#tftp
#bootfile

224
socket.c
View File

@ -1,4 +1,7 @@
/* socket.c -- DHCP server client/server socket creation */
/*
* socket.c -- DHCP server client/server socket creation
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*/
#include <fcntl.h>
#include <string.h>
@ -13,63 +16,198 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
/*
#ifndef EMBED
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.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 <errno.h>
#include "debug.h"
#include "dhcpd.h"
#include "files.h"
#include "options.h"
#include "leases.h"
int serverSocket(short listen_port) {
int server_socket;
struct sockaddr_in server;
int n = 1;
int server_socket;
struct sockaddr_in server;
int n = 1;
server_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(server_socket == -1)
return -1;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(listen_port);
server.sin_addr.s_addr = INADDR_ANY;
if(setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1)
server_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(server_socket == -1)
return -1;
if(bind(server_socket, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
return -1;
return server_socket;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(listen_port);
server.sin_addr.s_addr = INADDR_ANY;
if(setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1)
return -1;
if(bind(server_socket, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
return -1;
return server_socket;
}
int clientSocket(short send_from_port, short send_to_port) {
int n = 1;
int client_socket;
struct sockaddr_in client;
static u_int16_t checksum(void *addr, int count)
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register int32_t sum = 0;
u_int16_t *source = (u_int16_t *) addr;
client_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(client_socket == -1)
return -1;
while( count > 1 ) {
/* This is the inner loop */
sum += *source++;
count -= 2;
}
if (setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1)
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) source;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
/* send a packet to giaddr using the kernel ip stack */
static int send_packet_to_relay(struct dhcpMessage *payload, int payload_length)
{
int n = 1;
int fd, result;
struct sockaddr_in client;
DEBUG(LOG_INFO, "Forwarding packet to relay");
if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
return -1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1)
return -1;
setsockopt(client_socket, SOL_SOCKET, SO_BROADCAST, (char *) &n, sizeof(n));
bzero(&client, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(send_from_port);
client.sin_addr.s_addr = INADDR_ANY;
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(SERVER_PORT);
client.sin_addr.s_addr = config.server;
if(bind(client_socket,(struct sockaddr *)&client, sizeof(struct sockaddr))==-1)
return -1;
if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
return -1;
bzero(&client, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(send_to_port);
client.sin_addr.s_addr = INADDR_BROADCAST;
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(SERVER_PORT);
client.sin_addr.s_addr = payload->giaddr;
if(connect(client_socket, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
return -1;
if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
return -1;
return client_socket;
result = write(fd, payload, payload_length);
close(fd);
return result;
}
/* send a packet to a specific arp address and ip address by creating our own ip packet */
static int send_packet_to_client(struct dhcpMessage *payload, int payload_length, int force_broadcast)
{
int fd;
int result;
struct sockaddr_ll dest;
struct udp_dhcp_packet packet;
u_int32_t ciaddr;
char chaddr[6];
if (force_broadcast) {
DEBUG(LOG_INFO, "broadcasting packet to client (NAK)");
ciaddr = INADDR_BROADCAST;
memcpy(chaddr, MAC_BCAST_ADDR, 6);
} else if (payload->ciaddr) {
DEBUG(LOG_INFO, "unicasting packet to client ciaddr");
ciaddr = payload->ciaddr;
memcpy(chaddr, payload->chaddr, 6);
} else if (ntohs(payload->flags) & BROADCAST_FLAG) {
DEBUG(LOG_INFO, "broadcasting packet to client (requested)");
ciaddr = INADDR_BROADCAST;
memcpy(chaddr, MAC_BCAST_ADDR, 6);
} else {
DEBUG(LOG_INFO, "unicasting packet to client yiaddr");
ciaddr = payload->yiaddr;
memcpy(chaddr, payload->chaddr, 6);
}
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
DEBUG(LOG_ERR, "socket call failed: %s", sys_errlist[errno]);
return -1;
}
memset(&dest, 0, sizeof(dest));
memset(&packet, 0, sizeof(packet));
dest.sll_family = AF_PACKET;
dest.sll_protocol = htons(ETH_P_IP);
dest.sll_ifindex = config.ifindex;
dest.sll_halen = 6;
memcpy(dest.sll_addr, chaddr, 6);
if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
DEBUG(LOG_ERR, "bind call failed: %s", sys_errlist[errno]);
close(fd);
return -1;
}
packet.ip.protocol = IPPROTO_UDP;
packet.ip.saddr = config.server;
packet.ip.daddr = ciaddr;
packet.ip.tot_len = htons(sizeof(packet.udp) + payload_length); /* cheat on the psuedo-header */
packet.udp.source = htons(SERVER_PORT);
packet.udp.dest = htons(CLIENT_PORT);
packet.udp.len = htons(sizeof(packet.udp) + payload_length);
memcpy(&(packet.data), payload, payload_length);
packet.udp.check = checksum(&packet, sizeof(packet.ip) + sizeof(packet.udp) + payload_length);
packet.ip.tot_len = htons(sizeof(packet.ip) + sizeof(packet.udp) + payload_length);
packet.ip.ihl = sizeof(packet.ip) >> 2;
packet.ip.version = IPVERSION;
packet.ip.ttl = IPDEFTTL;
packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip));
result = sendto(fd, &packet, ntohs(packet.ip.tot_len), 0, (struct sockaddr *) &dest, sizeof(dest));
if (result <= 0) {
DEBUG(LOG_ERR, "write on socket failed: %s", sys_errlist[errno]);
}
close(fd);
return result;
}
/* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */
int send_packet(struct dhcpMessage *payload, int force_broadcast)
{
int ret, payload_length;
payload_length = sizeof(struct dhcpMessage) - 308;
payload_length += end_option(payload->options) + 1;
if (payload_length % 2) {
payload_length++;
*((char *) payload + payload_length - 1) = '\0';
}
DEBUG(LOG_INFO, "payload length is %d bytes", payload_length);
if (payload->giaddr)
ret = send_packet_to_relay(payload, payload_length);
else ret = send_packet_to_client(payload, payload_length, force_broadcast);
return ret;
}

View File

@ -1,5 +1,8 @@
/* socket.h */
#ifndef _SOCKET_H
#define _SOCKET_H
int serverSocket(short listen_port);
int clientSocket(short send_from_port, short send_to_port);
int send_packet(struct dhcpMessage *payload, int force_broadcast);
#endif