Commit a8b53b42 authored by Ted Lemon's avatar Ted Lemon
Browse files

Various user-provided patches

parent 48695f7d
......@@ -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
......@@ -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)
......@@ -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
......
......@@ -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,
......
/* netbsd.h
/* bsdos.h
System dependencies for NetBSD... */
System dependencies for BSDI BSD/OS... */
/*
* Copyright (c) 1996 The Internet Software Consortium. All rights reserved.
......
......@@ -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)) {
......
......@@ -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. */
......
......@@ -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
......@@ -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)) {
......
......@@ -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;
......
......@@ -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");
}
......
......@@ -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