Retire MINIX dhcpd(8)

Change-Id: I4b8c738b6176ce390a7a7817b0dcaf9caffe636c
This commit is contained in:
David van Moolenbroek 2017-02-14 17:50:02 +00:00
parent 035c234ade
commit 9490732a59
20 changed files with 7 additions and 4005 deletions

View File

@ -326,7 +326,7 @@
./usr/bin/deroff minix-base
./usr/bin/devmand minix-base
./usr/bin/devsize minix-base
./usr/bin/dhcpd minix-base
./usr/bin/dhcpd minix-base obsolete
./usr/bin/dhrystone minix-base
./usr/bin/diff minix-base
./usr/bin/dirname minix-base
@ -609,7 +609,7 @@
./usr/bin/znew minix-base
./usr/etc minix-base
./usr/etc/daily minix-base
./usr/etc/dhcptags.conf minix-base
./usr/etc/dhcptags.conf minix-base obsolete
./usr/etc/rc minix-base
./usr/include/c++ minix-base gcc=5
./usr/include/c++/experimental minix-base gcc=5

View File

@ -254,7 +254,7 @@
./usr/libdata/debug/usr/bin/deroff.debug minix-debug debug
./usr/libdata/debug/usr/bin/devmand.debug minix-debug debug
./usr/libdata/debug/usr/bin/devsize.debug minix-debug debug
./usr/libdata/debug/usr/bin/dhcpd.debug minix-debug debug
./usr/libdata/debug/usr/bin/dhcpd.debug minix-debug debug,obsolete
./usr/libdata/debug/usr/bin/dhrystone.debug minix-debug debug
./usr/libdata/debug/usr/bin/diff.debug minix-debug debug
./usr/libdata/debug/usr/bin/dirname.debug minix-debug debug

View File

@ -3274,7 +3274,7 @@
./usr/man/man5/configfile.5 minix-man
./usr/man/man5/cpio.5 minix-man
./usr/man/man5/crontab.5 minix-man
./usr/man/man5/dhcp.conf.5 minix-man
./usr/man/man5/dhcp.conf.5 minix-man obsolete
./usr/man/man5/dir.5 minix-man obsolete
./usr/man/man5/editrc.5 minix-man
./usr/man/man5/ethers.5 minix-man
@ -3382,7 +3382,7 @@
./usr/man/man8/cron.8 minix-man
./usr/man/man8/dev_mkdb.8 minix-man
./usr/man/man8/devsize.8 minix-man
./usr/man/man8/dhcpd.8 minix-man
./usr/man/man8/dhcpd.8 minix-man obsolete
./usr/man/man8/diskctl.8 minix-man
./usr/man/man8/fbdctl.8 minix-man
./usr/man/man8/fdisk.8 minix-man

View File

@ -458,7 +458,6 @@ install-etc-files-safe: .PHONY .MAKE check_DESTDIR MAKEDEV
.else # LSC Minix Specific
.for owner group mode sdir tdir files in \
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/usr/ ${DESTDIR}/usr/etc/ daily \
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/usr/ ${DESTDIR}/usr/etc/ dhcptags.conf \
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/usr/ ${DESTDIR}/usr/etc/ rc \
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/ ${DESTDIR}/usr/lib/ crontab \
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/ ${DESTDIR}/etc/ system.conf \

View File

@ -1,63 +0,0 @@
# A list of all tags mentioned in RFC-1533.
tag 1 netmask ip 1 1;
tag 2 zoneoffset number 4 1;
tag 3 gateway ip 1 0;
tag 4 timeserver ip 1 0;
tag 5 nameserver ip 1 0;
tag 6 DNSserver ip 1 0;
tag 7 logserver ip 1 0;
tag 8 cookieserver ip 1 0;
tag 9 LPR ip 1 0;
tag 10 impress ip 1 0;
tag 11 resource ip 1 0;
tag 12 hostname ascii 1 0;
tag 13 bootfilesize number 2 1;
tag 14 coredump ip 1 0;
tag 15 domain ascii 1 0;
tag 16 swapserver ip 1 1;
tag 17 rootpath ascii 1 0;
tag 18 extensions ascii 1 0;
tag 19 IPforwarding boolean 1 1;
tag 20 IPnonlocalsource boolean 1 1;
tag 21 IPpolicyfilter ip 2 0;
tag 22 IPmaxreassembly number 2 1;
tag 23 IPTTL number 1 1;
tag 24 IPMTUaging number 4 1;
tag 25 IPMTUplateau number 2 0;
tag 26 IPMTU number 2 1;
tag 27 IPsublocal boolean 1 1;
tag 28 IPbroadcast ip 1 1;
tag 29 IPmaskdiscovery boolean 1 1;
tag 30 IPmasksupplier boolean 1 1;
tag 31 IPdiscovery boolean 1 1;
tag 32 IPsolicitation ip 1 1;
tag 33 IPstaticroute ip 2 0;
tag 34 ARPtrailer boolean 1 1;
tag 35 ARPtimeout number 4 1;
tag 36 ETHencapsulation boolean 1 1;
tag 37 TCPTTL number 1 1;
tag 38 TCPkeepaliveinterval number 4 1;
tag 39 TCPkeepalivegarbage boolean 1 1;
tag 40 NISdomain ascii 1 0;
tag 41 NISserver ip 1 0;
tag 42 NTPserver ip 1 0;
tag 43 VENDOR octet 1 0;
tag 44 NetBIOSNS ip 1 0;
tag 45 NetBIOSdgram ip 1 0;
tag 46 NetBIOSnodetype number 1 1;
tag 47 NetBIOSscope octet 1 0;
tag 48 Xfontserver ip 1 0;
tag 49 XDM ip 1 0;
tag 50 DHCPreqip ip 1 1;
tag 51 DHCPlease number 4 1;
tag 52 DHCPoverload number 1 1;
tag 53 DHCPtype number 1 1;
tag 54 DHCPserverID ip 1 1;
tag 55 DHCPreqpar number 1 0;
tag 56 DHCPmessage ascii 1 0;
tag 57 DHCPsize number 2 1;
tag 58 DHCPrenewal number 4 1;
tag 59 DHCPrebinding number 4 1;
tag 60 DHCPclassID ascii 1 0;
tag 61 DHCPclientID octet 1 0;

View File

@ -8,7 +8,7 @@
CPPFLAGS.fslib.c+= -I${NETBSDSRCDIR}/minix/fs
CPPFLAGS.fsversion.c+= -I${NETBSDSRCDIR}/minix/fs
SRCS+= dhcp_gettag.c dhcp_settag.c fsversion.c gcov.c itoa.c \
SRCS+= fsversion.c gcov.c itoa.c \
oneC_sum.c read_tsc_64.c servxcheck.c fslib.c
.endif # defined(__MINIX)

View File

@ -6,7 +6,7 @@ SUBDIR= arp at backup \
cawf cdprobe \
cleantmp \
compress crc cron crontab \
DESCRIBE devmand devsize dhcpd \
DESCRIBE devmand devsize \
dhrystone \
eject \
fix format fsck.mfs \

View File

@ -1,7 +0,0 @@
# Makefile for dhcpd.
PROG= dhcpd
SRCS= dhcpd.c tags.c devices.c ether.c
MAN= dhcpd.8 dhcp.conf.5
.include <bsd.prog.mk>

View File

@ -1,26 +0,0 @@
/* arp.h - Address Resolution Protocol packet format.
* Author: Kees J. Bot
* 16 Dec 2000
*/
#ifndef ARP_H
#define ARP_H
typedef struct arp46 {
ether_addr_t dstaddr;
ether_addr_t srcaddr;
ether_type_t ethtype; /* ARP_PROTO. */
u16_t hdr, pro; /* ARP_ETHERNET & ETH_IP_PROTO. */
u8_t hln, pln; /* 6 & 4. */
u16_t op; /* ARP_REQUEST or ARP_REPLY. */
ether_addr_t sha; /* Source hardware address. */
u8_t spa[4]; /* Source protocol address. */
ether_addr_t tha; /* Likewise for the target. */
u8_t tpa[4];
char padding[60 - (4*6 + 2*4 + 4*2 + 2*1)];
} arp46_t;
#define ARP_ETHERNET 1 /* ARP on Ethernet. */
#define ARP_REQUEST 1 /* A request for an IP address. */
#define ARP_REPLY 2 /* A reply to a request. */
#endif /* ARP_H */

View File

@ -1,347 +0,0 @@
/* devices.c - Handle network devices.
* Author: Kees J. Bot
* 11 Jun 1999
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <signal.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/asynchio.h>
#include <net/hton.h>
#include <net/gen/in.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <net/gen/ether.h>
#include <net/gen/eth_hdr.h>
#include <net/gen/eth_io.h>
#include <net/gen/ip_hdr.h>
#include <net/gen/ip_io.h>
#include <net/gen/udp.h>
#include <net/gen/udp_hdr.h>
#include <net/gen/udp_io.h>
#include <net/gen/dhcp.h>
#include "dhcpd.h"
void get_buf(buf_t **bp)
{
/* Allocate and return a buffer pointer iff *bp == nil. */
if (*bp != nil) {
/* Already has one. */
} else {
/* Get one from the heap. */
buf_t *new= allocate(sizeof(*new));
new->dhcp= (dhcp_t *) (new->buf + sizeof(eth_hdr_t)
+ sizeof(ip_hdr_t) + sizeof(udp_hdr_t));
new->udpio= ((udp_io_hdr_t *) new->dhcp) - 1;
new->udp= ((udp_hdr_t *) new->dhcp) - 1;
new->ip= ((ip_hdr_t *) new->udp) - 1;
new->eth= ((eth_hdr_t *) new->ip) - 1;
*bp= new;
}
}
void put_buf(buf_t **bp)
{
/* Return a buffer to the heap. */
if (*bp != nil) {
free(*bp);
*bp= nil;
}
}
void give_buf(buf_t **dbp, buf_t **sbp)
{
/* Hand over a buffer to another variable. */
put_buf(dbp);
*dbp= *sbp;
*sbp= nil;
}
#define N_FDS 16 /* Minix can go async on many fds. */
static fd_t fds[N_FDS]; /* List of open descriptors. */
static struct network *fdwaitq; /* Queue of nets waiting for fds. */
network_t *newnetwork(void)
{
/* Create and initialize a network structure. */
network_t *new;
new= allocate(sizeof(*new));
memset(new, 0, sizeof(*new));
new->hostname= nil;
new->solicit= NEVER;
new->sol_ct= -1;
return new;
}
void closefd(fd_t *fdp)
{
/* Close a descriptor. */
if (fdp->fdtype != FT_CLOSED) {
asyn_close(&asyn, fdp->fd);
close(fdp->fd);
fdp->fdtype= FT_CLOSED;
fdp->since= 0;
put_buf(&fdp->bp);
if (debug >= 3) printf("%s: Closed\n", fdp->device);
}
}
static void timeout(int signum)
{
/* nothing to do, ioctl will be aborted automatically */
if (alarm(1) == (unsigned int)-1) fatal("alarm(1)");
}
int opendev(network_t *np, fdtype_t fdtype, int compete)
{
/* Make sure that a network has the proper device open and configured.
* Return true if this is made so, or false if the device doesn't exist.
* If compete is true then the caller competes for old descriptors.
* The errno value is EAGAIN if we're out of descriptors.
*/
fd_t *fdp, *fdold;
time_t oldest;
nwio_ethstat_t ethstat;
nwio_ethopt_t ethopt;
nwio_ipopt_t ipopt;
nwio_udpopt_t udpopt;
network_t **pqp;
static char devbytype[][4] = { "", "eth", "ip", "udp", "udp" };
/* Don't attempt to open higher level devices if not bound. */
if (!(np->flags & NF_BOUND) && fdtype > FT_ETHERNET) {
errno= EAGAIN;
return 0;
}
/* Check if already open / Find the oldest descriptor. */
fdold= nil;
oldest= NEVER;
for (fdp= fds; fdp < arraylimit(fds); fdp++) {
if (fdp->n == np->n && fdp->fdtype == fdtype) {
/* Already open. */
np->fdp= fdp;
return 1;
}
if (fdp->since <= oldest) { fdold= fdp; oldest= fdp->since; }
}
/* None free? Then wait for one to get old if so desired. */
if (fdold->fdtype != FT_CLOSED && !compete) {
errno= EAGAIN;
return 0;
}
if (!(np->flags & NF_WAIT)) {
for (pqp= &fdwaitq; *pqp != nil; pqp= &(*pqp)->wait) {}
*pqp= np;
np->wait= nil;
np->flags |= NF_WAIT;
}
/* We allow a net to keep a descriptor for half of the fast period. */
oldest += DELTA_FAST/2;
if (fdwaitq != np || (fdold->fdtype != FT_CLOSED && oldest > now)) {
/* This net is not the first in the queue, or the oldest isn't
* old enough. Forget it for now.
*/
if (oldest < event) event= oldest;
errno= EAGAIN;
return 0;
}
/* The oldest is mine. */
np->flags &= ~NF_WAIT;
fdwaitq= np->wait;
closefd(fdold);
/* Open the proper device in the proper mode. */
fdp= fdold;
fdp->n= np->n;
if (lwip && (fdtype == FT_ETHERNET || fdtype == FT_ICMP))
sprintf(fdp->device, "/dev/ip");
else
sprintf(fdp->device, "/dev/%s%d", devbytype[fdtype], np->n);
np->fdp= fdp;
if ((fdp->fd= open(fdp->device, O_RDWR)) < 0) {
if (errno == ENOENT || errno == ENODEV || errno == ENXIO) return 0;
fatal(fdp->device);
}
switch (fdtype) {
case FT_ETHERNET:
if (lwip) {
nwio_ipopt_t ipopt;
int result;
char ethdev[64];
int efd;
sprintf(ethdev, "/dev/eth%d", np->n);
if ((efd = open(fdp->device, O_RDWR)) < 0) {
if (errno == ENOENT || errno == ENODEV ||
errno == ENXIO)
return 0;
fatal(ethdev);
}
if (ioctl(efd, NWIOGETHSTAT, &ethstat) < 0) {
/* Not an Ethernet. */
close(efd);
return 0;
}
close(efd);
np->eth= ethstat.nwes_addr;
ipopt.nwio_flags= NWIO_COPY | NWIO_PROTOSPEC;
ipopt.nwio_proto= 17; /* UDP */
result= ioctl (fdp->fd, NWIOSIPOPT, &ipopt);
if (result<0)
perror("ioctl (NWIOSIPOPT)"), exit(1);
break;
}
/* Cannot use NWIOGETHSTAT in non-blocking mode due to a race between
* the reply from the ethernet driver and the cancel message from VFS
* for reaching inet. Hence, a signal is used to interrupt NWIOGETHSTAT
* in case the driver isn't ready yet.
*/
if (signal(SIGALRM, timeout) == SIG_ERR) fatal("signal(SIGALRM)");
if (alarm(1) == (unsigned int)-1) fatal("alarm(1)");
if (ioctl(np->fdp->fd, NWIOGETHSTAT, &ethstat) < 0) {
/* Not an Ethernet. */
close(fdp->fd);
return 0;
}
if (alarm(0) == (unsigned int)-1) fatal("alarm(0)");
np->eth= ethstat.nwes_addr;
ethopt.nweo_flags= NWEO_COPY | NWEO_EN_LOC | NWEO_EN_BROAD
| NWEO_REMANY | NWEO_TYPEANY | NWEO_RWDATALL;
if (ioctl(fdp->fd, NWIOSETHOPT, &ethopt) < 0) {
fprintf(stderr, "%s: %s: Unable to set eth options: %s\n",
program, fdp->device, strerror(errno));
exit(1);
}
break;
case FT_ICMP:
ipopt.nwio_flags= NWIO_COPY | NWIO_EN_LOC | NWIO_EN_BROAD
| NWIO_REMANY | NWIO_PROTOSPEC
| NWIO_HDR_O_SPEC | NWIO_RWDATALL;
ipopt.nwio_tos= 0;
ipopt.nwio_ttl= 1;
ipopt.nwio_df= 0;
ipopt.nwio_hdropt.iho_opt_siz= 0;
ipopt.nwio_proto= IPPROTO_ICMP;
if (ioctl(fdp->fd, NWIOSIPOPT, &ipopt) < 0) {
fprintf(stderr, "%s: %s: Unable to set IP options: %s\n",
program, fdp->device, strerror(errno));
exit(1);
}
break;
case FT_BOOTPC:
if (lwip) {
struct sockaddr_in si_me;
close(fdp->fd);
fdp->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fdp->fd < 0)
return 0;
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
si_me.sin_port = htons(port_client);
if (bind(fdp->fd, (struct sockaddr *) &si_me,
sizeof(si_me)) == -1) {
close(fdp->fd);
printf("DHCP : cannot bind client socket to port %d\n",
port_client);
return 0;
}
break;
}
udpopt.nwuo_flags= NWUO_COPY | NWUO_EN_LOC | NWUO_EN_BROAD
| NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL
| NWUO_DI_IPOPT | NWUO_LP_SET;
udpopt.nwuo_locport= port_client;
goto udp;
case FT_BOOTPS:
udpopt.nwuo_flags= NWUO_EXCL | NWUO_EN_LOC | NWUO_EN_BROAD
| NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL
| NWUO_DI_IPOPT | NWUO_LP_SET;
udpopt.nwuo_locport= port_server;
udp:
if (ioctl(fdp->fd, NWIOSUDPOPT, &udpopt) == -1) {
fprintf(stderr, "%s: %s: Unable to set UDP options: %s\n",
program, fdp->device, strerror(errno));
exit(1);
}
break;
default:;
}
fdp->fdtype= fdtype;
fdp->since= now;
if (debug >= 3) printf("%s: Opened\n", fdp->device);
return 1;
}
void closedev(network_t *np, fdtype_t fdtype)
{
/* We no longer need a given type of device to be open. */
fd_t *fdp;
for (fdp= fds; fdp < arraylimit(fds); fdp++) {
if (fdp->n == np->n && (fdp->fdtype == fdtype || fdtype == FT_ALL)) {
closefd(fdp);
}
}
}
char *ipdev(int n)
{
/* IP device for network #n. */
static char device[sizeof("/dev/ipNNN")];
sprintf(device, "/dev/ip%d", n);
return device;
}
void set_ipconf(char *device, ipaddr_t ip, ipaddr_t mask, unsigned mtu)
{
/* Set IP address and netmask of an IP device. */
int fd;
nwio_ipconf_t ipconf;
if (test > 0) return;
if ((fd= open(device, O_RDWR)) < 0) fatal(device);
ipconf.nwic_flags= NWIC_IPADDR_SET | NWIC_NETMASK_SET;
ipconf.nwic_ipaddr= ip;
ipconf.nwic_netmask= mask;
#ifdef NWIC_MTU_SET
if (mtu != 0) {
ipconf.nwic_flags |= NWIC_MTU_SET;
ipconf.nwic_mtu= mtu;
}
#endif
if (ioctl(fd, NWIOSIPCONF, &ipconf) < 0) fatal(device);
close(fd);
}

View File

@ -1,498 +0,0 @@
.TH DHCP.CONF 5
.SH NAME
dhcp.conf \- dynamic host configuration protocol configuration
.SH SYNOPSIS
.B /etc/dhcp.conf
.SH DESCRIPTION
.de SP
.if t .sp 0.4
.if n .sp
..
The file
.B /etc/dhcp.conf
contains the configuration for the DHCP client/server program
.BR dhcpd .
This text is a long summation of all the elements that can be found in this
configuration file. For a more "just tell me what to do" approach see
.BR boot (8).
.PP
The syntax used is that of the common configuration file described in
.BR configfile (5).
.PP
To find information for a client we first need its IP address. Occasionally
this IP address is already known (the special "INFORM" query), but normally
we have to make a first pass through the configuration file for a
.B client
entry. If that fails then we use an IP address from the pool file. If we
now have an IP address then the real information gathering can begin.
.PP
The DHCP daemon reads the configuration file from beginning to end and
gathers all information that matches, and information from all macros that
are mentioned within the elements that match. If we end up with DHCP
information that includes at least a netmask definition, and is good for the
network the request came in from, then it is returned to the client. If a
DHCP tag is specified twice then the last one wins.
.PP
In the description below we use [ and ] to denote optional things, and | to
show a choice between two things.
.PP
Client IDs can be either ordinary Ethernet addresses, that are treated as a
seven octet string (01 followed by the Ethernet address), or any random
octet string in hexadecimal.
.PP
IP addresses can be simply that, or host names. These host names are
searched in
.B /etc/hosts
by
.B dhcpd
itself using a domain based prefix match, i.e. you can use "flotsam" for
"flotsam.example.com", but not "alpha" for "alphabeta". Once the program
decides to be a server it will also look up names normally in the DNS.
If a host has more than one IP address then the address on the network the
query was seen on is used.
.PP
Case isn't important in the configuration file, "client", "CLIENT" and
"ClIeNt" are all treated the same.
.PP
Some elements may optionally name a macro or a curly braces enclosed
parameter list of more elements. If the element matches then the data
in the macro body or parameter list is gathered.
.PP
The following elements can be used:
.PP
.B client
.I client-ID
.RB [ ip #]
.I host
.RI [ macro |{ params }];
.PP
.RS
Defines a client with a given client ID that is to have the IP address
denoted by
.I host .
On the first pass only the client ID is matched looking for an IP address
that lies on the network the request came in on. On the
information gathering pass both client ID and IP address must match. If
a machine has the same Ethernet address on two or more interfaces then the
IP address given out is the one on the same network as the request came in
on. The optional interface name
.RB ( ip #)
must be used if the DHCP daemon is gathering data for itself at boot time
to differentiate interfaces with the same ethernet addresses. This is
only necessary under Minix-vmd when ethernets on different VLANs share
the same physical ethernet. The interface name is only used for a machine's
own networks, it ignored on entries for other hosts.
.RE
.PP
.B class
.IR class-name " ..."
.IR macro |{ params };
.PP
.RS
Includes the macro or parameters if one of the class names is matched. A
host normally includes a class ID in its request. MINIX 3 and Minix-vmd
use "Minix" as the class name. For Windows the class ID starts with
"MSFT", and Solaris' starts with "SUNW".
(Use
.B dhcpd \-d3
to find out what the full IDs are exactly.) The class names are matched if a
.I class-name
is a prefix of the class ID sent by the client.
.RE
.PP
.B host
.I host-spec
.IR macro |{ params };
.PP
.RS
Includes the macro or parameters if the IP address of the client matches the
host specification. This can either be an ordinary hostname, or a netblock
in CIDR notation, e.g. 172.35.0.0/16. The example includes all IP addresses
whose top 16 bits are the same as the top 16 bits of 172.35.0.0. Such a
netblock automatically defines a netmask (255.255.0.0 in the example) if no
netmask has been specified yet.
.RE
.PP
.B interface
.BR ip #
.I host
.RI [ macro |{ params }];
.PP
.RS
Makes
.B dhcpd
set the IP address of interface
.BR ip #
(where # is a number) to the IP address denoted by
.IR host .
This element should only be used for interfaces that are not true Ethernets,
and so do not have a unique Ethernet address that can be used for a client
element. If the machine has at least one true Ethernet then all interface
elements should be added to the parameter list of a host or client element
for that Ethernet interface. This binds them to that machine and allows a
single configuration file to be shared among machines. Especially a server
should never have "free" interface elements. The macro or parameters are
only evaluated if data is gathered for the given interface. (Note that they
will be hidden by a client element for another interface.)
.RE
.PP
.B macro
.IR macro-name ;
.PP
.RS
Include the parameter list of the macro named
.I macro-name
defined elsewhere. (This means that "host flotsam stuff" is just short
for "host flotsam { macro stuff; }".)
.RE
.PP
.B macro
.I macro-name
.RI { params };
.PP
.RS
Defines a macro with the given parameter list. Whenever the macro is used
the parameter list is substituted instead. A macro can not be defined
within another parameter list.
.RE
.PP
.B option
.RB [ ip #]
.B server
.RB [ inform ];
.br
.B option
.RB [ ip #]
.B relay
.IR host ;
.br
.B option
.RB [ ip #]
.BR possessive ;
.br
.B option
.RB [ ip #]
.B hostname
.IR name ;
.PP
.RS
Makes
.B dhcpd
set special options for the interface that it is gathering data for, or the
interface denoted by the optional
.BR ip #
argument. The options are:
.SP
.B server
.RB [ inform ]
.RS
Be a DHCP server on the network connected to the interface. Add the word
.B inform
if DHCPINFORM requests must be answered for hosts we don't have an address
for.
.RE
.SP
.B relay
.I host
.RS
Be a DHCP relay to the indicated host.
.RE
.SP
.B possessive
.RS
Do not disable the interface if the DHCP lease expires. Useful if the
DHCP server of the provider is unreliable, crashing a lot and causing the
lease to expire. (Think twice before turning this option on. You have to
be absolutely sure that it's the DHCP server that's the culprit and not
a flaky network. You don't want an IP address conflict to be your fault.)
.RE
.SP
.B hostname
.I name
.RS
Use the given name as our hostname in the DHCP queries. Some sites key on
that bit of information instead of a client ID.
.RE
.RE
.PP
.B tag
.I number name type granularity
.IR max ;
.PP
.RS
Defines a DHCP tag for the given tag number and gives it a name. The name can
be used in the configuration file to set tag values when gathering data.
The
.I type
field can be one of
.BR ascii ,
.BR boolean ,
.BR ip ,
.BR number
or
.BR octet
to specify the type of the tag as a simple string, a boolean, an IP address,
a number, or a string of octet values.
The
.I granularity
field specifies that that number of items must be given or a multiple
thereof, unless the type is a number, then it is the size of the number (1,
2 or 4).
The
.I max
field tells the maximum number of items that may be used with the tag, with
0 meaning "unlimited".
.SP
Three tags, the ones that MINIX 3 really cares about, have been predefined,
and there are also a few pseudotags predefined for the static fields in a
DHCP packet that one may want to set:
.SP
.RS
.nf
tag ? siaddr ip 1 1;
tag ? sname ascii 1 64;
tag ? file ascii 1 128;
tag 1 netmask ip 1 1;
tag 3 gateway ip 1 0;
tag 6 DNSserver ip 1 0;
.fi
.RE
.SP
The file
.B /usr/etc/dhcptags.conf
contains tag definitions for all standard DHCP tags. It is wise to include
this file at the top of any DHCP configuration file.
.RE
.PP
.B no
.IR tag-name ;
.PP
.RS
Removes a tag with the given name from the data gathered at this point.
Useful if one host is different from all others, for instance if it doesn't
need a gateway definition, because it happens to be the gateway.
.RE
.PP
.IR "ascii-tag string" ;
.PP
.RS
Adds an ASCII tag to the gathered data. The string can be a simple word, or
a quoted string.
.RE
.PP
.I boolean-tag
.BR false | true ;
.PP
.RS
Set a boolean tag to be false or true. (Encoded as a octet of value 0 or 1.
Note that if you prefer to use 0 or 1 instead of false or true then you can
define a boolean tag as a size 1 number instead.)
.RE
.PP
.IR "ip-tag host" " ...;"
.PP
.RS
Sets a tag that needs one or more IP addresses. The host names are
translated as usual. To make it easier to specify netmasks one can use a
slash followed by a number, e.g.
.BR "netmask /27" ,
which is a handy alternative for
.BR "netmask 255.255.255.224" .
.RE
.PP
.IR "number-tag number" " ...;"
.PP
.RS
Set a number tag.
.RE
.PP
.IR "octet-tag hexdigits" ;
.PP
.RS
Set an octet string tag.
.I Hexdigits
is a series of hexadecimal digits that are two by two used to set the
octets.
.RE
.PP
.SH EXAMPLE
As an example the DHCP configuration used by the author of this document is
included. His network at home consists of a number of PCs, an ISDN router
named rhone and a PC named saone serving as router/tunnel to/via a cable
ISP. Both the rhone and the saone connect the home net to the network of
the Vrije Universiteit, but the rhone is only active if the cable doesn't
work.
.PP
The saone is a DHCP server, and one of the ordinary PCs is a backup DHCP
server. Both use the same configuration file, which is added below, with
extra commentary introduced by
.B ##
at a deeper indent level:
.RS
.de xS \" Example start
.sp
.nf
.ft C
..
.de xE \" Example end
.fi
.ft R
..
.de cS \" Commentary start
.sp
.in +12m
.ti -\w'## 'u
##\ \c
..
.de cE \" Commentary end
.in -12m
..
.xS
.ta +8m +16m
include /usr/etc/dhcptags.conf;
.xE
.cS
With the help of the tag definitions we can use tags like "DHCPlease".
.cE
.xS
host 130.37.102.64/27 {
DNSserver saone darask;
host 130.37.102.88/29 { DHCPlease 259200; }
};
.xE
.cS
This defines the network 130.37.102.64/27, with netmask 255.255.255.224
(implicit from the network definition). The DNS servers for this net are
saone and darask. A smaller subrange of addresses is used as an address
pool on the saone, so a lease of 259200 seconds (3 days) is defined. The
netmask is still /27, as set by the outer network definition.
.cE
.xS
host 130.37.102.248/30 {};
.xE
.cS
A network of two addresses for routing tests.
.cE
.xS
host saone {
option server;
option ip1 possessive;
interface ip2 saone-net2;
DNSserver 130.37.24.3 130.37.24.6;
};
.xE
.cS
With the network definitions done we turn our attention to the hosts. Saone
is a DHCP server on its main interface. The second interface
.RB ( ip1 )
is connected to the cable modem. It gets its address from the cableco's
DHCP server, and if that server decides to go deaf then the saone keeps
the interface up ("possessive") even if the lease expires. The pseudo IP
interface
.B ip2
is set to the IP address of
.BR saone-net2 ,
one side of the encrypted tunnel over the cable to a Minix-vmd box at the VU.
The DNS servers specified override the default setting for the network, naming
two external servers at the VU that know the world.
.cE
.xS
host darask {
option server;
DNSserver saone;
class MINIX 3 { DNSserver saone 130.37.24.3 130.37.24.6; };
};
.xE
.cS
The darask is also a server, the backup for saone on the odd chance that it
is unavailable. It uses saone and the external name servers, but only
when it is running MINIX 3. When running Windows it only uses saone.
.cE
.xS
.ta +32m +16m
client 0:1:1b:a:68:ce darask; # NE2000
client 0:1:1b:a:77:23 burask; # NE2000
#lient 0:0:c0:b0:da:64 burask; # WD8013EWC
client 8:0:5a:38:b2:f finiah; # PCMCIA NE2000
client 0:0:c0:3a:12:10 bardelask; # WD8003
#lient 2:60:8c:ab:8a:6d bardelask; # 3C503
client 0:a0:c5:20:9:6d rhone;
client 0:1:1b:a:4c:3b saone; # NE2000
#lient 0:0:c0:fb:2:6a saone-net1; # WD8013EWC
.xE
.cS
Lastly the ethernet addresses of all the hosts are listed, so that they can
be translated to IP addresses. The lines that are commented out are for
extra network cards that are currently unused. The last is used to connect
to the cable modem, so it's only here because it's nice to have the ethernet
address written down somewhere.
.cE
.RE
.PP
The host names shown above are translated by DHCP using this
.BR /etc/hosts :
.RS
.xS
.ta +\w'130.37.102.249mm'u
604800 %ttl
2419200 %stale
130.37.102.65 darask.kjb.upwind.org
130.37.102.66 burask.kjb.upwind.org
130.37.102.67 finiah.kjb.upwind.org
130.37.102.68 bardelask.kjb.upwind.org
130.37.102.69 roniah.kjb.upwind.org
130.37.102.70 saone.kjb.upwind.org
130.37.102.2 saone-net2.kjb.upwind.org
130.37.102.88 rhone.kjb.upwind.org
130.37.102.89 dyn89.kjb.upwind.org
130.37.102.90 dyn90.kjb.upwind.org
130.37.102.91 dyn91.kjb.upwind.org
130.37.102.92 dyn92.kjb.upwind.org
130.37.102.93 dyn93.kjb.upwind.org
130.37.102.94 dyn94.kjb.upwind.org
130.37.102.249 tst1.kjb.upwind.org
130.37.102.250 tst2.kjb.upwind.org
.xE
.RE
.SH FILES
.TP
.B /usr/etc/dhcptags.conf
A supplied list of standard tag definitions as per RFC-1533. (Well, the
tag numbers and their meaning are standard, the names are made up.)
.SH "SEE ALSO"
.BR RFC-2131 ,
.BR RFC-1533 ,
.BR configfile (5),
.BR hosts (5),
.BR boot (8),
.BR dhcpd (8).
.SH NOTES
The amount of memory
.B dhcpd
needs increases with the size of configuration file. MINIX 3 can
handle
.B dhcptags.conf
and a modest sized
.BR dhcp.conf .
You have to increase the stack size to accommodate more. (No problem under
Minix-vmd, of course.)
.SH NOTES
Items that are only necessary for a certain host should only be specified
for that host. Items for a whole network are best added to a netblock
specification. Use class elements for a certain type of host, and macros
for exceptions. Try to limit information as much as possibly to those hosts
that need it. (Don't go overboard. A MINIX 3 machine won't be bothered by a
few NetBIOS tags.)
.PP
DHCPINFORM requests should always be answered when being a server, but
J. Random Sysadmin trying to diagnose problems doesn't like it when little
MINIX 3 machines show up in a packet trace unexpectedly. It's best to be
inconspicuous on a network you don't own.
.SH BUGS
There are a few too many subtle mistakes one can make.
.SH AUTHOR
Kees J. Bot <kjb@cs.vu.nl>

View File

@ -1,208 +0,0 @@
.TH DHCPD 8
.SH NAME
dhcpd \- dynamic host configuration protocol daemon
.SH SYNOPSIS
.in +.5i
.ti -.5i
.B dhdpd
.RB [ \-qar ]
.RB [ \-t [\fIlevel\fP]]
.RB [ \-d [\fIlevel\fP]]
.RB [ \-f
.IR configfile ]
.RB [ \-c
.IR cachefile ]
.RB [ \-p
.IR poolfile ]
.RI [ host " ...]"
.in -.5i
.SH DESCRIPTION
.de SP
.if t .sp 0.4
.if n .sp
..
.B Dhcpd
is a client and a server for the Dynamic Host Configuration Protocol. As a
client it collects DHCP data to configure the Ethernet networks with, and as
a server it answers DHCP queries from other machines.
.PP
This manual page describes the operation of
.BR dhcpd ,
the associated configuration file is described in
.BR dhcp.conf (5).
(The latter, together with
.BR boot (8),
is of more practical value when it comes to getting a machine's networks
interfaces up and running. See the options section below for debugging DCHP
problems.)
.SS Initialization
On a normal startup, i.e. none of the
.BR \-q ,
.BR \-a
or
.BR \-r
options are given,
.B dhcpd
determines what IP devices are present, and which of those are Ethernets.
For each network it looks for information in the configuration file as if
it were a server answering a query for that network. If any information is
found then the IP address is configured and the information stored in the
cache file.
.SS "Client Operation"
For each still unconfigured network a DHCP DISCOVER request is broadcast on
that network. If a DHCP OFFER reply is received then a DHCP REQUEST is
broadcast for the IP address offered, and if a DHCP ACK is received then the
network is configured and the information stored in the cache file.
.PP
If no reply is received then another query is sent after 4 seconds, and then
again after 8 seconds, doubling each time until 64 seconds. Every 64
seconds thereafter a request is broadcast until a reply is received.
.PP
Once configured the DHCP lease, rebind and renew times are computed. At the
renew time a DHCP REQUEST is sent to the DHCP server to extend the lease.
Normally we get an answer and refresh our information, but if no reply is
received we wait for half the remaining time until the rebind time and keep
retrying and halving the remaining time. When the rebind time is reached
the DHCP REQUEST is broadcast to try and reach some other DHCP server.
Halving the remaining time again and again until the lease expires. At that
point we go back to square one and broadcast a DHCP DISCOVER.
.PP
If at any point a DHCP NAK is received we start over completely. After a
DHCP OFFER an ARP request is transmitted just before the DHCP REQUEST to
check if the address offered is already in use. If an ARP reply is received
before the DHCP ACK then after the ACK we send a DHCP DECLINE to the server
to tell that the address isn't what we want and again we start over.
.SS "Router Discovery"
The gateway offered by the DHCP server is made known to the TCP/IP server by
sending an ICMP router advertisement to the local interface with a short
lifetime and a low priority. Then up to three router solicitations are
broadcast three seconds apart to look for a router. If a router answers
with a router advertisement then we no longer worry about routing for that
interface. Otherwise the router information is refreshed before it expires
and another solicitation is sent out. This happens about twice an hour.
.SS "Server Operation"
Once all networks so marked are configured the daemon starts answering
requests by other machines or relaying requests to other DHCP servers.
DHCP requests are answered if information for a client
can be found in the configuration file, or if a free address can be found in
the pool file, or if a client rerequests an address it already owns.
.PP
If the daemon is both a server and a relay for a network then it will try
to answer a request and only relay if it has no answer.
.SS "Nothing more to do?"
If the daemon finds out that all networks have an infinite lease (configured
with a fixed address), there is no router information to keep warm, and
it isn't a server then it simply exits.
.SS "Asynchronous I/O?"
MINIX 3 doesn't have the asynchronous I/O that Minix-vmd has, so under MINIX 3
the daemon only works with one network at a time. If it's stuck on the same
network for 32 seconds then that network is closed and another network is
tried for 32 seconds. This usually works ok as a client, but as a server it
can only handle one network.
.SH OPTIONS
.TP
.B \-q
Read and print the cache and pool file contents, showing DHCP information
for each network, and the IP addresses in the pool with lease times and
current/last owners of those addresses.
.TP
.B \-a
Add the named hosts (or IP addresses) to the pool file.
.TP
.B \-r
Remove hosts from the pool file.
.TP
.RB [ \-t [\fIlevel\fP]]
Set the test level (by default 1). At test level 1 all networks are seen as
unconfigured, will not be configured and no data will be put in the cache.
The program will just act as-if. At test level 2 the interfaces will not be
configured from the configuration file, the data must come from a remote
server. At level 3 the renewal, rebind and lease time will be 60, 120
and 180 seconds. At level 4 these times will be 60, 60, and 120. At
level 5 these times will be 60, 60, and 60. These test levels are meant
to debug the DHCP client code, and are best used with a high debug level.
.TP
.RB [ \-d [\fIlevel\fP]]
Set the debug level (by default 1). At debug level 1 the program shows
Ethernet and IP addresses as they are determined or configured, DHCP
messages sent and received with little detail (one line per message), and
memory use. At debug level 2 each DHCP packet is decoded and shown in
detail. At debug level 3 device opens and closes are shown. The debugging
level may also be increased by 1 at runtime by sending signal
.BR SIGUSR1
or turned off (set to 0) with
.BR SIGUSR2 .
.TP
.BI \-f " configfile"
Names the configuration file, by default
.BR /etc/dhcp.conf .
.TP
.BI \-c " cachefile"
Names the cache file, by default
.BR /usr/adm/dhcp.cache .
.TP
.BI \-p " poolfile"
Names the IP address pool, by default
.BR /usr/adm/dhcp.pool .
.SH "SEE ALSO"
.BR RFC-2131 ,
.BR RFC-1533 ,
.BR dhcp.conf (5),
.BR hosts (5),
.BR ifconfig (8),
.BR inet (8),
.BR boot (8),
.BR inetd (8),
.BR nonamed (8).
.SH DIAGNOSTICS
.TP
"'/etc/dhcp.conf', line ..."
The program exits on any configuration file error. You have to correct the
error and restart the program.
.TP
"No lease set for address ..."
There must be a lease time defined for addresses in the pool. Correct and
restart the program.
.TP
"###### declines #.#.#.# saying '...'"
A client with the given client identifier (usually 01 followed by the client's
Ethernet address) declines an IP address, hopefully with a message telling
why. This usually means that the IP address is already in use by another
host. This program, acting as a client, will tell what other host in its
message, but Windows has no additional info alas.
.TP
"Got a NAK from #.#.#.# [through #.#.#.#] saying '...'"
The server with the given IP address doesn't want us to have or keep the IP
address we were offered or are rerequesting. This could mean that the server
has forgotten about us and has given our address to another machine. This
is bad if our lease hasn't yet expired. There may be a relay involved, and
there may even be a text message with precise information.
.TP
"#.#.#.# offered by #.#.#.# is already in use by #:#:#:#:#:#"
We got an ARP reply for an offered address. We won't accept it, and send
out a DECLINE when we get an ACK.
.TP
"DHCP packet too big, ..."
You've got way to much information in the configuration file, more than fits
in a minimum size DHCP packet. (Notify the author if you really need to send
more information. He doesn't think anyone needs to.)
.TP
"Pool table is corrupt"
You will have to remove and refill the pool file. Chaos may ensue if
there are active clients and they don't use ARP to detect each other.
(Most do.)
.SH BUGS
There is no randomization of timers. Modern systems don't blink under the
load of several clients broadcasting a few packets in sync.
.PP
There is no extra time spent waiting for an ARP reply. It is assumed that
any IP stack will immediately respond, so that the DHCP server can't
possibly beat it at sending out an ACK. (The DHCP server has to commit the
lease to stable storage first anyway.)
.PP
Way more nonsense can be sent in a DHCP packet that MINIX 3 could do
something with, but nobody does so we don't bother.
.PP
DHCP was invented by a rabid gerbil on speed.
.SH AUTHOR
Kees J. Bot <kjb@cs.vu.nl>

File diff suppressed because it is too large Load Diff

View File

@ -1,162 +0,0 @@
/* dhcpd.h - Dynamic Host Configuration Protocol daemon.
* Author: Kees J. Bot
* 16 Dec 2000
*/
#define nil ((void*)0)
#include <minix/paths.h>
#include <net/if_ether.h>
/* Paths to files. */
#define PATH_DHCPCONF _PATH_DHCPCONF
#define PATH_DHCPPID _PATH_DHCPPID
#define PATH_DHCPCACHE _PATH_DHCPCACHE
#define PATH_DHCPPOOL _PATH_DHCPPOOL
#define CLID_MAX 32 /* Maximum client ID length. */
#ifndef EXTERN
#define EXTERN extern
#endif
extern int lwip;
EXTERN char *program; /* This program's name. */
extern char *configfile; /* Configuration file. */
extern char *poolfile; /* Dynamic address pool. */
EXTERN int serving; /* True if being a DHCP server. */
EXTERN unsigned test; /* Test level. */
EXTERN unsigned debug; /* Debug level. */
EXTERN asynchio_t asyn; /* Bookkeeping for all async I/O. */
/* BOOTP UDP ports: (That they are different is quite stupid.) */
EXTERN u16_t port_server; /* Port server listens on. */
EXTERN u16_t port_client; /* Port client listens on. */
#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
#define arraylimit(a) ((a) + arraysize(a))
#define between(a,c,z) (sizeof(c) <= sizeof(unsigned) ? \
(unsigned) (c) - (a) <= (unsigned) (z) - (a) : \
(unsigned long) (c) - (a) <= (unsigned long) (z) - (a))
/* To treat objects as octet arrays: */
#define B(a) ((u8_t *) (a))
/* Times. */
EXTERN time_t start, now; /* Start and current time. */
EXTERN time_t event; /* Time of the next timed event. */
/* Special times and periods: */
#define NEVER (sizeof(time_t) <= sizeof(int) ? INT_MAX : LONG_MAX)
#define DELTA_FIRST 4 /* Between first and second query. */
#define DELTA_FAST 64 /* Unbound queries this often. */
#define DELTA_SLOW 512 /* Bound queries are more relaxed. */
#define N_SOLICITS 3 /* Number of solicitations. */
#define DELTA_SOL 3 /* Time between solicitations. */
#define DELTA_ADV 2048 /* Router adverts to self lifetime. */
/* Buffers for packets. */
typedef struct buf {
eth_hdr_t *eth; /* Ethernet header in payload. */
ip_hdr_t *ip; /* IP header in payload. */
udp_hdr_t *udp; /* UDP header in payload. */
udp_io_hdr_t *udpio; /* UDP I/O header in payload. */
dhcp_t *dhcp; /* DHCP data in payload. */
u8_t pad[2]; /* buf[] must start at 2 mod 4. */
/* Payload: */
u8_t buf[ETH_MAX_PACK_SIZE];
} buf_t;
#define BUF_ETH_SIZE (ETH_MAX_PACK_SIZE)
#define BUF_IP_SIZE (BUF_ETH_SIZE - sizeof(eth_hdr_t))
#define BUF_UDP_SIZE (BUF_IP_SIZE - sizeof(ip_hdr_t) - sizeof(udp_hdr_t) \
+ sizeof(udp_io_hdr_t))
/* Type of network device open: Ethernet, ICMP, BOOTP client, BOOTP server. */
typedef enum { FT_CLOSED, FT_ETHERNET, FT_ICMP, FT_BOOTPC, FT_BOOTPS } fdtype_t;
#define FT_ALL FT_CLOSED /* To close all open descriptors at once. */
typedef struct fd { /* An open descriptor. */
i8_t fd; /* Open descriptor. */
u8_t fdtype; /* Type of network open. */
char device[sizeof("/dev/eth###")]; /* Device name. */
u8_t n; /* Network that owns it. */
buf_t *bp; /* Associated packet buffer. */
time_t since; /* Open since when? */
} fd_t;
/* Network state: Any IP device, Ethernet in sink mode, True Ethernet. */
typedef enum { NT_IP, NT_SINK, NT_ETHERNET } nettype_t;
typedef struct network { /* Information on a network. */
u8_t n; /* Network number. */
ether_addr_t eth; /* Ethernet address of this net. */
u8_t type; /* What kind of net is this? */
i8_t sol_ct; /* Router solicitation count. */
ether_addr_t conflict; /* Address conflict with this one. */
unsigned flags; /* Various flags. */
fd_t *fdp; /* Current open device. */
struct network *wait; /* Wait for a resource list. */
ipaddr_t ip; /* IP address of this net. */
ipaddr_t mask; /* Associated netmask. */
ipaddr_t gateway; /* My router. */
ipaddr_t server; /* My DHCP server. */
const char *hostname; /* Optional hostname to query for. */
time_t start; /* Query or lease start time. */
time_t delta; /* Query again after delta seconds. */
time_t renew; /* Next query or go into renewal. */
time_t rebind; /* When to go into rebind. */
time_t lease; /* When our lease expires. */
time_t solicit; /* Time to do a router solicitation. */
} network_t;
/* Flags. */
#define NF_NEGOTIATING 0x001 /* Negotiating with a DHCP server. */
#define NF_BOUND 0x002 /* Address configured through DHCP. */
#define NF_SERVING 0x004 /* I'm a server on this network. */
#define NF_RELAYING 0x008 /* I'm relaying for this network. */
#define NF_WAIT 0x010 /* Wait for a resource to free up. */
#define NF_IRDP 0x020 /* IRDP is used on this net. */
#define NF_CONFLICT 0x040 /* There is an address conflict. */
#define NF_POSSESSIVE 0x080 /* Keep address if lease expires. */
#define NF_INFORM 0x100 /* It's ok to answer DHCPINFORM. */
/* Functions defined in dhcpd.c. */
void report(const char *label);
void fatal(const char *label);
void *allocate(size_t size);
int ifname2if(const char *name);
network_t *if2net(int n);
/* Devices.c */
void get_buf(buf_t **bp);
void put_buf(buf_t **bp);
void give_buf(buf_t **dbp, buf_t **sbp);
network_t *newnetwork(void);
void closefd(fd_t *fdp);
int opendev(network_t *np, fdtype_t fdtype, int compete);
void closedev(network_t *np, fdtype_t fdtype);
char *ipdev(int n);
void set_ipconf(char *device, ipaddr_t ip, ipaddr_t mask, unsigned mtu);
/* Ether.c */
void udp2ether(buf_t *bp, network_t *np);
int ether2udp(buf_t *bp);
void make_arp(buf_t *bp, network_t *np);
int is_arp_me(buf_t *bp, network_t *np);
void icmp_solicit(buf_t *bp);
void icmp_advert(buf_t *bp, network_t *np);
ipaddr_t icmp_is_advert(buf_t *bp);
/* Tags.c */
#define gettag(dp, st, pd, pl) dhcp_gettag((dp), (st), (pd), (pl))
void settag(dhcp_t *dp, int tag, void *data, size_t len);
char *cidr_ntoa(ipaddr_t addr, ipaddr_t mask);
void ether2clid(u8_t *clid, ether_addr_t *eth);
void initdhcpconf(void);
int makedhcp(dhcp_t *dp, u8_t *class, size_t calen, u8_t *client, size_t cilen,
ipaddr_t ip, ipaddr_t ifip, network_t *np);
char *dhcptypename(int type);
void printdhcp(dhcp_t *dp);

View File

@ -1,206 +0,0 @@
/* ether.c - Raw Ethernet stuff
* Author: Kees J. Bot
* 16 Dec 2000
*/
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/asynchio.h>
#include <net/hton.h>
#include <net/gen/in.h>
#include <net/gen/ether.h>
#include <net/gen/eth_hdr.h>
#include <net/gen/ip_hdr.h>
#include <net/gen/icmp.h>
#include <net/gen/icmp_hdr.h>
#include <net/gen/oneCsum.h>
#include <net/gen/udp.h>
#include <net/gen/udp_hdr.h>
#include <net/gen/dhcp.h>
#include "arp.h"
#include "dhcpd.h"
static ether_addr_t BCAST_ETH = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
#define BCAST_IP htonl(0xFFFFFFFFUL)
#define LOCALHOST htonl(0x7F000001UL)
static u16_t udp_cksum(ipaddr_t src, ipaddr_t dst, udp_hdr_t *udp)
{
/* Compute the checksum of an UDP packet plus data. */
struct udp_pseudo {
ipaddr_t src, dst;
u8_t zero, proto;
u16_t length;
} pseudo;
size_t len;
/* Fill in the UDP pseudo header that must be prefixed to the UDP
* packet to compute the checksum of the whole thing.
*/
pseudo.src= src;
pseudo.dst= dst;
pseudo.zero= 0;
pseudo.proto= IPPROTO_UDP;
pseudo.length= udp->uh_length;
len= ntohs(udp->uh_length);
if (len & 1) {
/* Length is odd? Pad with a zero. */
B(udp)[len++]= 0;
}
return oneC_sum(oneC_sum(0, &pseudo, sizeof(pseudo)), udp, len);
}
void udp2ether(buf_t *bp, network_t *np)
{
/* Transform a packet in UDP format to raw Ethernet. Ignore the UDP
* addresses, always broadcast from 0.0.0.0.
*/
udp_io_hdr_t udpio;
/* Save the UDP I/O header. */
udpio= *bp->udpio;
/* Fill in the Ethernet, IP and UDP headers. */
bp->eth->eh_dst= BCAST_ETH;
bp->eth->eh_src= np->eth;
bp->eth->eh_proto= htons(ETH_IP_PROTO);
bp->ip->ih_vers_ihl= 0x45;
bp->ip->ih_tos= 0;
bp->ip->ih_length= htons(sizeof(ip_hdr_t)
+ sizeof(udp_hdr_t) + udpio.uih_data_len);
bp->ip->ih_id= 0;
bp->ip->ih_flags_fragoff= ntohs(0x4000);
bp->ip->ih_ttl= IP_MAX_TTL;
bp->ip->ih_proto= IPPROTO_UDP;
bp->ip->ih_hdr_chk= 0;
bp->ip->ih_src= 0;
bp->ip->ih_dst= BCAST_IP;
bp->ip->ih_hdr_chk= ~oneC_sum(0, bp->ip, sizeof(*bp->ip));
bp->udp->uh_src_port= udpio.uih_src_port;
bp->udp->uh_dst_port= udpio.uih_dst_port;
bp->udp->uh_length= htons(sizeof(udp_hdr_t) + udpio.uih_data_len);
bp->udp->uh_chksum= 0;
bp->udp->uh_chksum= ~udp_cksum(bp->ip->ih_src, bp->ip->ih_dst, bp->udp);
}
int ether2udp(buf_t *bp)
{
/* Transform an UDP packet read from raw Ethernet to normal UDP.
* Return true iff the packet is indeed UDP and has no errors.
*/
udp_io_hdr_t udpio;
if (bp->eth->eh_proto != htons(ETH_IP_PROTO)
|| bp->ip->ih_vers_ihl != 0x45
|| bp->ip->ih_proto != IPPROTO_UDP
|| oneC_sum(0, bp->ip, 20) != (u16_t) ~0
|| udp_cksum(bp->ip->ih_src, bp->ip->ih_dst, bp->udp) != (u16_t) ~0
) {
/* Not UDP/IP or checksums bad. */
return 0;
}
udpio.uih_src_addr= bp->ip->ih_src;
udpio.uih_dst_addr= bp->ip->ih_dst;
udpio.uih_src_port= bp->udp->uh_src_port;
udpio.uih_dst_port= bp->udp->uh_dst_port;
udpio.uih_ip_opt_len= 0;
udpio.uih_data_len= ntohs(bp->udp->uh_length) - sizeof(udp_hdr_t);
*bp->udpio= udpio;
return 1;
}
void make_arp(buf_t *bp, network_t *np)
{
/* Create an ARP packet to query for my IP address. */
arp46_t *arp= (arp46_t *) bp->eth;
memset(arp, 0, sizeof(*arp));
arp->dstaddr= BCAST_ETH;
arp->srcaddr= np->eth;
arp->ethtype= htons(ETH_ARP_PROTO);
arp->hdr= htons(ARP_ETHERNET);
arp->pro= htons(ETH_IP_PROTO);
arp->op= htons(ARP_REQUEST);
arp->hln= 6;
arp->pln= 4;
arp->sha= np->eth;
memcpy(arp->spa, &np->ip, sizeof(np->ip));
memcpy(arp->tpa, &np->ip, sizeof(np->ip));
}
int is_arp_me(buf_t *bp, network_t *np)
{
/* True iff an ARP packet is a reply from someone else with an address I
* thought was mine. (That's like, bad.)
*/
arp46_t *arp= (arp46_t *) bp->eth;
if (arp->ethtype == htons(ETH_ARP_PROTO)
&& arp->hdr == htons(ARP_ETHERNET)
&& arp->pro == htons(ETH_IP_PROTO)
&& arp->op == htons(ARP_REPLY)
&& memcmp(&arp->spa, &np->ip, sizeof(np->ip)) == 0
&& memcmp(&arp->sha, &np->eth, sizeof(np->eth)) != 0
) {
np->conflict= arp->sha;
return 1;
}
return 0;
}
void icmp_solicit(buf_t *bp)
{
/* Fill in a router solicitation ICMP packet. */
icmp_hdr_t *icmp= (icmp_hdr_t *) (bp->ip + 1);
bp->ip->ih_vers_ihl= 0x45;
bp->ip->ih_dst= BCAST_IP;
icmp->ih_type= ICMP_TYPE_ROUTE_SOL;
icmp->ih_code= 0;
icmp->ih_hun.ihh_unused= 0;
icmp->ih_chksum= 0;
icmp->ih_chksum= ~oneC_sum(0, icmp, 8);
}
void icmp_advert(buf_t *bp, network_t *np)
{
/* Fill in a router advert to be sent to my own interface. */
u32_t *data;
icmp_hdr_t *icmp= (icmp_hdr_t *) (bp->ip + 1);
bp->ip->ih_vers_ihl= 0x45;
bp->ip->ih_dst= LOCALHOST;
icmp->ih_type= ICMP_TYPE_ROUTER_ADVER;
icmp->ih_code= 0;
icmp->ih_hun.ihh_ram.iram_na= 1;
icmp->ih_hun.ihh_ram.iram_aes= 2;
icmp->ih_hun.ihh_ram.iram_lt= htons(DELTA_ADV);
data = (u32_t *) icmp->ih_dun.uhd_data;
data[0] = np->gateway;
data[1] = htonl((u32_t) -9999);
icmp->ih_chksum= 0;
icmp->ih_chksum= ~oneC_sum(0, icmp, 16);
}
ipaddr_t icmp_is_advert(buf_t *bp)
{
/* Check if an IP packet is a router advertisement, and if it's genuine,
* i.e. the sender is mentioned in the packet.
*/
icmp_hdr_t *icmp= (icmp_hdr_t *) (bp->ip + 1);
int i;
if (icmp->ih_type == ICMP_TYPE_ROUTER_ADVER) {
for (i= 0; i < icmp->ih_hun.ihh_ram.iram_na; i++) {
if (((u32_t *) icmp->ih_dun.uhd_data)[2*i] == bp->ip->ih_src) {
/* It's a router! */
return bp->ip->ih_src;
}
}
}
return 0;
}

View File

@ -1,926 +0,0 @@
/* tags.c - Obtain DHCP tags from the config file
* Author: Kees J. Bot
* 16 Dec 2000
*/
#include <sys/types.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <configfile.h>
#include <sys/ioctl.h>
#include <sys/asynchio.h>
#include <net/hton.h>
#include <net/gen/socket.h>
#include <netdb.h>
#include <net/gen/in.h>
#include <net/gen/inet.h>
#include <net/gen/ether.h>
#include <net/gen/if_ether.h>
#include <net/gen/eth_hdr.h>
#include <net/gen/ip_hdr.h>
#include <net/gen/udp.h>
#include <net/gen/udp_hdr.h>
#include <net/gen/dhcp.h>
#include <arpa/inet.h>
#include "dhcpd.h"
#define doff(field) offsetof(dhcp_t, field)
void settag(dhcp_t *dp, int tag, void *data, size_t len)
{
if (!dhcp_settag(dp, tag, data, len)) {
/* Oops, it didn't fit? Is this really Minix??? */
fprintf(stderr,
"%s: DHCP packet too big, please trim the configuration\n",
program);
exit(1);
}
}
static int name2ip(ipaddr_t *pip, const char *name, ipaddr_t ifip)
{
/* Translate a name to an IP address, preferably from the hosts file,
* but also from the DNS if being a server. Prefer the address closest
* to the interface with IP address 'ifip' if there are choices..
*/
extern struct hostent *_gethostent(void); /* File reading versions. */
extern void _endhostent(void);
struct hostent *he;
size_t len= strlen(name);
u32_t d, distance= -1;
ipaddr_t ip;
int i;
char *hn;
/* Already an IP address? */
if (inet_aton(name, (struct in_addr *)pip)) return 1;
/* In the hosts file? */
while ((he= _gethostent()) != nil) {
hn= he->h_name;
i= -1;
do {
if (strncasecmp(name, hn, len) == 0
&& (hn[len] == 0 || hn[len] == '.')
) {
memcpy(&ip, he->h_addr, sizeof(ip));
d= ntohl(ip) ^ ntohl(ifip);
if (d < distance) {
*pip= ip;
distance= d;
}
break;
}
} while ((hn= he->h_aliases[++i]) != nil);
}
_endhostent();
if (distance < -1) return 1;
/* Nothing? Try the real DNS if being a server. */
if (serving) {
if ((he= gethostbyname(name)) != nil && he->h_addrtype == AF_INET) {
/* Select the address closest to 'ifip'. */
for (i= 0; he->h_addr_list[i] != nil; i++) {
memcpy(&ip, he->h_addr_list[i], sizeof(ip));
d= ntohl(ip) ^ ntohl(ifip);
if (d < distance) {
*pip= ip;
distance= d;
}
}
return 1;
}
}
return 0;
}
static char *ip2name(ipaddr_t ip)
{
/* Translate an IP address to a name, etc, etc. */
extern struct hostent *_gethostent(void); /* File reading versions. */
extern void _endhostent(void);
struct hostent *he;
/* In the hosts file? */
while ((he= _gethostent()) != nil) {
if (memcmp(he->h_addr, &ip, sizeof(ip)) == 0) break;
}
_endhostent();
/* Nothing? Try the real DNS if being a server. */
if (he == nil && serving) {
he= gethostbyaddr((char *) &ip, sizeof(ip), AF_INET);
}
return he != nil ? he->h_name : nil;
}
static int cidr_aton(const char *cidr, ipaddr_t *addr, ipaddr_t *mask)
{
char *slash, *check;
ipaddr_t a;
int ok;
unsigned long len;
if ((slash= strchr(cidr, '/')) == nil) return 0;
*slash++= 0;
ok= inet_aton(cidr, (struct in_addr *)&a);
len= strtoul(slash, &check, 10);
if (check == slash || *check != 0 || len > 32) ok= 0;
*--slash= '/';
if (!ok) return 0;
*addr= a;
*mask= htonl(len == 0 ? 0 : (0xFFFFFFFFUL << (32-len)) & 0xFFFFFFFFUL);
return 1;
}
char *cidr_ntoa(ipaddr_t addr, ipaddr_t mask)
{
ipaddr_t testmask= 0xFFFFFFFFUL;
int n;
static char result[sizeof("255.255.255.255/255.255.255.255")];
for (n= 32; n >= 0; n--) {
if (mask == htonl(testmask)) break;
testmask= (testmask << 1) & 0xFFFFFFFFUL;
}
sprintf(result, "%s/%-2d", inet_ntoa(*(struct in_addr *)&addr), n);
if (n == -1) strcpy(strchr(result, '/')+1,
inet_ntoa(*(struct in_addr *)&mask));
return result;
}
static size_t ascii2octet(u8_t *b, size_t size, const char *a)
{
/* Convert a series of hex digit pairs to an octet (binary) array at
* 'b' with length 'size'. Return the number of octets in 'a' or
* -1 on error.
*/
size_t len;
int n, c;
len= 0;
n= 0;
while ((c= *a++) != 0) {
if (between('0', c, '9')) c= (c - '0') + 0x0;
else
if (between('a', c, 'f')) c= (c - 'a') + 0xa;
else
if (between('A', c, 'F')) c= (c - 'A') + 0xA;
else {
return -1;
}
if (n == 0) {
if (len < size) b[len] = c << 4;
} else {
if (len < size) b[len] |= c;
len++;
}
n ^= 1;
}
return n == 0 ? len : -1;
}
void ether2clid(u8_t *clid, ether_addr_t *eth)
{
/* Convert an Ethernet address to the default client ID form. */
clid[0]= DHCP_HTYPE_ETH;
memcpy(clid+1, eth, DHCP_HLEN_ETH);
}
static size_t ascii2clid(u8_t *clid, const char *a)
{
/* Convert an ethernet address, or a series of hex digits to a client ID.
* Return its length if ok, otherwise -1.
*/
size_t len;
ether_addr_t *eth;
if ((eth= ether_aton(a)) != nil) {
ether2clid(clid, eth);
len= 1+DHCP_HLEN_ETH;
} else {
len= ascii2octet(clid, CLID_MAX, a);
}
return len;
}
static config_t *dhcpconf; /* In-core DHCP configuration. */
/* DHCP tag types. */
typedef enum { TT_ASCII, TT_BOOLEAN, TT_IP, TT_NUMBER, TT_OCTET } tagtype_t;
/* DHCP/BOOTP tag definitions. */
typedef struct tagdef {
u8_t tag; /* Tag number. */
u8_t type; /* Type and flags. */
u8_t gran; /* Granularity. */
u8_t max; /* Maximum number of arguments. */
const char *name; /* Defined name. */
} tagdef_t;
#define TF_TYPE 0x07 /* To mask out the type. */
#define TF_STATIC 0x08 /* "Static", i.e. a struct field. */
#define TF_RO 0x10 /* Read-only, user can't set. */
/* List of static DHCP fields. The tag field is misused here as an offset
* into the DHCP structure.
*/
static tagdef_t statictag[] = {
{ doff(op), TT_NUMBER|TF_STATIC|TF_RO, 1, 1, "op" },
{ doff(htype), TT_NUMBER|TF_STATIC|TF_RO, 1, 1, "htype" },
{ doff(hlen), TT_NUMBER|TF_STATIC|TF_RO, 1, 1, "hlen" },
{ doff(hops), TT_NUMBER|TF_STATIC|TF_RO, 1, 1, "hops" },
{ doff(xid), TT_NUMBER|TF_STATIC|TF_RO, 4, 1, "xid" },
{ doff(secs), TT_NUMBER|TF_STATIC|TF_RO, 2, 1, "secs" },
{ doff(flags), TT_NUMBER|TF_STATIC|TF_RO, 2, 1, "flags" },
{ doff(ciaddr), TT_IP|TF_STATIC|TF_RO, 1, 1, "ciaddr" },
{ doff(yiaddr), TT_IP|TF_STATIC|TF_RO, 1, 1, "yiaddr" },
{ doff(siaddr), TT_IP|TF_STATIC, 1, 1, "siaddr" },
{ doff(giaddr), TT_IP|TF_STATIC|TF_RO, 1, 1, "giaddr" },
{ doff(chaddr), TT_OCTET|TF_STATIC|TF_RO, 1, 16, "chaddr" },
{ doff(sname), TT_ASCII|TF_STATIC, 1, 64, "sname" },
{ doff(file), TT_ASCII|TF_STATIC, 1, 128, "file" },
};
#define N_STATIC arraysize(statictag)
static tagdef_t alltagdef[N_STATIC + 254]; /* List of tag definitions. */
#define tagdef (alltagdef+N_STATIC-1) /* Just the optional ones. */
#define tagdefined(tp) ((tp)->name != nil)
static void inittagdef(void)
{
/* Initialize the tag definitions from the "tag" commands in the config
* file.
*/
int t;
tagdef_t *tp;
static tagdef_t predef[] = {
{ DHCP_TAG_NETMASK, TT_IP, 1, 1, "netmask" },
{ DHCP_TAG_GATEWAY, TT_IP, 1, 255, "gateway" },
{ DHCP_TAG_DNS, TT_IP, 1, 255, "DNSserver" },
};
static char *typenames[] = { "ascii", "boolean", "ip", "number", "octet" };
config_t *cfg;
static u8_t rotags[] = {
DHCP_TAG_REQIP, DHCP_TAG_OVERLOAD, DHCP_TAG_TYPE, DHCP_TAG_SERVERID,
DHCP_TAG_REQPAR, DHCP_TAG_MESSAGE, DHCP_TAG_MAXDHCP
};
for (t= 1; t <= 254; t++) {
tp= &tagdef[t];
tp->tag= t;
tp->type= TT_OCTET;
tp->name= nil;
}
/* Set the static and "all Minix needs" tags. */
memcpy(alltagdef, statictag, sizeof(statictag));
for (tp= predef; tp < arraylimit(predef); tp++) tagdef[tp->tag] = *tp;
/* Search for tag definitions in the config file. */
for (cfg= dhcpconf; cfg != nil; cfg= cfg->next) {
config_t *cmd= cfg->list;
if (strcasecmp(cmd->word, "tag") == 0) {
if (config_length(cmd) == 6
&& (cmd->next->flags & CFG_DULONG)
&& config_isatom(cmd->next->next)
&& config_isatom(cmd->next->next->next)
&& (cmd->next->next->next->next->flags & CFG_DULONG)
&& (cmd->next->next->next->next->next->flags & CFG_DULONG)
) {
unsigned long tag, gran, max;
const char *name, *typename;
unsigned type;
tag= strtoul(cmd->next->word, nil, 10);
name= cmd->next->next->word;
typename= cmd->next->next->next->word;
gran= strtoul(cmd->next->next->next->next->word, nil, 10);
max= strtoul(cmd->next->next->next->next->next->word, nil, 10);
for (type= 0; type < arraysize(typenames); type++) {
if (strcasecmp(typename, typenames[type]) == 0) break;
}
if (!(1 <= tag && tag <= 254)
|| !(type < arraysize(typenames))
|| !((type == TT_NUMBER
&& (gran == 1 || gran == 2 || gran == 4))
|| (type != TT_NUMBER && 1 <= gran && gran <= 16))
|| !(max <= 255)
) {
fprintf(stderr,
"\"%s\", line %u: Tag definition is incorrect\n",
cmd->file, cmd->line);
exit(1);
}
tp= &tagdef[(int)tag];
tp->type= type;
tp->name= name;
tp->gran= gran;
tp->max= max;
} else {
fprintf(stderr,
"\"%s\", line %u: Usage: tag number name type granularity max\n",
cmd->file, cmd->line);
exit(1);
}
}
}
/* Many DHCP tags are not for the user to play with. */
for (t= 0; t < arraysize(rotags); t++) tagdef[rotags[t]].type |= TF_RO;
}
static tagdef_t *tagdefbyname(const char *name)
{
/* Find a tag definition by the name of the tag. Return null if not
* defined.
*/
tagdef_t *tp;
for (tp= alltagdef; tp < arraylimit(alltagdef); tp++) {
if (tagdefined(tp) && strcasecmp(tp->name, name) == 0) return tp;
}
return nil;
}
void initdhcpconf(void)
{
/* Read/refresh configuration from the DHCP configuration file. */
dhcpconf= config_read(configfile, 0, dhcpconf);
if (config_renewed(dhcpconf)) inittagdef();
}
static void configtag(dhcp_t *dp, config_t *cmd, ipaddr_t ifip)
{
/* Add a tag to a DHCP packet from the config file. */
tagdef_t *tp;
u8_t data[260], *d;
size_t i;
int delete= 0;
if (strcasecmp(cmd->word, "no") == 0) {
if (config_length(cmd) != 2 || !config_isatom(cmd->next)) {
fprintf(stderr, "\"%s\", line %u: Usage: no tag-name\n",
cmd->file, cmd->line);
exit(1);
}
cmd= cmd->next;
delete= 1;
}
if ((tp= tagdefbyname(cmd->word)) == nil) {
fprintf(stderr, "\"%s\", line %u: Unknown tag '%s'\n",
cmd->file, cmd->line, cmd->word);
exit(1);
}
if (tp->type & TF_RO) {
fprintf(stderr, "\"%s\", line %u: Tag '%s' can't be configured\n",
cmd->file, cmd->line, cmd->word);
exit(1);
}
i= 0;
d= data;
if (!delete) {
config_t *arg= cmd->next;
do {
switch (tp->type & TF_TYPE) {
case TT_ASCII: {
if (arg == nil || !config_isatom(arg) || arg->next != nil) {
fprintf(stderr, "\"%s\", line %u: Usage: %s string\n",
cmd->file, cmd->line, cmd->word);
exit(1);
}
strncpy((char *) data, arg->word, sizeof(data));
d += i = strnlen((char *) data, sizeof(data));
break;}
case TT_BOOLEAN: {
if (arg == nil || !config_isatom(arg)
|| !(strcasecmp(arg->word, "false") == 0
|| strcasecmp(arg->word, "true") == 0)
) {
fprintf(stderr,
"\"%s\", line %u: Usage: %s false|true ...\n",
cmd->file, cmd->line, cmd->word);
exit(1);
}
if (d < arraylimit(data)) {
*d++ = (arg->word[0] != 'f' && arg->word[0] != 'F');
}
i++;
break;}
case TT_IP: {
ipaddr_t ip;
unsigned long len;
char *end;
if (arg == nil || !config_isatom(arg)) {
fprintf(stderr, "\"%s\", line %u: Usage: %s host ...\n",
cmd->file, cmd->line, cmd->word);
exit(1);
}
if (arg->word[0] == '/'
&& between(1, len= strtoul(arg->word+1, &end, 10), 31)
&& *end == 0
) {
ip= htonl((0xFFFFFFFFUL << (32-len)) & 0xFFFFFFFFUL);
} else
if (!name2ip(&ip, arg->word, ifip)) {
fprintf(stderr,
"\"%s\", line %u: Can't translate %s to an IP address\n",
arg->file, arg->line, arg->word);
exit(1);
}
if (d <= arraylimit(data) - sizeof(ip)) {
memcpy(d, &ip, sizeof(ip));
d += sizeof(ip);
}
i++;
break;}
case TT_NUMBER: {
unsigned long n;
int g;
if (arg == nil || !(arg->flags & CFG_CLONG)) {
fprintf(stderr, "\"%s\", line %u: Usage: %s number ...\n",
cmd->file, cmd->line, cmd->word);
exit(1);
}
n= strtoul(arg->word, nil, 0);
g= tp->gran;
do {
if (d <= arraylimit(data)) *d++ = (n >> (--g * 8)) & 0xFF;
} while (g != 0);
i++;
break;}
case TT_OCTET: {
if (arg == nil || !config_isatom(arg) || arg->next != nil) {
fprintf(stderr, "\"%s\", line %u: Usage: %s hexdigits\n",
cmd->file, cmd->line, cmd->word);
exit(1);
}
i= ascii2octet(data, sizeof(data), arg->word);
if (i == -1) {
fprintf(stderr,
"\"%s\", line %u: %s: Bad hexdigit string\n",
arg->file, arg->line, arg->word);
exit(1);
}
d= data + i;
break;}
}
} while ((arg= arg->next) != nil);
if (d > data + 255) {
fprintf(stderr, "\"%s\", line %u: Tag value is way too big\n",
cmd->file, cmd->line);
exit(1);
}
if ((tp->type & TF_TYPE) != TT_NUMBER && (i % tp->gran) != 0) {
fprintf(stderr,
"\"%s\", line %u: Expected a multiple of %d initializers\n",
cmd->file, cmd->line, tp->gran);
exit(1);
}
if (tp->max != 0 && i > tp->max) {
fprintf(stderr,
"\"%s\", line %u: Got %d initializers, can have only %d\n",
cmd->file, cmd->line, (int) i, tp->max);
exit(1);
}
}
if (tp->type & TF_STATIC) {
size_t len= tp->gran * tp->max;
if ((tp->type & TF_TYPE) == TT_IP) len *= sizeof(ipaddr_t);
memset(B(dp) + tp->tag, 0, len);
memcpy(B(dp) + tp->tag, data, (d - data));
} else {
settag(dp, tp->tag, data, (d - data));
}
}
int makedhcp(dhcp_t *dp, u8_t *class, size_t calen, u8_t *client, size_t cilen,
ipaddr_t ip, ipaddr_t ifip, network_t *np)
{
/* Fill in a DHCP packet at 'dp' for the host identified by the
* (class, client, ip) combination. Makedhcp is normally called twice,
* once to find the IP address (so ip == 0) and once again to find all
* data that goes with that IP address (ip != 0). On the first call the
* return value of this function should be ignored and only 'yiaddr'
* checked and used as 'ip' on the next pass. True is returned iff there
* is information for the client on the network at interface address
* 'ifip', by checking if the 'ip' and 'ifip' are on the same network.
* If np is nonnull then we are working for one of our own interfaces, so
* options can be set and adjourning interfaces can be programmed.
*/
config_t *todo[16];
size_t ntodo= 0;
ipaddr_t hip, mask;
u8_t *pmask;
char *hostname;
u32_t distance= -1;
initdhcpconf();
/* Start creating a packet. */
dhcp_init(dp);
dp->op= DHCP_BOOTREPLY;
/* The initial TODO list is the whole DHCP config. */
todo[ntodo++]= dhcpconf;
while (ntodo > 0) {
config_t *cmd, *follow;
if (todo[ntodo-1] == nil) { ntodo--; continue; }
cmd= todo[ntodo-1]->list;
todo[ntodo-1]= todo[ntodo-1]->next;
follow= nil; /* Macro or list to follow next? */
if (strcasecmp(cmd->word, "client") == 0) {
u8_t cfgid[CLID_MAX];
size_t cfglen;
char *name;
int ifno;
u32_t d;
if (between(3, config_length(cmd), 5)
&& config_isatom(cmd->next)
&& (cfglen= ascii2clid(cfgid, cmd->next->word)) != -1
&& config_isatom(cmd->next->next)
&& (((ifno= ifname2if(cmd->next->next->word)) == -1
&& config_length(cmd) <= 4)
|| ((ifno= ifname2if(cmd->next->next->word)) != -1
&& config_length(cmd) >= 4
&& config_isatom(cmd->next->next->next)))
) {
if (cilen == cfglen && memcmp(client, cfgid, cilen) == 0
&& (ifno == -1 || np == nil || ifno == np->n)
) {
config_t *atname= cmd->next->next;
if (ifno != -1) atname= atname->next;
name= (char *)atname->word;
if (name2ip(&hip, name, ifip) && (ip == 0 || ip == hip)) {
d= ntohl(hip) ^ ntohl(ifip);
if (d < distance) {
dp->yiaddr= hip;
follow= atname->next;
distance= d;
}
}
}
} else {
fprintf(stderr,
"\"%s\", line %u: Usage: client ID [ip#] host [macro|{params}]\n",
cmd->file, cmd->line);
exit(1);
}
} else
if (strcasecmp(cmd->word, "class") == 0) {
config_t *clist;
int match;
match= 0;
for (clist= cmd->next; clist != nil
&& clist->next != nil
&& config_isatom(clist); clist= clist->next) {
if (calen > 0
&& strncmp(clist->word, (char *) class, calen) == 0
) {
match= 1;
}
}
if (clist == cmd->next || clist->next != nil) {
fprintf(stderr,
"\"%s\", line %u: Usage: class class-name ... macro|{params}\n",
cmd->file, cmd->line);
}
if (match) follow= clist;
} else
if (strcasecmp(cmd->word, "host") == 0) {
if (config_length(cmd) == 3
&& config_isatom(cmd->next)
) {
if (ip != 0) {
if (cidr_aton(cmd->next->word, &hip, &mask)) {
if (((hip ^ ip) & mask) == 0) {
if (!gettag(dp, DHCP_TAG_NETMASK, nil, nil)) {
settag(dp, DHCP_TAG_NETMASK,
&mask, sizeof(mask));
}
dp->yiaddr= ip;
follow= cmd->next->next;
}
} else
if (name2ip(&hip, cmd->next->word, ifip)) {
if (hip == ip) {
dp->yiaddr= ip;
follow= cmd->next->next;
}
}
}
} else {
fprintf(stderr,
"\"%s\", line %u: Usage: host host-spec macro|{params}\n",
cmd->file, cmd->line);
exit(1);
}
} else
if (strcasecmp(cmd->word, "interface") == 0) {
if (between(3, config_length(cmd), 4)
&& config_isatom(cmd->next)
&& config_isatom(cmd->next->next)
) {
network_t *ifnp;
if (np != nil) {
if ((ifnp= if2net(ifname2if(cmd->next->word))) == nil) {
fprintf(stderr,
"\"%s\", line %u: Can't find interface %s\n",
cmd->next->file, cmd->next->line, cmd->next->word);
exit(1);
}
if (!name2ip(&hip, cmd->next->next->word, 0)) {
fprintf(stderr,
"\"%s\", line %u: Can't find IP address of %s\n",
cmd->next->next->file, cmd->next->next->line,
cmd->next->next->word);
exit(1);
}
ifnp->ip= hip;
if (ifnp == np) {
dp->yiaddr= hip;
follow= cmd->next->next->next;
}
}
} else {
fprintf(stderr,
"\"%s\", line %u: Usage: interface ip# host%s\n",
cmd->file, cmd->line, ntodo==1 ? " [macro|{params}]" : "");
exit(1);
}
} else
if (strcasecmp(cmd->word, "macro") == 0) {
if (config_length(cmd) == 2 && config_isatom(cmd->next)) {
follow= cmd->next;
} else
if (ntodo > 1) {
fprintf(stderr, "\"%s\", line %u: Usage: macro macro-name\n",
cmd->file, cmd->line);
exit(1);
}
} else
if (strcasecmp(cmd->word, "tag") == 0) {
if (ntodo > 1) {
fprintf(stderr,
"\"%s\", line %u: A %s can't be defined here\n",
cmd->file, cmd->line, cmd->word);
exit(1);
}
} else
if (strcasecmp(cmd->word, "option") == 0) {
int ifno;
network_t *ifnp;
config_t *opt;
if ((opt= cmd->next) != nil
&& config_isatom(opt)
&& (ifno= ifname2if(opt->word)) != -1
) {
if ((ifnp= if2net(ifno)) == nil) {
fprintf(stderr,
"\"%s\", line %u: Interface %s is not enabled\n",
opt->file, opt->line, opt->word);
exit(1);
}
opt= opt->next;
} else {
ifnp= np;
}
if (between(1, config_length(opt), 2)
&& config_isatom(opt)
&& strcasecmp(opt->word, "server") == 0
&& (opt->next == nil
|| strcasecmp(opt->next->word, "inform") == 0)
) {
if (np != nil) {
ifnp->flags |= NF_SERVING;
if (opt->next != nil) ifnp->flags |= NF_INFORM;
}
} else
if (config_length(opt) == 2
&& config_isatom(opt)
&& strcasecmp(opt->word, "relay") == 0
&& config_isatom(opt->next)
) {
if (np != nil) {
if (!name2ip(&hip, opt->next->word, ifip)) {
fprintf(stderr,
"\"%s\", line %u: Can't find IP address of %s\n",
opt->next->file, opt->next->line,
opt->next->word);
exit(1);
}
ifnp->flags |= NF_RELAYING;
ifnp->server= hip;
}
} else
if (config_length(opt) == 1
&& config_isatom(opt)
&& strcasecmp(opt->word, "possessive") == 0
) {
if (np != nil) ifnp->flags |= NF_POSSESSIVE;
} else
if (config_length(opt) == 2
&& config_isatom(opt)
&& strcasecmp(opt->word, "hostname") == 0
&& config_isatom(opt->next)
) {
if (np != nil) np->hostname= opt->next->word;
} else {
fprintf(stderr, "\"%s\", line %u: Unknown option\n",
cmd->file, cmd->line);
exit(1);
}
} else {
/* Must be an actual data carrying tag. */
configtag(dp, cmd, ifip);
}
if (follow != nil) {
/* A client/class/host entry selects a macro or list that must
* be followed next.
*/
config_t *macro;
if (config_isatom(follow)) { /* Macro name */
config_t *cfg;
for (cfg= dhcpconf; cfg != nil; cfg= cfg->next) {
macro= cfg->list;
if (strcasecmp(macro->word, "macro") == 0) {
if (config_length(macro) == 3
&& config_isatom(macro->next)
&& config_issub(macro->next->next)
) {
if (strcasecmp(macro->next->word, follow->word) == 0
) {
break;
}
} else {
fprintf(stderr,
"\"%s\", line %u: Usage: macro macro-name {params}\n",
macro->file, macro->line);
}
}
}
follow= cfg == nil ? nil : macro->next->next->list;
} else {
/* Simply a list of more tags and stuff. */
follow= follow->list;
}
if (ntodo == arraysize(todo)) {
fprintf(stderr, "\"%s\", line %u: Nesting is too deep\n",
follow->file, follow->line);
exit(1);
}
todo[ntodo++]= follow;
}
}
/* Check if the IP and netmask are OK for the interface. */
if (!gettag(dp, DHCP_TAG_NETMASK, &pmask, nil)) return 0;
memcpy(&mask, pmask, sizeof(mask));
if (((ip ^ ifip) & mask) != 0) return 0;
/* Fill in the hostname and/or domain. */
if ((hostname= ip2name(ip)) != nil) {
char *domain;
if ((domain= strchr(hostname, '.')) != nil) *domain++ = 0;
if (!gettag(dp, DHCP_TAG_HOSTNAME, nil, nil)) {
settag(dp, DHCP_TAG_HOSTNAME, hostname, strlen(hostname));
}
if (domain != nil && !gettag(dp, DHCP_TAG_DOMAIN, nil, nil)) {
settag(dp, DHCP_TAG_DOMAIN, domain, strlen(domain));
}
}
return 1;
}
static char *dhcpopname(int op)
{
static char *onames[] = { "??\?", "REQUEST", "REPLY" };
return onames[op < arraysize(onames) ? op : 0];
}
char *dhcptypename(int type)
{
static char *tnames[] = {
"??\?", "DISCOVER", "OFFER", "REQUEST", "DECLINE",
"ACK", "NAK", "RELEASE", "INFORM"
};
return tnames[type < arraysize(tnames) ? type : 0];
}
void printdhcp(dhcp_t *dp)
{
/* Print the contents of a DHCP packet, usually for debug purposes. */
tagdef_t *tp;
u8_t *data, *ovld;
size_t i, len;
for (tp= alltagdef; tp < arraylimit(alltagdef); tp++) {
if (tp->type & TF_STATIC) {
data= B(dp) + tp->tag;
len= tp->gran * tp->max;
if ((tp->type & TF_TYPE) == TT_IP) len *= sizeof(ipaddr_t);
if (tp->tag == doff(chaddr)) len= dp->hlen;
/* Don't show uninteresting stuff. */
if (tp->tag == doff(htype) && dp->htype == DHCP_HTYPE_ETH) continue;
if (tp->tag == doff(hlen) && dp->hlen == DHCP_HLEN_ETH) continue;
if ((tp->tag == doff(file) || tp->tag == doff(sname))
&& gettag(dp, DHCP_TAG_OVERLOAD, &ovld, nil)
&& (ovld[0] & (tp->tag == doff(file) ? 1 : 2))
) {
continue;
}
for (i= 0; i < len && data[i] == 0; i++) {}
if (i == len) continue;
} else {
if (!gettag(dp, tp->tag, &data, &len)) continue;
}
if (tagdefined(tp)) {
printf("\t%s =", tp->name);
} else {
printf("\tT%d =", tp->tag);
}
i= 0;
while (i < len) {
switch (tp->type & TF_TYPE) {
case TT_ASCII: {
printf(" \"%.*s\"", (int) len, data);
i= len;
break;}
case TT_BOOLEAN: {
printf(data[i++] == 0 ? " false" : " true");
break;}
case TT_IP: {
ipaddr_t ip;
memcpy(&ip, data+i, sizeof(ip));
printf(" %s", inet_ntoa(*(struct in_addr *)&ip));
i += sizeof(ip);
break;}
case TT_NUMBER: {
u32_t n= 0;
int g= tp->gran;
do n= (n << 8) | data[i++]; while (--g != 0);
printf(" %lu", (unsigned long) n);
if ((tp->type & TF_STATIC) && tp->tag == doff(op)) {
printf(" (%s)", dhcpopname(n));
}
if (!(tp->type & TF_STATIC) && tp->tag == DHCP_TAG_TYPE) {
printf(" (%s)", dhcptypename(n));
}
break;}
case TT_OCTET: {
if (i == 0) fputc(' ', stdout);
printf("%02X", data[i++]);
break;}
}
}
fputc('\n', stdout);
}
}

View File

@ -8,11 +8,6 @@
#define _PATH_SYSTEM_CONF_DIR "/etc/system.conf.d"
#define _PATH_SYSTEM_CONF_PKG_DIR "/usr/pkg/etc/system.conf.d"
#define _PATH_DHCPCONF "/etc/dhcp.conf"
#define _PATH_DHCPPID "/usr/run/dhcpd.pid"
#define _PATH_DHCPCACHE "/usr/adm/dhcp.cache"
#define _PATH_DHCPPOOL "/usr/adm/dhcp.pool"
#define _PATH_RAMDISK "/dev/ram"
#define _PATH_DRIVERS "/service"

View File

@ -1,55 +0,0 @@
/* dhcp_gettag() Author: Kees J. Bot
* 1 Dec 2000
*/
#define nil ((void*)0)
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <net/hton.h>
#include <net/gen/in.h>
#include <net/gen/dhcp.h>
#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
int dhcp_gettag(dhcp_t *dp, int searchtag, u8_t **pdata, size_t *plen)
{
/* Find a tag in the options field, or possibly in the file or sname
* fields. Return true iff found, and return the data and/or length if
* their pointers are non-null.
*/
u8_t *p;
u8_t *optfield[3];
size_t optlen[3];
int i, tag, len;
/* The DHCP magic number must be correct, or no tags. */
if (dp->magic != DHCP_MAGIC) return 0;
optfield[0]= dp->options;
optlen[0]= arraysize(dp->options);
optfield[1]= dp->file;
optlen[1]= 0; /* Unknown if used for options yet. */
optfield[2]= dp->sname;
optlen[2]= 0;
for (i= 0; i < 3; i++) {
p= optfield[i];
while (p < optfield[i] + optlen[i]) {
tag= *p++;
if (tag == 255) break;
len= tag == 0 ? 0 : *p++;
if (tag == searchtag) {
if (pdata != nil) *pdata= p;
if (plen != nil) *plen= len;
return 1;
}
if (tag == DHCP_TAG_OVERLOAD) {
/* There are also options in the file or sname field. */
if (*p & 1) optlen[1]= arraysize(dp->file);
if (*p & 2) optlen[1]= arraysize(dp->sname);
}
p += len;
}
}
return 0;
}

View File

@ -1,57 +0,0 @@
/* dhcp_init(), dhcp_settag() Author: Kees J. Bot
* 1 Dec 2000
*/
#define nil ((void*)0)
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <net/hton.h>
#include <net/gen/in.h>
#include <net/gen/dhcp.h>
#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
#define arraylimit(a) ((a) + arraysize(a))
void dhcp_init(dhcp_t *dp)
{
/* Initialize a DHCP packet. */
memset(dp, 0, offsetof(dhcp_t, magic));
dp->magic= DHCP_MAGIC;
memset(dp->options, 255, sizeof(dp->options));
}
int dhcp_settag(dhcp_t *dp, int tag, void *data, size_t len)
{
/* Add a tag to a DHCP packet. No padding. Only do the options field.
* (This is Minix, we don't need megabytes of silly bits of data.)
* The length may be zero to delete a tag.
*/
u8_t *p;
int n;
if (tag <= 0 || tag >= 255) return 0;
for (p= dp->options; p < arraylimit(dp->options) && *p != 255; p += n) {
n= 1 + 1 + p[1];
if (*p == tag) {
/* The tag is already there, remove it so it gets replaced. */
memmove(p, p + n, arraylimit(dp->options) - (p + n));
memset(arraylimit(dp->options) - n, 255, n);
n= 0;
}
}
/* Add tag. */
if (len == 0) {
/* We're merely deleting a tag. */
} else
if (p + 1 + 1 + len <= arraylimit(dp->options)) {
*p++ = tag;
*p++ = len;
memcpy(p, data, len);
} else {
/* Oops, it didn't fit? Is this really Minix??? */
return 0;
}
return 1;
}

View File

@ -71,9 +71,6 @@ A file that doesn't exist is seen as empty.
.PP
A generic configuration file can be read with the functions described in
.BR configfile (3).
.SH EXAMPLES
Have a look at
.BR /etc/dhcp.conf .
.SH "SEE ALSO"
.BR configfile (3).
.SH NOTES