mirror of
https://git.busybox.net/udhcp
synced 2025-05-08 22:09:45 +08:00
Import of rewrite to 0.9.0
This commit is contained in:
parent
9e89798760
commit
815b41096f
11
AUTHORS
11
AUTHORS
@ -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:
|
||||
--------------
|
||||
|
15
ChangeLog
15
ChangeLog
@ -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
|
||||
|
45
Makefile
45
Makefile
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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
102
README
@ -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
12
TODO
@ -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
120
arpping.c
@ -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;
|
||||
}
|
||||
|
||||
|
13
arpping.h
13
arpping.h
@ -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
16
debug.c
@ -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
45
debug.h
@ -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
|
112
dhcpd.h
112
dhcpd.h
@ -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
105
dumpleases.c
Normal 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
416
files.c
@ -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
39
files.h
@ -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
94
leases.c
Normal 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
13
leases.h
Normal 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
|
58
nettel.c
58
nettel.c
@ -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
|
5
nettel.h
5
nettel.h
@ -1,5 +0,0 @@
|
||||
/* nettel.h */
|
||||
|
||||
int commitChanges();
|
||||
int route_add_host(int type);
|
||||
|
260
options.c
260
options.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
19
options.h
19
options.h
@ -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
|
@ -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
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
subnet 255.255.255.0
|
||||
router 192.168.111.1
|
||||
dns 192.168.111.2
|
||||
wins 192.168.111.3
|
@ -1 +0,0 @@
|
||||
<EFBFBD><EFBFBD>o!<21><>o"<22><>o#<23><>o$
|
107
samples/udhcpd.conf
Normal file
107
samples/udhcpd.conf
Normal 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
224
socket.c
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user