mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-30 05:47:45 +00:00
Various user-provided patches
This commit is contained in:
parent
48695f7d76
commit
a8b53b4220
7
Makefile
7
Makefile
@ -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)
|
||||
|
20
README
20
README
@ -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
|
||||
|
7
bootp.c
7
bootp.c
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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. */
|
||||
|
258
common/socket.c
258
common/socket.c
@ -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,19 +107,50 @@ 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;
|
||||
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
|
||||
again. */
|
||||
if (!intbuf) {
|
||||
@ -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;
|
||||
|
2
db.c
2
db.c
@ -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
96
dhcp.c
@ -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);
|
||||
|
4
dhcpd.c
4
dhcpd.c
@ -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
16
dhcpd.h
@ -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));
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
16
osdep.h
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
258
socket.c
258
socket.c
@ -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,19 +107,50 @@ 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;
|
||||
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
|
||||
again. */
|
||||
if (!intbuf) {
|
||||
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user