2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-30 13:57:50 +00:00

Various user-provided patches

This commit is contained in:
Ted Lemon 1996-03-16 17:50:30 +00:00
parent 48695f7d76
commit a8b53b4220
25 changed files with 799 additions and 74 deletions

View File

@ -8,12 +8,15 @@ all: dhcpd dhclient
.include <bsd.prog.mk>
CFLAGS += -g -Wall -Wstrict-prototypes -Wno-unused \
DEBUG=-g
CFLAGS += $(DEBUG) -Wall -Wstrict-prototypes -Wno-unused \
-Wno-implicit -Wno-comment \
-Wno-uninitialized -Werror
dhclient: dhclient.o confpars.o alloc.o memory.o options.o \
hash.o tables.o inet.o convert.o conflex.o errwarn.o \
tree.o print.o db.o
cc -o dhclient dhclient.o confpars.o alloc.o memory.o options.o \
$(CC) -o dhclient dhclient.o confpars.o alloc.o memory.o options.o \
hash.o tables.o inet.o convert.o conflex.o errwarn.o \
print.o tree.o db.o

View File

@ -11,7 +11,7 @@ DEBUG=-g
CFLAGS=$(DEBUG)
dhcpd: $(OBJS) $(COBJ)
cc -o dhcpd $(OBJS) $(COBJ)
$(CC) -o dhcpd $(OBJS) $(COBJ)
dhclient: dhclient.o $(COBJ)
cc -o dhclient dhclient.o $(COBJ)
$(CC) -o dhclient dhclient.o $(COBJ)

20
README
View File

@ -32,6 +32,26 @@ Bakeoff participants at Connectathon who tried their clients against
dhcpd and told me where it was busted, or, later on, that it wasn't
busted anymore.
DEBUGGING
dhcpd logs to LOG_DAEMON. Depending on the logging level that you
choose with syslog, you can get quite a bit of information about what
dhcpd is doing. To get the most logging, put the following in your
/etc/syslog.conf file and restart syslog:
daemon.debug: /var/log/daemon.log
(obviously, change the filename to suit your taste).
This change may have the unfortunate side effect of capturing a lot of
information from daemons other than dhcpd that you don't want to look
at.
You can also compile dhcpd with ``make DEBUG="-g -DDEBUG"''. If you
do this, dhcpd will run in the foreground rather than as a daemon, and
will print its log messages to standard error. It will also dump the
contents of all packets it receives and sends.
BUGS
Currently, ISC dhcpd supports the DHCP protocol strictly the standard

View File

@ -151,8 +151,11 @@ void bootp (packet)
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending bootp reply to %s, port %d",
inet_ntoa (to.sin_addr), to.sin_port);
note ("Sending BOOTREPLY to %s, address %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (packet -> raw -> yiaddr));
errno = 0;
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,

View File

@ -1,6 +1,6 @@
/* netbsd.h
/* bsdos.h
System dependencies for NetBSD... */
System dependencies for BSDI BSD/OS... */
/*
* Copyright (c) 1996 The Internet Software Consortium. All rights reserved.

View File

@ -106,7 +106,7 @@ static int get_token (cfile)
ttok = read_string (cfile);
break;
}
if (isascii (c) && isdigit (c)) {
if ((isascii (c) && isdigit (c)) || c == '-') {
ttok = read_number (c, cfile);
break;
} else if (isascii (c) && isalpha (c)) {

View File

@ -173,12 +173,15 @@ void cons_options (inpacket, outpacket, options, overload)
/* XXX Maybe it would be safe to assume that we can send a packet
to the client that's as big as the one it sent us, even if it
didn't specify a large MTU. */
if (inpacket && inpacket -> options [DHO_DHCP_MAX_MESSAGE_SIZE].data)
if (inpacket && inpacket -> options [DHO_DHCP_MAX_MESSAGE_SIZE].data) {
main_buffer_size =
(getUShort (inpacket -> options
[DHO_DHCP_MAX_MESSAGE_SIZE].data)
- DHCP_FIXED_LEN);
else
/* Enforce a minimum packet size... */
if (main_buffer_size < (576 - DHCP_FIXED_LEN))
main_buffer_size = 576 - DHCP_FIXED_LEN;
} else
main_buffer_size = 576 - DHCP_FIXED_LEN;
/* Preload the option priority list with mandatory options. */

View File

@ -48,6 +48,27 @@ static char copyright[] =
#include "dhcpd.h"
#include <sys/ioctl.h>
#ifdef USE_BPF
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/if_ether.h>
struct interface {
struct in_addr address;
int bpf;
};
static struct interface *if_list;
static int num_ifaces;
#endif
/* List of sockets we're accepting packets on... */
struct socklist {
struct socklist *next;
@ -86,17 +107,48 @@ u_int32_t *get_interface_list (count)
second time to copy them into an array of addresses. */
for (i = 0; i < ic.ifc_len;) {
struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
#ifdef HAVE_SIN_LEN
i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
#else
i += sizeof *ifp;
#endif
if (ifp -> ifr_addr.sa_family == AF_INET) {
struct sockaddr_in *foo =
(struct sockaddr_in *)(&ifp -> ifr_addr);
/* We don't want the loopback interface. */
if (foo -> sin_addr.s_addr == INADDR_LOOPBACK)
continue;
if (intbuf)
intbuf [ifix++] = foo -> sin_addr.s_addr;
else
if (intbuf) {
intbuf [ifix] = foo -> sin_addr.s_addr;
#ifdef USE_BPF
/* Open a bpf device for this interface */
{
int b;
char filename[50];
for (b = 0; 1; b++)
{
snprintf(filename, sizeof(filename),
"/dev/bpf%d", b);
if ((if_list[ifix].bpf =
open(filename, O_RDWR, 0)) < 0)
if (errno == EBUSY)
continue;
else
error ("Can't find free bpf: %m");
else
break;
}
if (ioctl(if_list[ifix].bpf,
BIOCSETIF, ifp) < 0)
error ("Can't BIOCSETIF on bpf: %m");
}
if_list[ifix].address = foo->sin_addr;
#endif
ifix++;
} else {
++ifcount;
}
}
}
/* If we haven't already filled our array, allocate it and go
@ -107,6 +159,13 @@ u_int32_t *get_interface_list (count)
"get_interface_list");
if (!intbuf)
return intbuf;
#ifdef USE_BPF
num_ifaces = ifcount;
if (!(if_list = (struct interface *)dmalloc
(num_ifaces * sizeof(*if_list),
"get_interface_list")))
error ("Can't allocate memory for if_list");
#endif
goto again;
}
*count = ifcount;
@ -215,3 +274,198 @@ void dispatch ()
} while (1);
}
#ifndef USE_BPF
int sendpkt (packet, raw, len, to, tolen)
struct packet *packet;
struct dhcp_packet *raw;
size_t len;
struct sockaddr *to;
int tolen;
{
return(sendto(packet->client_sock, raw, len, 0, to, tolen));
}
#else
static void IpChecksum(struct ip *ip);
static void UdpChecksum(struct ip *ip);
static u_int32_t Checksum(u_int16_t *buf, int nwords);
struct raw_packet
{
u_int16_t space;
struct ether_header en_hdr;
struct ip ip;
struct udphdr udp;
struct dhcp_packet dhcp;
};
int sendpkt (in_packet, raw, len, to, tolen)
struct packet *in_packet;
struct dhcp_packet *raw;
size_t len;
struct sockaddr *to;
int tolen;
{
int i, k;
struct iaddr dest;
struct subnet *subnet;
struct raw_packet out_packet;
struct raw_packet *const pkt = &out_packet;
/* Find local subnet, or else forward to gateway */
dest.len = 4;
memcpy(&dest.iabuf, &((struct sockaddr_in *) to)->sin_addr, dest.len);
if ((subnet = find_subnet(dest)) == NULL)
return(sendto(in_packet->client_sock, raw, len, 0, to, tolen));
/* Find interface corresponding to subnet */
for (i = 0; i < num_ifaces; i++)
{
for (k = 0; k < subnet->net.len
&& (dest.iabuf[k] & subnet->netmask.iabuf[k])
== (subnet->net.iabuf[k] & subnet->netmask.iabuf[k]);
k++);
if (k == subnet->net.len)
break;
}
if (i == num_ifaces)
return(sendto(in_packet->client_sock, raw, len, 0, to, tolen));
/* EtherNet header */
memset(pkt->en_hdr.ether_dhost, 0xff, sizeof(pkt->en_hdr.ether_dhost));
memset(pkt->en_hdr.ether_shost, 0x00, sizeof(pkt->en_hdr.ether_shost));
pkt->en_hdr.ether_type = ETHERTYPE_IP;
/* IP header (except for checksum) */
pkt->ip.ip_v = 4;
pkt->ip.ip_hl = 5;
pkt->ip.ip_tos = IPTOS_LOWDELAY;
pkt->ip.ip_len = htons(sizeof(pkt->ip) + sizeof(pkt->udp) + len);
pkt->ip.ip_id = 0;
pkt->ip.ip_off = 0;
pkt->ip.ip_ttl = 16;
pkt->ip.ip_p = IPPROTO_UDP;
pkt->ip.ip_sum = 0;
pkt->ip.ip_src = if_list[i].address;
inet_aton("255.255.255.255", &pkt->ip.ip_dst);
/* UDP header */
pkt->udp.uh_sport = htons(67); /* XXX! */
pkt->udp.uh_dport = in_packet->client_port;
pkt->udp.uh_ulen = htons(sizeof(pkt->udp) + len);
pkt->udp.uh_sum = 0;
/* DHCP packet */
pkt->dhcp = *raw;
/* Compute checksums */
UdpChecksum(&pkt->ip);
IpChecksum(&pkt->ip);
/* Fire it off */
if (write(if_list[i].bpf, &pkt->en_hdr,
ntohs(pkt->ip.ip_len) + sizeof(pkt->en_hdr)) < 0)
warn ("Can't deliver packet: write: %m");
return(0);
}
/*
* UdpChecksum()
*
* Recompute a UDP checksum on a packet
*
* UDP pseudo-header (prot = IPPROTO_UDP = 17):
*
* | source IP address |
* | dest. IP address |
* | zero | prot | UDP leng |
*
*/
static void
UdpChecksum(struct ip *ip)
{
struct udphdr *udp = (struct udphdr *) ((long *) ip + ip->ip_hl);
u_int32_t sum;
/* Pad with zero */
if (ntohs(udp->uh_ulen) & 0x1)
*((u_char *) udp + ntohs(udp->uh_ulen)) = 0;
/* Do pseudo-header first */
sum = Checksum((u_int16_t *) &ip->ip_src, 4);
sum += (u_int16_t) IPPROTO_UDP;
sum += (u_int16_t) ntohs(udp->uh_ulen);
/* Now do UDP packet itself */
udp->uh_sum = 0;
sum += Checksum((u_int16_t *) udp,
((u_int16_t) ntohs(udp->uh_ulen) + 1) >> 1);
/* Flip it & stick it */
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
sum = ~sum;
udp->uh_sum = htons(sum);
}
/*
* IpChecksum()
*
* Recompute an IP header checksum
*
*/
static void
IpChecksum(struct ip *ip)
{
u_int32_t sum;
/* Sum up IP header words */
ip->ip_sum = 0;
sum = Checksum((u_int16_t *) ip, ip->ip_hl * 2);
/* Flip it & stick it */
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
sum = ~sum;
ip->ip_sum = htons(sum);
}
/*
* Checksum()
*
* Do the one's complement sum thing over a range of words
* Ideally, this should get replaced by an assembly version.
*/
static u_int32_t
Checksum(u_int16_t *buf, int nwords)
{
u_int32_t sum = 0;
while (nwords--)
sum += (u_int16_t) ntohs(*buf++);
return(sum);
}
#endif

View File

@ -106,7 +106,7 @@ static int get_token (cfile)
ttok = read_string (cfile);
break;
}
if (isascii (c) && isdigit (c)) {
if ((isascii (c) && isdigit (c)) || c == '-') {
ttok = read_number (c, cfile);
break;
} else if (isascii (c) && isalpha (c)) {

View File

@ -1024,7 +1024,7 @@ TIME parse_date (cfile, bc)
skip_to_semi (cfile);
longjmp (*bc, 1);
}
tm.tm_mon = atoi (val);
tm.tm_mon = atoi (val) - 1;
/* Slash seperating month from day... */
token = next_token (&val, cfile);
@ -1093,9 +1093,12 @@ TIME parse_date (cfile, bc)
}
tm.tm_sec = atoi (val);
#ifndef BROKEN_TM_GMT
/* linux does not implement these yet */
tm.tm_zone = "GMT";
tm.tm_isdst = 0;
tm.tm_gmtoff = 0;
#endif
tm.tm_isdst = 0;
/* XXX */ /* We assume that mktime does not use tm_yday. */
tm.tm_yday = 0;

2
db.c
View File

@ -117,7 +117,7 @@ void new_lease_file ()
/* Make a temporary lease file... */
time (&t);
sprintf (newfname, "%s.%d", _PATH_DHCPD_DB, t & 32767);
sprintf (newfname, "%s.%d", _PATH_DHCPD_DB, (int) (t & 32767));
if ((db_file = fopen (newfname, "w")) == NULL) {
error ("Can't start new lease file: %m");
}

96
dhcp.c
View File

@ -83,6 +83,11 @@ void dhcpdiscover (packet)
{
struct lease *lease = find_lease (packet);
debug ("Received DHCPDISCOVER from %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
/* If we didn't find a lease, try to allocate one... */
if (!lease) {
lease = packet -> subnet -> last_lease;
@ -106,17 +111,29 @@ void dhcprequest (packet)
struct lease *lease = find_lease (packet);
struct iaddr cip;
/* If a client on our local network wants to renew a lease on
an address off our local network, NAK it. */
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
cip.len = 4;
memcpy (cip.iabuf,
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
4);
} else {
cip.len = 4;
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
}
debug ("Received DHCPREQUEST from %s for %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
piaddr (cip));
/* If a client on our local network wants to renew a lease on
an address off our local network, NAK it. */
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
if (!addr_eq (packet -> subnet -> net,
subnet_number (cip,
packet -> subnet -> netmask))) {
nak_lease (packet);
nak_lease (packet, &cip);
return;
}
}
@ -127,7 +144,7 @@ void dhcprequest (packet)
if (!addr_eq (packet -> subnet -> net,
subnet_number (cip,
packet -> subnet -> netmask))) {
nak_lease (packet);
nak_lease (packet, &cip);
return;
}
}
@ -149,7 +166,7 @@ void dhcprequest (packet)
/* If we didn't find a lease, don't try to allocate one... */
if (!lease) {
nak_lease (packet);
nak_lease (packet, &cip);
return;
}
@ -161,6 +178,12 @@ void dhcprelease (packet)
{
struct lease *lease = find_lease (packet);
debug ("Received DHCPRELEASE from %s for %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (packet -> raw -> ciaddr));
/* If we found a lease, release it. */
if (lease) {
release_lease (lease);
@ -171,6 +194,22 @@ void dhcpdecline (packet)
struct packet *packet;
{
struct lease *lease = find_lease (packet);
struct iaddr cip;
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
cip.len = 4;
memcpy (cip.iabuf,
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
4);
} else {
cip.len = 0;
}
debug ("Received DHCPDECLINE from %s for %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
piaddr (cip));
/* If we found a lease, mark it as unusable and complain. */
if (lease) {
@ -181,10 +220,17 @@ void dhcpdecline (packet)
void dhcpinform (packet)
struct packet *packet;
{
debug ("Received DHCPINFORM from %s for %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (packet -> raw -> ciaddr));
}
void nak_lease (packet)
void nak_lease (packet, cip)
struct packet *packet;
struct iaddr *cip;
{
struct sockaddr_in to;
int result;
@ -244,8 +290,8 @@ void nak_lease (packet)
to.sin_addr = raw.giaddr;
to.sin_port = server_port;
} else {
to.sin_addr.s_addr = INADDR_BROADCAST;
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
memcpy (&to.sin_addr.s_addr, cip->iabuf, 4);
to.sin_port = packet->client_port;
}
to.sin_family = AF_INET;
@ -254,14 +300,17 @@ void nak_lease (packet)
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending dhcp NAK to %s, port %d",
note ("Sending DHCPNAK to %s at IP address %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (to.sin_addr), htons (to.sin_port));
errno = 0;
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
0, (struct sockaddr *)&to, sizeof to);
result = sendpkt (packet, &raw, outgoing.packet_length,
(struct sockaddr *) &to, sizeof(to));
if (result < 0)
warn ("sendto: %m");
warn ("sendpkt: %m");
#ifdef DEBUG
dump_packet (packet);
@ -471,6 +520,15 @@ void ack_lease (packet, lease, offer, when)
options [DHO_DHCP_USER_CLASS_ID] -> tree = (struct tree *)0;
}
/* Sanity check the lease time. */
if ((lease->offered_expiry - cur_time) < 0)
putULong(lease_time_buf, packet->subnet->default_lease_time);
else if (lease -> offered_expiry - cur_time >
packet -> subnet -> max_lease_time)
putULong (lease_time_buf, packet -> subnet -> max_lease_time);
else
putULong(lease_time_buf, lease -> offered_expiry - cur_time);
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
@ -508,7 +566,7 @@ void ack_lease (packet, lease, offer, when)
/* Otherwise, broadcast it on the local network. */
} else {
to.sin_addr.s_addr = INADDR_BROADCAST;
memcpy (&to.sin_addr.s_addr, lease -> ip_addr.iabuf, 4);
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
}
@ -518,14 +576,18 @@ void ack_lease (packet, lease, offer, when)
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending dhcp reply to %s, port %d",
note ("Sending %s to %s at IP address %s",
offer == DHCPACK ? "DHCPACK" : "DHCPOFFER",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (to.sin_addr), htons (to.sin_port));
errno = 0;
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
0, (struct sockaddr *)&to, sizeof to);
result = sendpkt (packet, &raw, outgoing.packet_length,
(struct sockaddr *) &to, sizeof(to));
if (result < 0)
warn ("sendto: %m");
warn ("sendpkt: %m");
#ifdef DEBUG
dump_packet (packet);

View File

@ -179,9 +179,9 @@ int main (argc, argv, envp)
}
/* Write a pid file. */
if ((i = open (_PATH_DHCPD_PID, O_WRONLY | O_CREAT)) >= 0) {
if ((i = open (_PATH_DHCPD_PID, O_WRONLY | O_CREAT, 0640)) >= 0) {
char obuf [20];
sprintf (obuf, "%d\n", getpid ());
sprintf (obuf, "%d\n", (int)getpid ());
write (i, obuf, strlen (obuf));
close (i);
}

16
dhcpd.h
View File

@ -54,9 +54,9 @@
#include <ctype.h>
#include <time.h>
#include "osdep.h"
#include "dhcp.h"
#include "cdefs.h"
#include "osdep.h"
#include "tree.h"
#include "hash.h"
#include "inet.h"
@ -150,14 +150,21 @@ typedef unsigned char option_mask [16];
#define OPTION_SPACE(x) ((x) + 2 * ((x) / 255 + 1))
/* Default path to dhcpd config file. */
#ifndef _PATH_DHCPD_CONF
#ifdef DEBUG
#define _PATH_DHCPD_CONF "dhcpd.conf"
#define _PATH_DHCPD_DB "dhcpd.leases"
#else
#ifndef _PATH_DHCPD_CONF
#define _PATH_DHCPD_CONF "/etc/dhcpd.conf"
#endif
#ifndef _PATH_DHCPD_DB
#define _PATH_DHCPD_DB "/etc/dhcpd.leases"
#endif
#ifndef _PATH_DHCPD_PID
#define _PATH_DHCPD_PID "/var/run/dhcpd.pid"
#endif
#endif
#define MAX_TIME 0x7fffffff
@ -252,7 +259,7 @@ void dhcprequest PROTO ((struct packet *));
void dhcprelease PROTO ((struct packet *));
void dhcpdecline PROTO ((struct packet *));
void dhcpinform PROTO ((struct packet *));
void nak_lease PROTO ((struct packet *));
void nak_lease PROTO ((struct packet *, struct iaddr *cip));
void ack_lease PROTO ((struct packet *, struct lease *, unsigned char, TIME));
struct lease *find_lease PROTO ((struct packet *));
@ -309,8 +316,11 @@ void dump_raw PROTO ((unsigned char *, int));
/* socket.c */
u_int32_t *get_interface_list PROTO ((int *));
char *get_interface PROTO ((u_int32_t));
void listen_on PROTO ((u_int16_t, u_int32_t));
void dispatch PROTO ((void));
int sendpkt PROTO ((struct packet *, struct dhcp_packet *,
size_t, struct sockaddr *, int));
/* hash.c */
struct hash_table *new_hash PROTO ((void));

View File

@ -1,6 +1,6 @@
/* netbsd.h
/* bsdos.h
System dependencies for NetBSD... */
System dependencies for BSDI BSD/OS... */
/*
* Copyright (c) 1996 The Internet Software Consortium. All rights reserved.

View File

@ -54,9 +54,9 @@
#include <ctype.h>
#include <time.h>
#include "osdep.h"
#include "dhcp.h"
#include "cdefs.h"
#include "osdep.h"
#include "tree.h"
#include "hash.h"
#include "inet.h"
@ -150,14 +150,21 @@ typedef unsigned char option_mask [16];
#define OPTION_SPACE(x) ((x) + 2 * ((x) / 255 + 1))
/* Default path to dhcpd config file. */
#ifndef _PATH_DHCPD_CONF
#ifdef DEBUG
#define _PATH_DHCPD_CONF "dhcpd.conf"
#define _PATH_DHCPD_DB "dhcpd.leases"
#else
#ifndef _PATH_DHCPD_CONF
#define _PATH_DHCPD_CONF "/etc/dhcpd.conf"
#endif
#ifndef _PATH_DHCPD_DB
#define _PATH_DHCPD_DB "/etc/dhcpd.leases"
#endif
#ifndef _PATH_DHCPD_PID
#define _PATH_DHCPD_PID "/var/run/dhcpd.pid"
#endif
#endif
#define MAX_TIME 0x7fffffff
@ -252,7 +259,7 @@ void dhcprequest PROTO ((struct packet *));
void dhcprelease PROTO ((struct packet *));
void dhcpdecline PROTO ((struct packet *));
void dhcpinform PROTO ((struct packet *));
void nak_lease PROTO ((struct packet *));
void nak_lease PROTO ((struct packet *, struct iaddr *cip));
void ack_lease PROTO ((struct packet *, struct lease *, unsigned char, TIME));
struct lease *find_lease PROTO ((struct packet *));
@ -309,8 +316,11 @@ void dump_raw PROTO ((unsigned char *, int));
/* socket.c */
u_int32_t *get_interface_list PROTO ((int *));
char *get_interface PROTO ((u_int32_t));
void listen_on PROTO ((u_int16_t, u_int32_t));
void dispatch PROTO ((void));
int sendpkt PROTO ((struct packet *, struct dhcp_packet *,
size_t, struct sockaddr *, int));
/* hash.c */
struct hash_table *new_hash PROTO ((void));

View File

@ -48,3 +48,19 @@
#include "cf/netbsd.h"
#endif
#ifdef __FreeBSD__
#include "cf/freebsd.h"
#endif
#ifdef sun
#include "cf/sunos4.h"
#endif
#ifdef ultrix
#include "cf/ultrix.h"
#endif
#ifdef linux
#include "cf/linux.h"
#endif

View File

@ -173,12 +173,15 @@ void cons_options (inpacket, outpacket, options, overload)
/* XXX Maybe it would be safe to assume that we can send a packet
to the client that's as big as the one it sent us, even if it
didn't specify a large MTU. */
if (inpacket && inpacket -> options [DHO_DHCP_MAX_MESSAGE_SIZE].data)
if (inpacket && inpacket -> options [DHO_DHCP_MAX_MESSAGE_SIZE].data) {
main_buffer_size =
(getUShort (inpacket -> options
[DHO_DHCP_MAX_MESSAGE_SIZE].data)
- DHCP_FIXED_LEN);
else
/* Enforce a minimum packet size... */
if (main_buffer_size < (576 - DHCP_FIXED_LEN))
main_buffer_size = 576 - DHCP_FIXED_LEN;
} else
main_buffer_size = 576 - DHCP_FIXED_LEN;
/* Preload the option priority list with mandatory options. */

16
osdep.h
View File

@ -48,3 +48,19 @@
#include "cf/netbsd.h"
#endif
#ifdef __FreeBSD__
#include "cf/freebsd.h"
#endif
#ifdef sun
#include "cf/sunos4.h"
#endif
#ifdef ultrix
#include "cf/ultrix.h"
#endif
#ifdef linux
#include "cf/linux.h"
#endif

View File

@ -151,8 +151,11 @@ void bootp (packet)
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending bootp reply to %s, port %d",
inet_ntoa (to.sin_addr), to.sin_port);
note ("Sending BOOTREPLY to %s, address %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (packet -> raw -> yiaddr));
errno = 0;
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,

View File

@ -1024,7 +1024,7 @@ TIME parse_date (cfile, bc)
skip_to_semi (cfile);
longjmp (*bc, 1);
}
tm.tm_mon = atoi (val);
tm.tm_mon = atoi (val) - 1;
/* Slash seperating month from day... */
token = next_token (&val, cfile);
@ -1093,9 +1093,12 @@ TIME parse_date (cfile, bc)
}
tm.tm_sec = atoi (val);
#ifndef BROKEN_TM_GMT
/* linux does not implement these yet */
tm.tm_zone = "GMT";
tm.tm_isdst = 0;
tm.tm_gmtoff = 0;
#endif
tm.tm_isdst = 0;
/* XXX */ /* We assume that mktime does not use tm_yday. */
tm.tm_yday = 0;

View File

@ -117,7 +117,7 @@ void new_lease_file ()
/* Make a temporary lease file... */
time (&t);
sprintf (newfname, "%s.%d", _PATH_DHCPD_DB, t & 32767);
sprintf (newfname, "%s.%d", _PATH_DHCPD_DB, (int) (t & 32767));
if ((db_file = fopen (newfname, "w")) == NULL) {
error ("Can't start new lease file: %m");
}

View File

@ -83,6 +83,11 @@ void dhcpdiscover (packet)
{
struct lease *lease = find_lease (packet);
debug ("Received DHCPDISCOVER from %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
/* If we didn't find a lease, try to allocate one... */
if (!lease) {
lease = packet -> subnet -> last_lease;
@ -106,17 +111,29 @@ void dhcprequest (packet)
struct lease *lease = find_lease (packet);
struct iaddr cip;
/* If a client on our local network wants to renew a lease on
an address off our local network, NAK it. */
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
cip.len = 4;
memcpy (cip.iabuf,
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
4);
} else {
cip.len = 4;
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
}
debug ("Received DHCPREQUEST from %s for %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
piaddr (cip));
/* If a client on our local network wants to renew a lease on
an address off our local network, NAK it. */
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
if (!addr_eq (packet -> subnet -> net,
subnet_number (cip,
packet -> subnet -> netmask))) {
nak_lease (packet);
nak_lease (packet, &cip);
return;
}
}
@ -127,7 +144,7 @@ void dhcprequest (packet)
if (!addr_eq (packet -> subnet -> net,
subnet_number (cip,
packet -> subnet -> netmask))) {
nak_lease (packet);
nak_lease (packet, &cip);
return;
}
}
@ -149,7 +166,7 @@ void dhcprequest (packet)
/* If we didn't find a lease, don't try to allocate one... */
if (!lease) {
nak_lease (packet);
nak_lease (packet, &cip);
return;
}
@ -161,6 +178,12 @@ void dhcprelease (packet)
{
struct lease *lease = find_lease (packet);
debug ("Received DHCPRELEASE from %s for %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (packet -> raw -> ciaddr));
/* If we found a lease, release it. */
if (lease) {
release_lease (lease);
@ -171,6 +194,22 @@ void dhcpdecline (packet)
struct packet *packet;
{
struct lease *lease = find_lease (packet);
struct iaddr cip;
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
cip.len = 4;
memcpy (cip.iabuf,
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
4);
} else {
cip.len = 0;
}
debug ("Received DHCPDECLINE from %s for %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
piaddr (cip));
/* If we found a lease, mark it as unusable and complain. */
if (lease) {
@ -181,10 +220,17 @@ void dhcpdecline (packet)
void dhcpinform (packet)
struct packet *packet;
{
debug ("Received DHCPINFORM from %s for %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (packet -> raw -> ciaddr));
}
void nak_lease (packet)
void nak_lease (packet, cip)
struct packet *packet;
struct iaddr *cip;
{
struct sockaddr_in to;
int result;
@ -244,8 +290,8 @@ void nak_lease (packet)
to.sin_addr = raw.giaddr;
to.sin_port = server_port;
} else {
to.sin_addr.s_addr = INADDR_BROADCAST;
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
memcpy (&to.sin_addr.s_addr, cip->iabuf, 4);
to.sin_port = packet->client_port;
}
to.sin_family = AF_INET;
@ -254,14 +300,17 @@ void nak_lease (packet)
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending dhcp NAK to %s, port %d",
note ("Sending DHCPNAK to %s at IP address %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (to.sin_addr), htons (to.sin_port));
errno = 0;
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
0, (struct sockaddr *)&to, sizeof to);
result = sendpkt (packet, &raw, outgoing.packet_length,
(struct sockaddr *) &to, sizeof(to));
if (result < 0)
warn ("sendto: %m");
warn ("sendpkt: %m");
#ifdef DEBUG
dump_packet (packet);
@ -471,6 +520,15 @@ void ack_lease (packet, lease, offer, when)
options [DHO_DHCP_USER_CLASS_ID] -> tree = (struct tree *)0;
}
/* Sanity check the lease time. */
if ((lease->offered_expiry - cur_time) < 0)
putULong(lease_time_buf, packet->subnet->default_lease_time);
else if (lease -> offered_expiry - cur_time >
packet -> subnet -> max_lease_time)
putULong (lease_time_buf, packet -> subnet -> max_lease_time);
else
putULong(lease_time_buf, lease -> offered_expiry - cur_time);
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
@ -508,7 +566,7 @@ void ack_lease (packet, lease, offer, when)
/* Otherwise, broadcast it on the local network. */
} else {
to.sin_addr.s_addr = INADDR_BROADCAST;
memcpy (&to.sin_addr.s_addr, lease -> ip_addr.iabuf, 4);
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
}
@ -518,14 +576,18 @@ void ack_lease (packet, lease, offer, when)
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending dhcp reply to %s, port %d",
note ("Sending %s to %s at IP address %s",
offer == DHCPACK ? "DHCPACK" : "DHCPOFFER",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (to.sin_addr), htons (to.sin_port));
errno = 0;
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
0, (struct sockaddr *)&to, sizeof to);
result = sendpkt (packet, &raw, outgoing.packet_length,
(struct sockaddr *) &to, sizeof(to));
if (result < 0)
warn ("sendto: %m");
warn ("sendpkt: %m");
#ifdef DEBUG
dump_packet (packet);

View File

@ -179,9 +179,9 @@ int main (argc, argv, envp)
}
/* Write a pid file. */
if ((i = open (_PATH_DHCPD_PID, O_WRONLY | O_CREAT)) >= 0) {
if ((i = open (_PATH_DHCPD_PID, O_WRONLY | O_CREAT, 0640)) >= 0) {
char obuf [20];
sprintf (obuf, "%d\n", getpid ());
sprintf (obuf, "%d\n", (int)getpid ());
write (i, obuf, strlen (obuf));
close (i);
}

260
socket.c
View File

@ -48,6 +48,27 @@ static char copyright[] =
#include "dhcpd.h"
#include <sys/ioctl.h>
#ifdef USE_BPF
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/if_ether.h>
struct interface {
struct in_addr address;
int bpf;
};
static struct interface *if_list;
static int num_ifaces;
#endif
/* List of sockets we're accepting packets on... */
struct socklist {
struct socklist *next;
@ -86,17 +107,48 @@ u_int32_t *get_interface_list (count)
second time to copy them into an array of addresses. */
for (i = 0; i < ic.ifc_len;) {
struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
#ifdef HAVE_SIN_LEN
i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
#else
i += sizeof *ifp;
#endif
if (ifp -> ifr_addr.sa_family == AF_INET) {
struct sockaddr_in *foo =
(struct sockaddr_in *)(&ifp -> ifr_addr);
/* We don't want the loopback interface. */
if (foo -> sin_addr.s_addr == INADDR_LOOPBACK)
continue;
if (intbuf)
intbuf [ifix++] = foo -> sin_addr.s_addr;
else
if (intbuf) {
intbuf [ifix] = foo -> sin_addr.s_addr;
#ifdef USE_BPF
/* Open a bpf device for this interface */
{
int b;
char filename[50];
for (b = 0; 1; b++)
{
snprintf(filename, sizeof(filename),
"/dev/bpf%d", b);
if ((if_list[ifix].bpf =
open(filename, O_RDWR, 0)) < 0)
if (errno == EBUSY)
continue;
else
error ("Can't find free bpf: %m");
else
break;
}
if (ioctl(if_list[ifix].bpf,
BIOCSETIF, ifp) < 0)
error ("Can't BIOCSETIF on bpf: %m");
}
if_list[ifix].address = foo->sin_addr;
#endif
ifix++;
} else {
++ifcount;
}
}
}
/* If we haven't already filled our array, allocate it and go
@ -107,6 +159,13 @@ u_int32_t *get_interface_list (count)
"get_interface_list");
if (!intbuf)
return intbuf;
#ifdef USE_BPF
num_ifaces = ifcount;
if (!(if_list = (struct interface *)dmalloc
(num_ifaces * sizeof(*if_list),
"get_interface_list")))
error ("Can't allocate memory for if_list");
#endif
goto again;
}
*count = ifcount;
@ -215,3 +274,198 @@ void dispatch ()
} while (1);
}
#ifndef USE_BPF
int sendpkt (packet, raw, len, to, tolen)
struct packet *packet;
struct dhcp_packet *raw;
size_t len;
struct sockaddr *to;
int tolen;
{
return(sendto(packet->client_sock, raw, len, 0, to, tolen));
}
#else
static void IpChecksum(struct ip *ip);
static void UdpChecksum(struct ip *ip);
static u_int32_t Checksum(u_int16_t *buf, int nwords);
struct raw_packet
{
u_int16_t space;
struct ether_header en_hdr;
struct ip ip;
struct udphdr udp;
struct dhcp_packet dhcp;
};
int sendpkt (in_packet, raw, len, to, tolen)
struct packet *in_packet;
struct dhcp_packet *raw;
size_t len;
struct sockaddr *to;
int tolen;
{
int i, k;
struct iaddr dest;
struct subnet *subnet;
struct raw_packet out_packet;
struct raw_packet *const pkt = &out_packet;
/* Find local subnet, or else forward to gateway */
dest.len = 4;
memcpy(&dest.iabuf, &((struct sockaddr_in *) to)->sin_addr, dest.len);
if ((subnet = find_subnet(dest)) == NULL)
return(sendto(in_packet->client_sock, raw, len, 0, to, tolen));
/* Find interface corresponding to subnet */
for (i = 0; i < num_ifaces; i++)
{
for (k = 0; k < subnet->net.len
&& (dest.iabuf[k] & subnet->netmask.iabuf[k])
== (subnet->net.iabuf[k] & subnet->netmask.iabuf[k]);
k++);
if (k == subnet->net.len)
break;
}
if (i == num_ifaces)
return(sendto(in_packet->client_sock, raw, len, 0, to, tolen));
/* EtherNet header */
memset(pkt->en_hdr.ether_dhost, 0xff, sizeof(pkt->en_hdr.ether_dhost));
memset(pkt->en_hdr.ether_shost, 0x00, sizeof(pkt->en_hdr.ether_shost));
pkt->en_hdr.ether_type = ETHERTYPE_IP;
/* IP header (except for checksum) */
pkt->ip.ip_v = 4;
pkt->ip.ip_hl = 5;
pkt->ip.ip_tos = IPTOS_LOWDELAY;
pkt->ip.ip_len = htons(sizeof(pkt->ip) + sizeof(pkt->udp) + len);
pkt->ip.ip_id = 0;
pkt->ip.ip_off = 0;
pkt->ip.ip_ttl = 16;
pkt->ip.ip_p = IPPROTO_UDP;
pkt->ip.ip_sum = 0;
pkt->ip.ip_src = if_list[i].address;
inet_aton("255.255.255.255", &pkt->ip.ip_dst);
/* UDP header */
pkt->udp.uh_sport = htons(67); /* XXX! */
pkt->udp.uh_dport = in_packet->client_port;
pkt->udp.uh_ulen = htons(sizeof(pkt->udp) + len);
pkt->udp.uh_sum = 0;
/* DHCP packet */
pkt->dhcp = *raw;
/* Compute checksums */
UdpChecksum(&pkt->ip);
IpChecksum(&pkt->ip);
/* Fire it off */
if (write(if_list[i].bpf, &pkt->en_hdr,
ntohs(pkt->ip.ip_len) + sizeof(pkt->en_hdr)) < 0)
warn ("Can't deliver packet: write: %m");
return(0);
}
/*
* UdpChecksum()
*
* Recompute a UDP checksum on a packet
*
* UDP pseudo-header (prot = IPPROTO_UDP = 17):
*
* | source IP address |
* | dest. IP address |
* | zero | prot | UDP leng |
*
*/
static void
UdpChecksum(struct ip *ip)
{
struct udphdr *udp = (struct udphdr *) ((long *) ip + ip->ip_hl);
u_int32_t sum;
/* Pad with zero */
if (ntohs(udp->uh_ulen) & 0x1)
*((u_char *) udp + ntohs(udp->uh_ulen)) = 0;
/* Do pseudo-header first */
sum = Checksum((u_int16_t *) &ip->ip_src, 4);
sum += (u_int16_t) IPPROTO_UDP;
sum += (u_int16_t) ntohs(udp->uh_ulen);
/* Now do UDP packet itself */
udp->uh_sum = 0;
sum += Checksum((u_int16_t *) udp,
((u_int16_t) ntohs(udp->uh_ulen) + 1) >> 1);
/* Flip it & stick it */
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
sum = ~sum;
udp->uh_sum = htons(sum);
}
/*
* IpChecksum()
*
* Recompute an IP header checksum
*
*/
static void
IpChecksum(struct ip *ip)
{
u_int32_t sum;
/* Sum up IP header words */
ip->ip_sum = 0;
sum = Checksum((u_int16_t *) ip, ip->ip_hl * 2);
/* Flip it & stick it */
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
sum = ~sum;
ip->ip_sum = htons(sum);
}
/*
* Checksum()
*
* Do the one's complement sum thing over a range of words
* Ideally, this should get replaced by an assembly version.
*/
static u_int32_t
Checksum(u_int16_t *buf, int nwords)
{
u_int32_t sum = 0;
while (nwords--)
sum += (u_int16_t) ntohs(*buf++);
return(sum);
}
#endif