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:
7
Makefile
7
Makefile
@@ -8,12 +8,15 @@ all: dhcpd dhclient
|
|||||||
|
|
||||||
.include <bsd.prog.mk>
|
.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
|
-Wno-uninitialized -Werror
|
||||||
|
|
||||||
dhclient: dhclient.o confpars.o alloc.o memory.o options.o \
|
dhclient: dhclient.o confpars.o alloc.o memory.o options.o \
|
||||||
hash.o tables.o inet.o convert.o conflex.o errwarn.o \
|
hash.o tables.o inet.o convert.o conflex.o errwarn.o \
|
||||||
tree.o print.o db.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 \
|
hash.o tables.o inet.o convert.o conflex.o errwarn.o \
|
||||||
print.o tree.o db.o
|
print.o tree.o db.o
|
||||||
|
@@ -11,7 +11,7 @@ DEBUG=-g
|
|||||||
CFLAGS=$(DEBUG)
|
CFLAGS=$(DEBUG)
|
||||||
|
|
||||||
dhcpd: $(OBJS) $(COBJ)
|
dhcpd: $(OBJS) $(COBJ)
|
||||||
cc -o dhcpd $(OBJS) $(COBJ)
|
$(CC) -o dhcpd $(OBJS) $(COBJ)
|
||||||
|
|
||||||
dhclient: dhclient.o $(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
|
dhcpd and told me where it was busted, or, later on, that it wasn't
|
||||||
busted anymore.
|
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
|
BUGS
|
||||||
|
|
||||||
Currently, ISC dhcpd supports the DHCP protocol strictly the standard
|
Currently, ISC dhcpd supports the DHCP protocol strictly the standard
|
||||||
|
7
bootp.c
7
bootp.c
@@ -151,8 +151,11 @@ void bootp (packet)
|
|||||||
#endif
|
#endif
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
||||||
|
|
||||||
note ("Sending bootp reply to %s, port %d",
|
note ("Sending BOOTREPLY to %s, address %s",
|
||||||
inet_ntoa (to.sin_addr), to.sin_port);
|
print_hw_addr (packet -> raw -> htype,
|
||||||
|
packet -> raw -> hlen,
|
||||||
|
packet -> raw -> chaddr),
|
||||||
|
inet_ntoa (packet -> raw -> yiaddr));
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
|
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.
|
* Copyright (c) 1996 The Internet Software Consortium. All rights reserved.
|
||||||
|
@@ -106,7 +106,7 @@ static int get_token (cfile)
|
|||||||
ttok = read_string (cfile);
|
ttok = read_string (cfile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (isascii (c) && isdigit (c)) {
|
if ((isascii (c) && isdigit (c)) || c == '-') {
|
||||||
ttok = read_number (c, cfile);
|
ttok = read_number (c, cfile);
|
||||||
break;
|
break;
|
||||||
} else if (isascii (c) && isalpha (c)) {
|
} 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
|
/* 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
|
to the client that's as big as the one it sent us, even if it
|
||||||
didn't specify a large MTU. */
|
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 =
|
main_buffer_size =
|
||||||
(getUShort (inpacket -> options
|
(getUShort (inpacket -> options
|
||||||
[DHO_DHCP_MAX_MESSAGE_SIZE].data)
|
[DHO_DHCP_MAX_MESSAGE_SIZE].data)
|
||||||
- DHCP_FIXED_LEN);
|
- 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;
|
main_buffer_size = 576 - DHCP_FIXED_LEN;
|
||||||
|
|
||||||
/* Preload the option priority list with mandatory options. */
|
/* 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 "dhcpd.h"
|
||||||
#include <sys/ioctl.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... */
|
/* List of sockets we're accepting packets on... */
|
||||||
struct socklist {
|
struct socklist {
|
||||||
struct socklist *next;
|
struct socklist *next;
|
||||||
@@ -86,19 +107,50 @@ u_int32_t *get_interface_list (count)
|
|||||||
second time to copy them into an array of addresses. */
|
second time to copy them into an array of addresses. */
|
||||||
for (i = 0; i < ic.ifc_len;) {
|
for (i = 0; i < ic.ifc_len;) {
|
||||||
struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
|
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;
|
i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
|
||||||
|
#else
|
||||||
|
i += sizeof *ifp;
|
||||||
|
#endif
|
||||||
if (ifp -> ifr_addr.sa_family == AF_INET) {
|
if (ifp -> ifr_addr.sa_family == AF_INET) {
|
||||||
struct sockaddr_in *foo =
|
struct sockaddr_in *foo =
|
||||||
(struct sockaddr_in *)(&ifp -> ifr_addr);
|
(struct sockaddr_in *)(&ifp -> ifr_addr);
|
||||||
/* We don't want the loopback interface. */
|
/* We don't want the loopback interface. */
|
||||||
if (foo -> sin_addr.s_addr == INADDR_LOOPBACK)
|
if (foo -> sin_addr.s_addr == INADDR_LOOPBACK)
|
||||||
continue;
|
continue;
|
||||||
if (intbuf)
|
if (intbuf) {
|
||||||
intbuf [ifix++] = foo -> sin_addr.s_addr;
|
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
|
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;
|
++ifcount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* If we haven't already filled our array, allocate it and go
|
/* If we haven't already filled our array, allocate it and go
|
||||||
again. */
|
again. */
|
||||||
if (!intbuf) {
|
if (!intbuf) {
|
||||||
@@ -107,6 +159,13 @@ u_int32_t *get_interface_list (count)
|
|||||||
"get_interface_list");
|
"get_interface_list");
|
||||||
if (!intbuf)
|
if (!intbuf)
|
||||||
return 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;
|
goto again;
|
||||||
}
|
}
|
||||||
*count = ifcount;
|
*count = ifcount;
|
||||||
@@ -215,3 +274,198 @@ void dispatch ()
|
|||||||
} while (1);
|
} 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);
|
ttok = read_string (cfile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (isascii (c) && isdigit (c)) {
|
if ((isascii (c) && isdigit (c)) || c == '-') {
|
||||||
ttok = read_number (c, cfile);
|
ttok = read_number (c, cfile);
|
||||||
break;
|
break;
|
||||||
} else if (isascii (c) && isalpha (c)) {
|
} else if (isascii (c) && isalpha (c)) {
|
||||||
|
@@ -1024,7 +1024,7 @@ TIME parse_date (cfile, bc)
|
|||||||
skip_to_semi (cfile);
|
skip_to_semi (cfile);
|
||||||
longjmp (*bc, 1);
|
longjmp (*bc, 1);
|
||||||
}
|
}
|
||||||
tm.tm_mon = atoi (val);
|
tm.tm_mon = atoi (val) - 1;
|
||||||
|
|
||||||
/* Slash seperating month from day... */
|
/* Slash seperating month from day... */
|
||||||
token = next_token (&val, cfile);
|
token = next_token (&val, cfile);
|
||||||
@@ -1093,9 +1093,12 @@ TIME parse_date (cfile, bc)
|
|||||||
}
|
}
|
||||||
tm.tm_sec = atoi (val);
|
tm.tm_sec = atoi (val);
|
||||||
|
|
||||||
|
#ifndef BROKEN_TM_GMT
|
||||||
|
/* linux does not implement these yet */
|
||||||
tm.tm_zone = "GMT";
|
tm.tm_zone = "GMT";
|
||||||
tm.tm_isdst = 0;
|
|
||||||
tm.tm_gmtoff = 0;
|
tm.tm_gmtoff = 0;
|
||||||
|
#endif
|
||||||
|
tm.tm_isdst = 0;
|
||||||
|
|
||||||
/* XXX */ /* We assume that mktime does not use tm_yday. */
|
/* XXX */ /* We assume that mktime does not use tm_yday. */
|
||||||
tm.tm_yday = 0;
|
tm.tm_yday = 0;
|
||||||
|
2
db.c
2
db.c
@@ -117,7 +117,7 @@ void new_lease_file ()
|
|||||||
|
|
||||||
/* Make a temporary lease file... */
|
/* Make a temporary lease file... */
|
||||||
time (&t);
|
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) {
|
if ((db_file = fopen (newfname, "w")) == NULL) {
|
||||||
error ("Can't start new lease file: %m");
|
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);
|
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 we didn't find a lease, try to allocate one... */
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
lease = packet -> subnet -> last_lease;
|
lease = packet -> subnet -> last_lease;
|
||||||
@@ -106,17 +111,29 @@ void dhcprequest (packet)
|
|||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
struct iaddr cip;
|
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) {
|
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
||||||
cip.len = 4;
|
cip.len = 4;
|
||||||
memcpy (cip.iabuf,
|
memcpy (cip.iabuf,
|
||||||
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
|
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
|
||||||
4);
|
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,
|
if (!addr_eq (packet -> subnet -> net,
|
||||||
subnet_number (cip,
|
subnet_number (cip,
|
||||||
packet -> subnet -> netmask))) {
|
packet -> subnet -> netmask))) {
|
||||||
nak_lease (packet);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +144,7 @@ void dhcprequest (packet)
|
|||||||
if (!addr_eq (packet -> subnet -> net,
|
if (!addr_eq (packet -> subnet -> net,
|
||||||
subnet_number (cip,
|
subnet_number (cip,
|
||||||
packet -> subnet -> netmask))) {
|
packet -> subnet -> netmask))) {
|
||||||
nak_lease (packet);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +166,7 @@ void dhcprequest (packet)
|
|||||||
|
|
||||||
/* If we didn't find a lease, don't try to allocate one... */
|
/* If we didn't find a lease, don't try to allocate one... */
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
nak_lease (packet);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +178,12 @@ void dhcprelease (packet)
|
|||||||
{
|
{
|
||||||
struct lease *lease = find_lease (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 we found a lease, release it. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
release_lease (lease);
|
release_lease (lease);
|
||||||
@@ -171,6 +194,22 @@ void dhcpdecline (packet)
|
|||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
struct lease *lease = find_lease (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 we found a lease, mark it as unusable and complain. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
@@ -181,10 +220,17 @@ void dhcpdecline (packet)
|
|||||||
void dhcpinform (packet)
|
void dhcpinform (packet)
|
||||||
struct packet *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 packet *packet;
|
||||||
|
struct iaddr *cip;
|
||||||
{
|
{
|
||||||
struct sockaddr_in to;
|
struct sockaddr_in to;
|
||||||
int result;
|
int result;
|
||||||
@@ -244,8 +290,8 @@ void nak_lease (packet)
|
|||||||
to.sin_addr = raw.giaddr;
|
to.sin_addr = raw.giaddr;
|
||||||
to.sin_port = server_port;
|
to.sin_port = server_port;
|
||||||
} else {
|
} else {
|
||||||
to.sin_addr.s_addr = INADDR_BROADCAST;
|
memcpy (&to.sin_addr.s_addr, cip->iabuf, 4);
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
to.sin_port = packet->client_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
to.sin_family = AF_INET;
|
to.sin_family = AF_INET;
|
||||||
@@ -254,14 +300,17 @@ void nak_lease (packet)
|
|||||||
#endif
|
#endif
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
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));
|
inet_ntoa (to.sin_addr), htons (to.sin_port));
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
|
result = sendpkt (packet, &raw, outgoing.packet_length,
|
||||||
0, (struct sockaddr *)&to, sizeof to);
|
(struct sockaddr *) &to, sizeof(to));
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
warn ("sendto: %m");
|
warn ("sendpkt: %m");
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
dump_packet (packet);
|
dump_packet (packet);
|
||||||
@@ -471,6 +520,15 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
options [DHO_DHCP_USER_CLASS_ID] -> tree = (struct tree *)0;
|
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);
|
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
|
||||||
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
|
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
|
||||||
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
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. */
|
/* Otherwise, broadcast it on the local network. */
|
||||||
} else {
|
} 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 */
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,14 +576,18 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
#endif
|
#endif
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
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));
|
inet_ntoa (to.sin_addr), htons (to.sin_port));
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
|
result = sendpkt (packet, &raw, outgoing.packet_length,
|
||||||
0, (struct sockaddr *)&to, sizeof to);
|
(struct sockaddr *) &to, sizeof(to));
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
warn ("sendto: %m");
|
warn ("sendpkt: %m");
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
dump_packet (packet);
|
dump_packet (packet);
|
||||||
|
4
dhcpd.c
4
dhcpd.c
@@ -179,9 +179,9 @@ int main (argc, argv, envp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write a pid file. */
|
/* 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];
|
char obuf [20];
|
||||||
sprintf (obuf, "%d\n", getpid ());
|
sprintf (obuf, "%d\n", (int)getpid ());
|
||||||
write (i, obuf, strlen (obuf));
|
write (i, obuf, strlen (obuf));
|
||||||
close (i);
|
close (i);
|
||||||
}
|
}
|
||||||
|
16
dhcpd.h
16
dhcpd.h
@@ -54,9 +54,9 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "osdep.h"
|
||||||
#include "dhcp.h"
|
#include "dhcp.h"
|
||||||
#include "cdefs.h"
|
#include "cdefs.h"
|
||||||
#include "osdep.h"
|
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "inet.h"
|
#include "inet.h"
|
||||||
@@ -150,14 +150,21 @@ typedef unsigned char option_mask [16];
|
|||||||
#define OPTION_SPACE(x) ((x) + 2 * ((x) / 255 + 1))
|
#define OPTION_SPACE(x) ((x) + 2 * ((x) / 255 + 1))
|
||||||
|
|
||||||
/* Default path to dhcpd config file. */
|
/* Default path to dhcpd config file. */
|
||||||
#ifndef _PATH_DHCPD_CONF
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define _PATH_DHCPD_CONF "dhcpd.conf"
|
#define _PATH_DHCPD_CONF "dhcpd.conf"
|
||||||
#define _PATH_DHCPD_DB "dhcpd.leases"
|
#define _PATH_DHCPD_DB "dhcpd.leases"
|
||||||
#else
|
#else
|
||||||
|
#ifndef _PATH_DHCPD_CONF
|
||||||
#define _PATH_DHCPD_CONF "/etc/dhcpd.conf"
|
#define _PATH_DHCPD_CONF "/etc/dhcpd.conf"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _PATH_DHCPD_DB
|
||||||
#define _PATH_DHCPD_DB "/etc/dhcpd.leases"
|
#define _PATH_DHCPD_DB "/etc/dhcpd.leases"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _PATH_DHCPD_PID
|
||||||
|
#define _PATH_DHCPD_PID "/var/run/dhcpd.pid"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_TIME 0x7fffffff
|
#define MAX_TIME 0x7fffffff
|
||||||
@@ -252,7 +259,7 @@ void dhcprequest PROTO ((struct packet *));
|
|||||||
void dhcprelease PROTO ((struct packet *));
|
void dhcprelease PROTO ((struct packet *));
|
||||||
void dhcpdecline PROTO ((struct packet *));
|
void dhcpdecline PROTO ((struct packet *));
|
||||||
void dhcpinform 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));
|
void ack_lease PROTO ((struct packet *, struct lease *, unsigned char, TIME));
|
||||||
struct lease *find_lease PROTO ((struct packet *));
|
struct lease *find_lease PROTO ((struct packet *));
|
||||||
|
|
||||||
@@ -309,8 +316,11 @@ void dump_raw PROTO ((unsigned char *, int));
|
|||||||
|
|
||||||
/* socket.c */
|
/* socket.c */
|
||||||
u_int32_t *get_interface_list PROTO ((int *));
|
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 listen_on PROTO ((u_int16_t, u_int32_t));
|
||||||
void dispatch PROTO ((void));
|
void dispatch PROTO ((void));
|
||||||
|
int sendpkt PROTO ((struct packet *, struct dhcp_packet *,
|
||||||
|
size_t, struct sockaddr *, int));
|
||||||
|
|
||||||
/* hash.c */
|
/* hash.c */
|
||||||
struct hash_table *new_hash PROTO ((void));
|
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.
|
* Copyright (c) 1996 The Internet Software Consortium. All rights reserved.
|
||||||
|
@@ -54,9 +54,9 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "osdep.h"
|
||||||
#include "dhcp.h"
|
#include "dhcp.h"
|
||||||
#include "cdefs.h"
|
#include "cdefs.h"
|
||||||
#include "osdep.h"
|
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "inet.h"
|
#include "inet.h"
|
||||||
@@ -150,14 +150,21 @@ typedef unsigned char option_mask [16];
|
|||||||
#define OPTION_SPACE(x) ((x) + 2 * ((x) / 255 + 1))
|
#define OPTION_SPACE(x) ((x) + 2 * ((x) / 255 + 1))
|
||||||
|
|
||||||
/* Default path to dhcpd config file. */
|
/* Default path to dhcpd config file. */
|
||||||
#ifndef _PATH_DHCPD_CONF
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define _PATH_DHCPD_CONF "dhcpd.conf"
|
#define _PATH_DHCPD_CONF "dhcpd.conf"
|
||||||
#define _PATH_DHCPD_DB "dhcpd.leases"
|
#define _PATH_DHCPD_DB "dhcpd.leases"
|
||||||
#else
|
#else
|
||||||
|
#ifndef _PATH_DHCPD_CONF
|
||||||
#define _PATH_DHCPD_CONF "/etc/dhcpd.conf"
|
#define _PATH_DHCPD_CONF "/etc/dhcpd.conf"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _PATH_DHCPD_DB
|
||||||
#define _PATH_DHCPD_DB "/etc/dhcpd.leases"
|
#define _PATH_DHCPD_DB "/etc/dhcpd.leases"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _PATH_DHCPD_PID
|
||||||
|
#define _PATH_DHCPD_PID "/var/run/dhcpd.pid"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_TIME 0x7fffffff
|
#define MAX_TIME 0x7fffffff
|
||||||
@@ -252,7 +259,7 @@ void dhcprequest PROTO ((struct packet *));
|
|||||||
void dhcprelease PROTO ((struct packet *));
|
void dhcprelease PROTO ((struct packet *));
|
||||||
void dhcpdecline PROTO ((struct packet *));
|
void dhcpdecline PROTO ((struct packet *));
|
||||||
void dhcpinform 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));
|
void ack_lease PROTO ((struct packet *, struct lease *, unsigned char, TIME));
|
||||||
struct lease *find_lease PROTO ((struct packet *));
|
struct lease *find_lease PROTO ((struct packet *));
|
||||||
|
|
||||||
@@ -309,8 +316,11 @@ void dump_raw PROTO ((unsigned char *, int));
|
|||||||
|
|
||||||
/* socket.c */
|
/* socket.c */
|
||||||
u_int32_t *get_interface_list PROTO ((int *));
|
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 listen_on PROTO ((u_int16_t, u_int32_t));
|
||||||
void dispatch PROTO ((void));
|
void dispatch PROTO ((void));
|
||||||
|
int sendpkt PROTO ((struct packet *, struct dhcp_packet *,
|
||||||
|
size_t, struct sockaddr *, int));
|
||||||
|
|
||||||
/* hash.c */
|
/* hash.c */
|
||||||
struct hash_table *new_hash PROTO ((void));
|
struct hash_table *new_hash PROTO ((void));
|
||||||
|
@@ -48,3 +48,19 @@
|
|||||||
#include "cf/netbsd.h"
|
#include "cf/netbsd.h"
|
||||||
#endif
|
#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
|
/* 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
|
to the client that's as big as the one it sent us, even if it
|
||||||
didn't specify a large MTU. */
|
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 =
|
main_buffer_size =
|
||||||
(getUShort (inpacket -> options
|
(getUShort (inpacket -> options
|
||||||
[DHO_DHCP_MAX_MESSAGE_SIZE].data)
|
[DHO_DHCP_MAX_MESSAGE_SIZE].data)
|
||||||
- DHCP_FIXED_LEN);
|
- 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;
|
main_buffer_size = 576 - DHCP_FIXED_LEN;
|
||||||
|
|
||||||
/* Preload the option priority list with mandatory options. */
|
/* Preload the option priority list with mandatory options. */
|
||||||
|
16
osdep.h
16
osdep.h
@@ -48,3 +48,19 @@
|
|||||||
#include "cf/netbsd.h"
|
#include "cf/netbsd.h"
|
||||||
#endif
|
#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
|
#endif
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
||||||
|
|
||||||
note ("Sending bootp reply to %s, port %d",
|
note ("Sending BOOTREPLY to %s, address %s",
|
||||||
inet_ntoa (to.sin_addr), to.sin_port);
|
print_hw_addr (packet -> raw -> htype,
|
||||||
|
packet -> raw -> hlen,
|
||||||
|
packet -> raw -> chaddr),
|
||||||
|
inet_ntoa (packet -> raw -> yiaddr));
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
|
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
|
||||||
|
@@ -1024,7 +1024,7 @@ TIME parse_date (cfile, bc)
|
|||||||
skip_to_semi (cfile);
|
skip_to_semi (cfile);
|
||||||
longjmp (*bc, 1);
|
longjmp (*bc, 1);
|
||||||
}
|
}
|
||||||
tm.tm_mon = atoi (val);
|
tm.tm_mon = atoi (val) - 1;
|
||||||
|
|
||||||
/* Slash seperating month from day... */
|
/* Slash seperating month from day... */
|
||||||
token = next_token (&val, cfile);
|
token = next_token (&val, cfile);
|
||||||
@@ -1093,9 +1093,12 @@ TIME parse_date (cfile, bc)
|
|||||||
}
|
}
|
||||||
tm.tm_sec = atoi (val);
|
tm.tm_sec = atoi (val);
|
||||||
|
|
||||||
|
#ifndef BROKEN_TM_GMT
|
||||||
|
/* linux does not implement these yet */
|
||||||
tm.tm_zone = "GMT";
|
tm.tm_zone = "GMT";
|
||||||
tm.tm_isdst = 0;
|
|
||||||
tm.tm_gmtoff = 0;
|
tm.tm_gmtoff = 0;
|
||||||
|
#endif
|
||||||
|
tm.tm_isdst = 0;
|
||||||
|
|
||||||
/* XXX */ /* We assume that mktime does not use tm_yday. */
|
/* XXX */ /* We assume that mktime does not use tm_yday. */
|
||||||
tm.tm_yday = 0;
|
tm.tm_yday = 0;
|
||||||
|
@@ -117,7 +117,7 @@ void new_lease_file ()
|
|||||||
|
|
||||||
/* Make a temporary lease file... */
|
/* Make a temporary lease file... */
|
||||||
time (&t);
|
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) {
|
if ((db_file = fopen (newfname, "w")) == NULL) {
|
||||||
error ("Can't start new lease file: %m");
|
error ("Can't start new lease file: %m");
|
||||||
}
|
}
|
||||||
|
@@ -83,6 +83,11 @@ void dhcpdiscover (packet)
|
|||||||
{
|
{
|
||||||
struct lease *lease = find_lease (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 we didn't find a lease, try to allocate one... */
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
lease = packet -> subnet -> last_lease;
|
lease = packet -> subnet -> last_lease;
|
||||||
@@ -106,17 +111,29 @@ void dhcprequest (packet)
|
|||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
struct iaddr cip;
|
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) {
|
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
||||||
cip.len = 4;
|
cip.len = 4;
|
||||||
memcpy (cip.iabuf,
|
memcpy (cip.iabuf,
|
||||||
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
|
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
|
||||||
4);
|
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,
|
if (!addr_eq (packet -> subnet -> net,
|
||||||
subnet_number (cip,
|
subnet_number (cip,
|
||||||
packet -> subnet -> netmask))) {
|
packet -> subnet -> netmask))) {
|
||||||
nak_lease (packet);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +144,7 @@ void dhcprequest (packet)
|
|||||||
if (!addr_eq (packet -> subnet -> net,
|
if (!addr_eq (packet -> subnet -> net,
|
||||||
subnet_number (cip,
|
subnet_number (cip,
|
||||||
packet -> subnet -> netmask))) {
|
packet -> subnet -> netmask))) {
|
||||||
nak_lease (packet);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +166,7 @@ void dhcprequest (packet)
|
|||||||
|
|
||||||
/* If we didn't find a lease, don't try to allocate one... */
|
/* If we didn't find a lease, don't try to allocate one... */
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
nak_lease (packet);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +178,12 @@ void dhcprelease (packet)
|
|||||||
{
|
{
|
||||||
struct lease *lease = find_lease (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 we found a lease, release it. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
release_lease (lease);
|
release_lease (lease);
|
||||||
@@ -171,6 +194,22 @@ void dhcpdecline (packet)
|
|||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
struct lease *lease = find_lease (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 we found a lease, mark it as unusable and complain. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
@@ -181,10 +220,17 @@ void dhcpdecline (packet)
|
|||||||
void dhcpinform (packet)
|
void dhcpinform (packet)
|
||||||
struct packet *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 packet *packet;
|
||||||
|
struct iaddr *cip;
|
||||||
{
|
{
|
||||||
struct sockaddr_in to;
|
struct sockaddr_in to;
|
||||||
int result;
|
int result;
|
||||||
@@ -244,8 +290,8 @@ void nak_lease (packet)
|
|||||||
to.sin_addr = raw.giaddr;
|
to.sin_addr = raw.giaddr;
|
||||||
to.sin_port = server_port;
|
to.sin_port = server_port;
|
||||||
} else {
|
} else {
|
||||||
to.sin_addr.s_addr = INADDR_BROADCAST;
|
memcpy (&to.sin_addr.s_addr, cip->iabuf, 4);
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
to.sin_port = packet->client_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
to.sin_family = AF_INET;
|
to.sin_family = AF_INET;
|
||||||
@@ -254,14 +300,17 @@ void nak_lease (packet)
|
|||||||
#endif
|
#endif
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
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));
|
inet_ntoa (to.sin_addr), htons (to.sin_port));
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
|
result = sendpkt (packet, &raw, outgoing.packet_length,
|
||||||
0, (struct sockaddr *)&to, sizeof to);
|
(struct sockaddr *) &to, sizeof(to));
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
warn ("sendto: %m");
|
warn ("sendpkt: %m");
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
dump_packet (packet);
|
dump_packet (packet);
|
||||||
@@ -471,6 +520,15 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
options [DHO_DHCP_USER_CLASS_ID] -> tree = (struct tree *)0;
|
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);
|
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
|
||||||
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
|
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
|
||||||
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
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. */
|
/* Otherwise, broadcast it on the local network. */
|
||||||
} else {
|
} 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 */
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,14 +576,18 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
#endif
|
#endif
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
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));
|
inet_ntoa (to.sin_addr), htons (to.sin_port));
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
result = sendto (packet -> client_sock, &raw, outgoing.packet_length,
|
result = sendpkt (packet, &raw, outgoing.packet_length,
|
||||||
0, (struct sockaddr *)&to, sizeof to);
|
(struct sockaddr *) &to, sizeof(to));
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
warn ("sendto: %m");
|
warn ("sendpkt: %m");
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
dump_packet (packet);
|
dump_packet (packet);
|
||||||
|
@@ -179,9 +179,9 @@ int main (argc, argv, envp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write a pid file. */
|
/* 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];
|
char obuf [20];
|
||||||
sprintf (obuf, "%d\n", getpid ());
|
sprintf (obuf, "%d\n", (int)getpid ());
|
||||||
write (i, obuf, strlen (obuf));
|
write (i, obuf, strlen (obuf));
|
||||||
close (i);
|
close (i);
|
||||||
}
|
}
|
||||||
|
258
socket.c
258
socket.c
@@ -48,6 +48,27 @@ static char copyright[] =
|
|||||||
#include "dhcpd.h"
|
#include "dhcpd.h"
|
||||||
#include <sys/ioctl.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... */
|
/* List of sockets we're accepting packets on... */
|
||||||
struct socklist {
|
struct socklist {
|
||||||
struct socklist *next;
|
struct socklist *next;
|
||||||
@@ -86,19 +107,50 @@ u_int32_t *get_interface_list (count)
|
|||||||
second time to copy them into an array of addresses. */
|
second time to copy them into an array of addresses. */
|
||||||
for (i = 0; i < ic.ifc_len;) {
|
for (i = 0; i < ic.ifc_len;) {
|
||||||
struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
|
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;
|
i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
|
||||||
|
#else
|
||||||
|
i += sizeof *ifp;
|
||||||
|
#endif
|
||||||
if (ifp -> ifr_addr.sa_family == AF_INET) {
|
if (ifp -> ifr_addr.sa_family == AF_INET) {
|
||||||
struct sockaddr_in *foo =
|
struct sockaddr_in *foo =
|
||||||
(struct sockaddr_in *)(&ifp -> ifr_addr);
|
(struct sockaddr_in *)(&ifp -> ifr_addr);
|
||||||
/* We don't want the loopback interface. */
|
/* We don't want the loopback interface. */
|
||||||
if (foo -> sin_addr.s_addr == INADDR_LOOPBACK)
|
if (foo -> sin_addr.s_addr == INADDR_LOOPBACK)
|
||||||
continue;
|
continue;
|
||||||
if (intbuf)
|
if (intbuf) {
|
||||||
intbuf [ifix++] = foo -> sin_addr.s_addr;
|
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
|
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;
|
++ifcount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* If we haven't already filled our array, allocate it and go
|
/* If we haven't already filled our array, allocate it and go
|
||||||
again. */
|
again. */
|
||||||
if (!intbuf) {
|
if (!intbuf) {
|
||||||
@@ -107,6 +159,13 @@ u_int32_t *get_interface_list (count)
|
|||||||
"get_interface_list");
|
"get_interface_list");
|
||||||
if (!intbuf)
|
if (!intbuf)
|
||||||
return 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;
|
goto again;
|
||||||
}
|
}
|
||||||
*count = ifcount;
|
*count = ifcount;
|
||||||
@@ -215,3 +274,198 @@ void dispatch ()
|
|||||||
} while (1);
|
} 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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user