Rearrange bootpd

This commit is contained in:
pst 1994-09-30 05:45:07 +00:00
commit 68e1cd350c
44 changed files with 9966 additions and 0 deletions

63
libexec/bootpd/Announce Normal file
View File

@ -0,0 +1,63 @@
This is an enhanced version of the CMU BOOTP server which was derived
from the original BOOTP server created by Bill Croft at Stanford.
This version merges most of the enhancements and bug-fixes from the
NetBSD, Columbia, and other versions.
New features in version 2.4 include:
Added a simple BOOTP gateway program: bootpgw
Allow host name anywhere IP address is expected.
Automatically lookup the IP address when the name of a
bootptab entry is a valid hostname.
(Dummy entries names should start with '.')
Merged changes from NetBSD and Columbia versions.
Merged changes for Solaris-2.X and SVR4 systems.
Combined bootptest into the bootp release.
Merged tag 18 support (:ef=...:) from Jason Zions.
Use :ef=extension_file_name: and make the
extension files for all clients using bootpef.
Merged HP compatibility (:ra=...:) from David R Linn.
Allows you to override the reply address.
(i.e. send the reply to a broadcast address)
Add /etc/ethers support for NetBSD.
More systems support getether (Ultrix, OSF, NetBSD)
Added RFC 1533 tags 40,41,42
:yd=<NIS domain>:ys=<NIS server>:nt=<NTP server>:
ConvOldTab.sh to convert old (1.1) bootptab to new format.
Permits extended-length replies with more option data.
Problems fixed in this version:
Fixed references to free host structures.
(used to cause core dump on Solaris)
Remove change that added null terminator to string options.
(this annoyed some clients...)
Add missing symbols to dump routine, fix order.
Works (again) with no -DSYSLOGD defined.
Fixed several more NULL references in readfile.
Added proper length checks to option insertions.
Fixed bootptest IP address printing.
Cleaned-up signed/unsigned and byteorder bugs.
Added SVR4/Streams support to getif and getether
Removed extra newlines in syslog messages.
Specify facility code when calling syslog(3)
When lookup_hwa fails, assume numeric HW address.
Systems on which I have seen this code work:
SunOS 4.X (Solaris 1.X)
SunOS 5.X (Solaris 2.X)
System V/386 Rel. 4.0
Systems on which others say this code works:
CDC EP/IX (1.4.3, 2.1.1)
DEC Ultrix (4.2, 4.3)
NetBSD (Current-8/94)
OSF/1 (DEC Alpha CPU)
Please direct questions, comments, and bug reports to:
<bootp@andrew.cmu.edu>
Gordon W. Ross Mercury Computer Systems
gwr@mc.com 199 Riverneck Road
508-256-1300 Chelmsford, MA 01824-2820

245
libexec/bootpd/Changes Normal file
View File

@ -0,0 +1,245 @@
Changes, most recent first
Date, <email> Real Name
what...
--> bootp-2.4.0
08/20/94 gwr@mc.com (Gordon W. Ross)
Fix code to build bootfile name based on combination of
client requested name and bootfile specifications.
Behave similarly with or without CHECK_FILE_ACCESS.
07/30/94 Dirk Koeppen <dirk@incom.de>
Add "min wait" option (mw) to cause bootpd to ignore
requests from clients that have not waited long enough.
Add code to honor client requests containing the DHCP
option "Maximum Message Size" and use its value to
determine the size of the reply message.
--> bootp-2.3.8
06/25/94 Christos Zoulas <christos@deshaw.com>
Add "-h" flag to override host name (affects default IP
address provided in reply messages. (Also minor bug fix)
05/27/94 gwr@mc.com (Gordon W. Ross)
Add code to call "arp -s IPADDR HWADDR" on systems
that do not provide an SIOCSARP ioctl (i.e. NetBSD)
--> bootp-2.3.7
05/05/94 Walter Wong <wcw+@CMU.EDU>
Reduce noize at debug level one, where log messages
are generated only for hosts that are recognized
and replied to by bootpd. (At request of HP folks.)
04/30/94 gwr@mc.com (Gordon W. Ross)
Use memxxx functions unless USE_BFUNCS is defined.
Added -f <file> option to bootptest (requested file).
04/29/94 tpaquett@ita.lgc.com (Trevor Paquette)
Remove call to haddr_conv802() in sendreply().
The setarp should get the non-transformed address.
04/27/94 gwr@mc.com
Improve logic for building bootfile pathname, so a path
will be put in the reply if either the client or bootpd
specifies a boot file. (Needed for NetBSD diskless boot)
04/25/94 shamash@boxhill.com (Ari Shamash)
Fix prs_inetaddr() so it allows '_' in hostnames.
04/16/94 gwr@mc.com (Gordon W. Ross)
Fix setarp for SVR4 (needs to use I_STR ioctl)
Thanks to several people: (all sent the same fix)
Barney Wolff <barney@databus.com>,
bear@upsys.se (Bj|rn Sj|holm),
Michael Kuschke <Michael.Kuschke@Materna.DE>,
03/25/95 Ulrich Heuer </I=zhhi9/G=Ulrich/S=Heuer/@zhflur.ubs.ubs.ch>
Make option string lengths not include a null terminator.
The trailing null breaks some clients.
03/15/94 "Edmund J. Sutcliffe" <ejs1@tower.york.ac.uk>
Add support for the "EX" option: Execute a program
before sending a BOOTREPLY to a client. Support for
this option is conditional on YORK_EX_OPTION.
03/10/94 Nigel Metheringham <nigelm@ohm.york.ac.uk>
Make getether.c work on Linux.
03/09/94 Koch@Math.Uni-Duisburg.DE (Peter Koch)
Add missing MANDIR definition to Makefile.
03/08/94 Jeroen.Scheerder@let.ruu.nl
Fix args to report in getether code for Ultrix.
Run install individually for each program.
--> bootp-2.3.6
03/07/94 gwr@mc.com
Cleanup for release (run gnu indent, tab-size=4)
02/24/94 Jeroen.Scheerder@let.ruu.nl
Allow underscore in host names - readfile.c:goodname()
Add ConvOldTab.sh - converts 1.1 bootptab to new format.
02/20/94 gwr@mc.com (Gordon W. Ross)
Make readfile tolerant of hardware addresses that start
with a letter. (If lookup_hwa() fails, assume numeric.)
Fix whitespace skip before :vm= auto: and avoid lookup.
02/12/94 walker@zk3.dec.com (Mary Walker)
Added support for 64-bit longs (for the DEC Alpha)
Allow ieee802 hardware address in bit-reversed oreder
02/07/94 hl@tekla.fi (Harald Lundberg)
Fix conflict with DUMP_FILE in syslog.h on OSF1
Use int for (struct bootp).bp_xid (for DEC Alpha)
Added Ultrix support to bootptest (getether)
02/06/94 brezak@ch.hp.com (John Brezak)
Add man-page and install targets to Makefile.NetBSD
Add getether support for NetBSD
02/05/94 gwr@mc.com (Gordon W. Ross)
Added tags 40,41,42 (NIS domain, NIS server, NTP server)
Add stub to getether for machines not yet supported.
--> bootp-2.3.5
01/29/94 gwr@mc.com (Gordon W. Ross)
Make bootpgw put a correct address in "giaddr" when
the client request came via broadcast.
01/22/94 gwr@mc.com (Gordon W. Ross)
Fix syslog call (missing "facility" code)
Add SVR4/Streams support to getif() and getether()
Fix getif bug (matched when it should not)
Macro-ize lots of similar cases in readfile.c
12/27/93 brezak@ch.hp.com (John Brezak)
Remove all newlines passed to syslog(3)
Add /etc/ethers support for NetBSD.
12/18/93 gwr@mc.com (Gordon W. Ross)
Fix bootptest IP address printing.
Fix byte-order bugs in bootpgw and bootptest.
Clean-up signed/unsigned mismatches.
Back out SLIP support changes for now
(code fragment saved in ToDo).
--> bootp-2.3.4 (beta test release)
12/12/93 gwr@mc.com (Gordon W. Ross)
Fixed several more NULL references in readfile.
Added proper length checks to option insertions.
--> bootp-2.3.3 (beta test release)
12/09/93 gwr@mc.com (Gordon W. Ross)
Added ASSERT checks to readfile.c:fill_defaults()
12/08/93 brezak@ch.hp.com (John Brezak)
New Makefile.NetBSD
Added setsid() and #ifdef TIOCNOTTY
(bootpd.c, bootpgw.c)
Moved #include <net/if.h> out of #ifdef SUNOS
Fixed several multiple declaration problems
12/04/93 gwr@mc.com (Gordon W. Ross)
Re-implemented Extension File support
based on work by Jason Zions <jazz@hal.com>
Added support for Reply-Address-Override to support
HP clients (need reply sent to broadcast address)
from David R. Linn <drl@vuse.vanderbilt.edu>
--> bootp-2.3.2 (beta test release)
11/27/93 gwr@mc.com (Gordon W. Ross)
Incorporated bootptest into the bootp release.
Added ANSI function prototypes everywhere.
11/17/93 dpm@depend.com (David P. Maynard)
Added automatic SLIP address determination.
(This is NOT dynamic IP address assignment.)
Cleaned up some type warnings from gcc.
11/11/93 gwr@mc.com (Gordon W. Ross)
Works (again) with no -DSYSLOGD defined.
Provide a default value for the subnet mask.
More #ifdef's for SunOS specific code (lookup_hwa)
Added a simple BOOTP gateway program: bootpgw
Reorganized for more code sharing (with bootpgw)
--> bootp-2.3.1 (alpha test release)
11/08/93 gwr@mc.com (Gordon W. Ross)
Back-out changes to honor option structure in request
(this needs to be a per-client option).
Merged changes from NetBSD and Columbia versions.
Allow host name anywhere IP address is expected.
Add null terminators to option strings.
Add missing symbols to dump routine, dump symbols
in alphabetical order, one tag per line.
--> bootp-2.2.D (posted as patch 2)
10/19/93 gwr@mc.com (Gordon W. Ross)
Fix references to free memory (leads to core dumps).
--> bootp-2.2.C (posted as patch 1)
10/14/93 gwr@mc.com (Gordon W. Ross)
Fix data access alignment problems on SPARC/Solaris.
--> bootp-2.2.B (posted to usenet)
10/11/93 gwr@mc.com (Gordon W. Ross)
Allow extended-length BOOTP packets (more vendor options)
Honor option format specified in client requests.
Added Solaris-2.X changes from db@sunbim.be (Danny Backx).
All history before this point may be inaccurate. Please send
changes if any of the credits are incorrect. -gwr
--> bootp-2.2+NetBSD released
08/27/93 brezak@ch.hp.com (John Brezak)
Added RFC 1396 support (tags 14-17)
--> bootp-2.2+NetBSD (version?)
??/??/93 mckim@lerc.nasa.gov (Jim McKim)
Ported to NetBSD (see Makefile.NetBSD)
Set server host name in responses.
Check all interfaces in address match routine.
--> bootp-2.2+FdC released
01/27/93 <fdc@watsun.cc.columbia.edu> Frank da Cruz
Added RFC 1395 information: Merit dump file,
client domain name, swap server address, root path.
--> bootp-2.2alpha released
11/14/91 <walt+@cmu.edu> Walter L. Wimer
Add "td" to TFTP directory for "secure" (chroot) TFTP.
Add "sa" tag to set explicit server address.
Automatically determine if child of inetd.
Use RFC 1048 format when request has magic number zero.
Fixed various bugs. Give bootptab a separate man page.
--> bootp-2.1 released
01/09/89 <walt+@cmu.edu> Walter L. Wimer
Check world read bit on TFTP boot file.
Add support for rfc1085 "bootfile size" tag.
Add generic tags. Fix byte order of rfc1048 data.
Fix various crashing bugs.
--> bootp-2.0 released
07/15/88 <walt+@cmu.edu> Walter L. Wimer
Added vendor information to conform to RFC1048.
Adopted termcap-like file format to support above.
Added hash table lookup instead of linear search.
Other cleanups.
--> bootp-1.3(?) released
07/24/87 <ddp@andrew.cmu.edu> Drew D. Perkins
Modified to use syslog instead of Kovar's
routines. Add debugging dumps. Many other fixups.
--> bootp-1.2(?) released
07/30/86 David Kovar at Carnegie Mellon University
Modified to work at CMU.
--> bootp-1.1 released
01/22/86 Bill Croft at Stanford University
Original created.

141
libexec/bootpd/ConvOldTab.sh Executable file
View File

@ -0,0 +1,141 @@
#!/bin/sh
# convert_bootptab Jeroen.Scheerder@let.ruu.nl 02/25/94
# This script can be used to convert bootptab files in old format
# to new (termcap-like) bootptab files
#
# The old format - real entries are commented out by '###'
#
# Old-style bootp files consist of two sections.
# The first section has two entries:
# First, a line that specifies the home directory
# (where boot file paths are relative to)
###/tftpboot
# The next non-empty non-comment line specifies the default bootfile
###no-file
# End of first section - indicated by '%%' at the start of the line
###%%
# The remainder of this file contains one line per client
# interface with the information shown by the table headings
# below. The host name is also tried as a suffix for the
# bootfile when searching the home directory (that is,
# bootfile.host)
#
# Note that htype is always 1, indicating the hardware type Ethernet.
# Conversion therefore always yields ':ha=ether:'.
#
# host htype haddr iaddr bootfile
#
###somehost 1 00:0b:ad:01:de:ad 128.128.128.128 dummy
# That's all for the description of the old format.
# For the new-and-improved format, see bootptab(5).
set -u$DX
case $#
in 2 ) OLDTAB=$1 ; NEWTAB=$2 ;;
* ) echo "Usage: `basename $0` <Input> <Output>"
exit 1
esac
if [ ! -r $OLDTAB ]
then
echo "`basename $0`: $OLDTAB does not exist or is unreadable."
exit 1
fi
if touch $NEWTAB 2> /dev/null
then
:
else
echo "`basename $0`: cannot write to $NEWTAB."
exit 1
fi
cat << END_OF_HEADER >> $NEWTAB
# /etc/bootptab: database for bootp server (/etc/bootpd)
# This file was generated automagically
# Blank lines and lines beginning with '#' are ignored.
#
# Legend: (see bootptab.5)
# first field -- hostname (not indented)
# bf -- bootfile
# bs -- bootfile size in 512-octet blocks
# cs -- cookie servers
# df -- dump file name
# dn -- domain name
# ds -- domain name servers
# ef -- extension file
# gw -- gateways
# ha -- hardware address
# hd -- home directory for bootfiles
# hn -- host name set for client
# ht -- hardware type
# im -- impress servers
# ip -- host IP address
# lg -- log servers
# lp -- LPR servers
# ns -- IEN-116 name servers
# ra -- reply address
# rl -- resource location protocol servers
# rp -- root path
# sa -- boot server address
# sm -- subnet mask
# sw -- swap server
# tc -- template host (points to similar host entry)
# td -- TFTP directory
# to -- time offset (seconds)
# ts -- time servers
# vm -- vendor magic number
# Tn -- generic option tag n
#
# Be careful about including backslashes where they're needed. Weird (bad)
# things can happen when a backslash is omitted where one is intended.
# Also, note that generic option data must be either a string or a
# sequence of bytes where each byte is a two-digit hex value.
# First, we define a global entry which specifies the stuff every host uses.
# (Host name lookups are relative to the domain: your.domain.name)
END_OF_HEADER
# Fix up HW addresses in aa:bb:cc:dd:ee:ff and aa-bb-cc-dd-ee-ff style first
# Then awk our stuff together
sed -e 's/[:-]//g' < $OLDTAB | \
nawk 'BEGIN { PART = 0 ; FIELD=0 ; BOOTPATH="unset" ; BOOTFILE="unset" }
/^%%/ {
PART = 1
printf ".default:\\\n\t:ht=ether:\\\n\t:hn:\\\n\t:dn=your.domain.name:\\\n\t:ds=your,dns,servers:\\\n\t:sm=255.255.0.0:\\\n\t:hd=%s:\\\n\t:rp=%s:\\\n\t:td=%s:\\\n\t:bf=%s:\\\n\t:to=auto:\n\n", BOOTPATH, BOOTPATH, BOOTPATH, BOOTFILE
next
}
/^$/ { next }
/^#/ { next }
{
if ( PART == 0 && FIELD < 2 )
{
if ( FIELD == 0 ) BOOTPATH=$1
if ( FIELD == 1 ) BOOTFILE=$1
FIELD++
}
}
{
if ( PART == 1 )
{
HOST=$1
HA=$3
IP=$4
BF=$5
printf "%s:\\\n\t:tc=.default:\\\n\t:ha=0x%s:\\\n\t:ip=%s:\\\n\t:bf=%s:\n", HOST, HA, IP, BF
}
}' >> $NEWTAB
exit 0

View File

@ -0,0 +1,29 @@
Installation instructions for SunOS
Compile the executable:
For SunOS 4.X:
make sunos4
For SunOS 5.X: (Solaris)
make sunos5
Install the executables:
make install
Edit (or create) the bootptab:
(See bootptab.sample and bootptab.5 manual entry)
edit /etc/bootptab
Edit /etc/services to add these two lines:
bootps 67/udp bootp # BOOTP Server
bootpc 68/udp # BOOTP Client
Edit /etc/inetd.conf to add the line:
bootp dgram udp wait root /usr/etc/bootpd bootpd -i
If you compiled report.c with LOG_LOCAL2 (defined in the Makefile)
then you may want to capture syslog messages from BOOTP by changing
your syslog.conf file. (See the sample syslog.conf file here).
Test the change with: logger -t test -p local2.info "message"

View File

@ -0,0 +1,184 @@
#
# Makefile for the BOOTP programs:
# bootpd - BOOTP server daemon
# bootpef - BOOTP extension file builder
# bootpgw - BOOTP gateway daemon
# bootptest - BOOTP tester (client)
#
# OPTion DEFinitions:
# Remove the -DVEND_CMU if you don't wish to support the "CMU vendor format"
# in addition to the RFC1048 format. Leaving out DEBUG saves little.
OPTDEFS= -DSYSLOG -DVEND_CMU -DDEBUG
# Uncomment and edit this to choose the facility code used for syslog.
# LOG_FACILITY= "-DLOG_BOOTP=LOG_LOCAL2"
# SYStem DEFinitions:
# Either uncomment some of the following, or do:
# "make sunos4" (or "make sunos5", etc.)
# SYSDEFS= -DSUNOS -DETC_ETHERS
# SYSDEFS= -DSVR4
# SYSLIBS= -lsocket -lnsl
# Uncomment this if your system does not provide streror(3)
# STRERROR=strerror.o
# FILE DEFinitions:
# The next few lines may be uncommented and changed to alter the default
# filenames bootpd uses for its configuration and dump files.
#CONFFILE= -DCONFIG_FILE=\"/usr/etc/bootptab\"
#DUMPFILE= -DDUMPTAB_FILE=\"/usr/etc/bootpd.dump\"
#FILEDEFS= $(CONFFILE) $(DUMPFILE)
# MORE DEFinitions (whatever you might want to add)
# One might define NDEBUG (to remove "assert()" checks).
MOREDEFS=
INSTALL=/usr/bin/install
DESTDIR=
BINDIR=/usr/etc
MANDIR=/usr/local/man
CFLAGS= $(OPTDEFS) $(SYSDEFS) $(FILEDEFS) $(MOREDEFS)
PROGS= bootpd bootpef bootpgw bootptest
TESTS= trylook trygetif trygetea
all: $(PROGS)
tests: $(TESTS)
system: install
install: $(PROGS)
-for f in $(PROGS) ;\
do \
$(INSTALL) -c -s $$f $(DESTDIR)$(BINDIR) ;\
done
MAN5= bootptab.5
MAN8= bootpd.8 bootpef.8 bootptest.8
install.man: $(MAN5) $(MAN8)
-for f in $(MAN5) ;\
do \
$(INSTALL) -c -m 644 $$f $(DESTDIR)$(MANDIR)/man5 ;\
done
-for f in $(MAN8) ;\
do \
$(INSTALL) -c -m 644 $$f $(DESTDIR)$(MANDIR)/man8 ;\
done
clean:
-rm -f core *.o
-rm -f $(PROGS) $(TESTS)
distclean:
-rm -f *.BAK *.CKP *~ .emacs*
#
# Handy targets for individual systems:
#
# DEC/OSF1 on the Alpha
alpha:
$(MAKE) SYSDEFS="-DETC_ETHERS -Dint32=int -D_SOCKADDR_LEN" \
STRERROR=strerror.o
# Control Data EP/IX 1.4.3 system, BSD 4.3 mode
epix143:
$(MAKE) CC="cc -systype bsd43" \
SYSDEFS="-Dconst= -D_SIZE_T -DNO_UNISTD -DUSE_BFUNCS" \
STRERROR=strerror.o
# Control Data EP/IX 2.1.1 system, SVR4 mode
epix211:
$(MAKE) CC="cc -systype svr4" \
SYSDEFS="-DSVR4" \
SYSLIBS="-lsocket -lnsl"
# Silicon Graphics IRIX (no <sys/sockio.h>, so not SVR4)
irix:
$(MAKE) SYSDEFS="-DSYSV -DIRIX"
# SunOS 4.X
sunos4:
$(MAKE) SYSDEFS="-DSUNOS -DETC_ETHERS" \
STRERROR=strerror.o
# Solaris 2.X (i.e. SunOS 5.X)
sunos5:
$(MAKE) SYSDEFS="-DSVR4 -DETC_ETHERS" \
SYSLIBS="-lsocket -lnsl"
# UNIX System V Rel. 4 (also: IRIX 5.X, others)
svr4:
$(MAKE) SYSDEFS="-DSVR4" \
SYSLIBS="-lsocket -lnsl"
#
# How to build each program:
#
OBJ_D= bootpd.o dovend.o readfile.o hash.o dumptab.o \
lookup.o getif.o hwaddr.o tzone.o report.o $(STRERROR)
bootpd: $(OBJ_D)
$(CC) -o $@ $(OBJ_D) $(SYSLIBS)
OBJ_EF= bootpef.o dovend.o readfile.o hash.o dumptab.o \
lookup.o hwaddr.o tzone.o report.o $(STRERROR)
bootpef: $(OBJ_EF)
$(CC) -o $@ $(OBJ_EF) $(SYSLIBS)
OBJ_GW= bootpgw.o getif.o hwaddr.o report.o $(STRERROR)
bootpgw: $(OBJ_GW)
$(CC) -o $@ $(OBJ_GW) $(SYSLIBS)
OBJ_TEST= bootptest.o print-bootp.o getif.o getether.o \
report.o $(STRERROR)
bootptest: $(OBJ_TEST)
$(CC) -o $@ $(OBJ_TEST) $(SYSLIBS)
# This is just for testing the lookup functions.
TRYLOOK= trylook.o lookup.o report.o $(STRERROR)
trylook : $(TRYLOOK)
$(CC) -o $@ $(TRYLOOK) $(SYSLIBS)
# This is just for testing getif.
TRYGETIF= trygetif.o getif.o report.o $(STRERROR)
trygetif : $(TRYGETIF)
$(CC) -o $@ $(TRYGETIF) $(SYSLIBS)
# This is just for testing getether.
TRYGETEA= trygetea.o getether.o report.o $(STRERROR)
trygetea : $(TRYGETEA)
$(CC) -o $@ $(TRYGETEA) $(SYSLIBS)
# This rule just keeps the LOG_BOOTP define localized.
report.o : report.c
$(CC) $(CFLAGS) $(LOG_FACILITY) -c $<
# Punt SunOS -target noise
.c.o:
$(CC) $(CFLAGS) -c $<
#
# Header file dependencies:
#
bootpd.o : bootp.h bptypes.h hash.h hwaddr.h bootpd.h dovend.h
bootpd.o : readfile.h report.h tzone.h patchlevel.h getif.h
bootpef.o : bootp.h bptypes.h hash.h hwaddr.h bootpd.h dovend.h
bootpef.o : readfile.h report.h tzone.h patchlevel.h
bootpgw.o : bootp.h bptypes.h getif.h hwaddr.h report.h patchlevel.h
bootptest.o : bootp.h bptypes.h bootptest.h getif.h patchlevel.h
dovend.o : bootp.h bptypes.h bootpd.h hash.h hwaddr.h report.h dovend.h
dumptab.o : bootp.h bptypes.h hash.h hwaddr.h report.h patchlevel.h bootpd.h
getif.o : getif.h report.h
hash.o : hash.h
hwaddr.o : bptypes.h hwaddr.h report.h
lookup.o : bootp.h bptypes.h lookup.h report.h
print-bootp.o : bootp.h bptypes.h bootptest.h
readfile.o : bootp.h bptypes.h hash.h hwaddr.h lookup.h readfile.h
readfile.o : report.h tzone.h bootpd.h
report.o : report.h
tzone.o : bptypes.h report.h tzone.h

47
libexec/bootpd/Problems Normal file
View File

@ -0,0 +1,47 @@
Common problems and ways to work around them:
Bootpd complains that it "can not get IP addr for HOSTNAME"
If the entry is a "dummy" (not a real host) used only for
reference by other entries, put '.' in front of the name.
If the entry is for a real client and the IP address for
the client can not be found using gethostbyname(), specify
the IP address for the client using numeric form.
Bootpd takes a long time to finish parsing the bootptab file:
Excessive startup time is usually caused by waiting for
timeouts on failed DNS lookup operations. If this is the
problem, find the client names for which DNS lookup fails
and change the bootptab to specify the IP addresses for
those clients using numeric form.
When bootptab entries do not specify an ip address, bootpd
attempts to lookup the tagname as a host name to find the
IP address. To suppress this default action, either make
the entry a "dummy" or specify its IP numeric address.
If your DNS lookups work but are just slow, consider either
running bootpd on the same machine as the DNS server or
running a caching DNS server on the host running bootpd.
My huge bootptab file causes startup time to be so long that clients
give up waiting for a reply.
Truly huge bootptab files make "inetd" mode impractical.
Start bootpd in "standalone" mode when the server boots.
Another possibility is to run one bootpd on each network
segment so each one can have a smaller bootptab. Only one
instance of bootpd may run on one server, so you would need
to use a different server for each network segment.
My bootp clients are given responses with a boot file name that is
not a fully specified path.
Make sure the TFTP directory or home directory tags are set:
:td=/tftpboot: (or)
:hd=/usr/boot: (for example)

133
libexec/bootpd/README Normal file
View File

@ -0,0 +1,133 @@
This is an enhanced version of the CMU BOOTP server which was derived
from the original BOOTP server created by Bill Croft at Stanford.
This version merges all the enhancements and bug-fixes from the
NetBSD, Columbia, and other versions.
Please direct questions, comments, and bug reports to the list:
<bootp@andrew.cmu.edu>
You can subscribe to this mailing list by sending mail to:
bootp-request@andrew.cmu.edu
(The body of the message should contain: "Add <your-address>")
[ From the NetBSD README file: ]
BOOTPD is a useful adjunct to the nfs diskless boot EPROM code.
The alternatives for initiating a boot of a kernel across a network
are to use RARP protocol, or BOOTP protocol. BOOTP is more flexible;
it allows additional items of information to be returned to the
booting client; it also supports booting across gateways.
[ From the CMU README file: ]
Notes:
1) BOOTP was originally designed and implemented by Bill Croft at Stanford.
Much of the credit for the ideas and the code goes to him. We've added
code to support the vendor specific area of the packet as specified in
RFC1048. We've also improved the host lookup algorithm and added some
extra logging.
2) The server now uses syslog to do logging. Specifically it uses the 4.3bsd
version. I've #ifdef'd all of these calls. If you are running 4.2 you
should compile without the -DSYSLOG switch.
3) You must update your /etc/services file to contain the following two lines:
bootps 67/udp bootp # BOOTP Server
bootpc 68/udp # BOOTP Client
4) Edit the bootptab. It has some explanitory comments, and there
is a manual entry describing its format (bootptab.5)
If you have any questions, just let us know.
Construction:
[ See the file Installation which is more up-to-date. -gwr ]
Make sure all of the files exist first. If anything is missing,
please contact either Walt Wimer or Drew Perkins by E-mail or phone.
Addresses and phone numbers are listed below.
Type 'make'. The options at present are: -DSYSLOG which enables logging
code, -DDEBUG which enables table dumping via signals, and -DVEND_CMU
which enables the CMU extensions for CMU PC/IP.
Edit the bootptab. The man page and the comments in the file should
explain how to go about doing so. If you have any problems, let me know.
Type 'make install'. This should put all of the files in the right place.
Edit your /etc/rc.local or /etc/inetd.conf file to start up bootpd upon
reboot. The following is a sample /etc/inetd.conf entry:
# BOOTP server
bootps dgram udp wait root /usr/etc/bootpd bootpd -i
Care and feeding:
If you change the interface cards on your host or add new hosts you will
need to update /etc/bootptab. Just edit it as before. Once you write
it back out, bootpd will notice that there is a new copy and will
reread it the next time it gets a request.
If your bootp clients don't get a response then several things might be
wrong. Most often, the entry for that host is not in the database.
Check the hardware address and then check the entry and make sure
everything is right. Other problems include the server machine crashing,
bad cables, and the like. If your network is very congested you should
try making your bootp clients send additional requests before giving up.
November 7, 1988
Walter L. Wimer Drew D. Perkins
ww0n@andrew.cmu.edu ddp@andrew.cmu.edu
(412) 268-6252 (412) 268-8576
4910 Forbes Ave
Pittsburgh, PA 15213
[ Contents description by file: ]
Announce* Text of release announcements
Changes Change history, reverse chronological
Installation Instructions for building and installing
Makefile* for "make"
README This file
ToDo Things not yet done
bootp.h The protocol header file
bootpd.8 Manual page for bootpd, boopgw
bootpd.c BOOTP server main module
bootpd.h header for above (and others)
bootpef.8 Manual page for bootpef
bootpef.c BOOTP extension file compiler
bootpgw.c BOOTP gateway main module
bootptab.5 A manual describing the bootptab format
bootptab.cmu A sample database file for the server
bootptab.mcs Another sample from <gwr@mc.com>
bootptest.8 Manual page for bootptest
bootptest.c BOOTP test program (fake client)
bootptest.h header for above
dovend.c Vendor Option builder (for bootpd, bootpef)
dovend.h header for above
dumptab.c Implements debugging dump for bootpd
getether.c For bootptest (not used yet)
getif.c Get network interface info.
getif.h header for above
hash.c The hash table module
hash.h header for above
hwaddr.c Hardware address support
hwaddr.h header for above
lookup.c Internet Protocol address lookup
lookup.h header for above
patchlevel.h Holds version numbers
print-bootp.c Prints BOOTP packets (taken from BSD tcpdump)
readfile.c The configuration file-reading routines
readfile.h header for above
report.c Does syslog-style messages
report.h header for above
strerror.c Library errno-to-string (for systems lacking it)
syslog.conf Sample config file for syslogd(8)
syslog.h For systems that lack syslog(3)
try*.c Test programs (for debugging)
tzone.c Get timezone offset
tzone.h header for above

147
libexec/bootpd/bootp.h Normal file
View File

@ -0,0 +1,147 @@
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of Carnegie Mellon University not be used
in advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
/*
* Bootstrap Protocol (BOOTP). RFC951 and RFC1395.
*
* $Id: bootp.h,v 1.1.1.1 1994/09/10 14:44:54 csgr Exp $
*
*
* This file specifies the "implementation-independent" BOOTP protocol
* information which is common to both client and server.
*
*/
#include "bptypes.h" /* for int32, u_int32 */
#define BP_CHADDR_LEN 16
#define BP_SNAME_LEN 64
#define BP_FILE_LEN 128
#define BP_VEND_LEN 64
#define BP_MINPKTSZ 300 /* to check sizeof(struct bootp) */
struct bootp {
unsigned char bp_op; /* packet opcode type */
unsigned char bp_htype; /* hardware addr type */
unsigned char bp_hlen; /* hardware addr length */
unsigned char bp_hops; /* gateway hops */
unsigned int32 bp_xid; /* transaction ID */
unsigned short bp_secs; /* seconds since boot began */
unsigned short bp_flags; /* RFC1532 broadcast, etc. */
struct in_addr bp_ciaddr; /* client IP address */
struct in_addr bp_yiaddr; /* 'your' IP address */
struct in_addr bp_siaddr; /* server IP address */
struct in_addr bp_giaddr; /* gateway IP address */
unsigned char bp_chaddr[BP_CHADDR_LEN]; /* client hardware address */
char bp_sname[BP_SNAME_LEN]; /* server host name */
char bp_file[BP_FILE_LEN]; /* boot file name */
unsigned char bp_vend[BP_VEND_LEN]; /* vendor-specific area */
/* note that bp_vend can be longer, extending to end of packet. */
};
/*
* UDP port numbers, server and client.
*/
#define IPPORT_BOOTPS 67
#define IPPORT_BOOTPC 68
#define BOOTREPLY 2
#define BOOTREQUEST 1
/*
* Hardware types from Assigned Numbers RFC.
*/
#define HTYPE_ETHERNET 1
#define HTYPE_EXP_ETHERNET 2
#define HTYPE_AX25 3
#define HTYPE_PRONET 4
#define HTYPE_CHAOS 5
#define HTYPE_IEEE802 6
#define HTYPE_ARCNET 7
/*
* Vendor magic cookie (v_magic) for CMU
*/
#define VM_CMU "CMU"
/*
* Vendor magic cookie (v_magic) for RFC1048
*/
#define VM_RFC1048 { 99, 130, 83, 99 }
/*
* Tag values used to specify what information is being supplied in
* the vendor (options) data area of the packet.
*/
/* RFC 1048 */
#define TAG_END ((unsigned char) 255)
#define TAG_PAD ((unsigned char) 0)
#define TAG_SUBNET_MASK ((unsigned char) 1)
#define TAG_TIME_OFFSET ((unsigned char) 2)
#define TAG_GATEWAY ((unsigned char) 3)
#define TAG_TIME_SERVER ((unsigned char) 4)
#define TAG_NAME_SERVER ((unsigned char) 5)
#define TAG_DOMAIN_SERVER ((unsigned char) 6)
#define TAG_LOG_SERVER ((unsigned char) 7)
#define TAG_COOKIE_SERVER ((unsigned char) 8)
#define TAG_LPR_SERVER ((unsigned char) 9)
#define TAG_IMPRESS_SERVER ((unsigned char) 10)
#define TAG_RLP_SERVER ((unsigned char) 11)
#define TAG_HOST_NAME ((unsigned char) 12)
#define TAG_BOOT_SIZE ((unsigned char) 13)
/* RFC 1395 */
#define TAG_DUMP_FILE ((unsigned char) 14)
#define TAG_DOMAIN_NAME ((unsigned char) 15)
#define TAG_SWAP_SERVER ((unsigned char) 16)
#define TAG_ROOT_PATH ((unsigned char) 17)
/* RFC 1497 */
#define TAG_EXTEN_FILE ((unsigned char) 18)
/* RFC 1533 */
#define TAG_NIS_DOMAIN ((unsigned char) 40)
#define TAG_NIS_SERVER ((unsigned char) 41)
#define TAG_NTP_SERVER ((unsigned char) 42)
/* DHCP maximum message size. */
#define TAG_MAX_MSGSZ ((unsigned char) 57)
/* XXX - Add new tags here */
/*
* "vendor" data permitted for CMU bootp clients.
*/
struct cmu_vend {
char v_magic[4]; /* magic number */
unsigned int32 v_flags; /* flags/opcodes, etc. */
struct in_addr v_smask; /* Subnet mask */
struct in_addr v_dgate; /* Default gateway */
struct in_addr v_dns1, v_dns2; /* Domain name servers */
struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */
struct in_addr v_ts1, v_ts2; /* Time servers */
int32 v_unused[6]; /* currently unused */
};
/* v_flags values */
#define VF_SMASK 1 /* Subnet mask field contains valid data */

305
libexec/bootpd/bootpd.8 Normal file
View File

@ -0,0 +1,305 @@
.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
.\"
.\" $Header: /home/ncvs/src/usr.sbin/bootpd/bootpd.8,v 1.1.1.1 1994/09/10 14:44:54 csgr Exp $
.\"
.TH BOOTPD 8 "November 06, 1993" "Carnegie Mellon University"
.SH NAME
bootpd, bootpgw \- Internet Boot Protocol server/gateway
.SH SYNOPSIS
.B bootpd
[
.B \-i
.B \-s
.B \-t
timeout
.B \-d
level
.B \-c
chdir\-path
]
[
.I bootptab
[
.I dumpfile
] ]
.br
.B bootpgw
[
.B \-i
.B \-s
.B \-t
timeout
.B \-d
level
] server
.SH DESCRIPTION
.I Bootpd
implements an Internet Bootstrap Protocol (BOOTP) server as defined in
RFC951, RFC1532, and RFC1533.
.I Bootpgw
implements a simple BOOTP gateway which can be used to forward
requests and responses between clients on one subnet and a
BOOTP server (i.e.
.IR bootpd )
on another subnet. While either
.I bootpd
or
.I bootpgw
will forward BOOTREPLY packets, only
.I bootpgw
will forward BOOTREQUEST packets.
.PP
One host on each network segment is normally configured to run either
.I bootpd
or
.I bootpgw
from
.I inetd
by including one of the following lines in the file
.IR /etc/inetd.conf :
.IP
bootps dgram udp wait root /etc/bootpd bootpd bootptab
.br
bootps dgram udp wait root /etc/bootpgw bootpgw server
.PP
This mode of operation is referred to as "inetd mode" and causes
.I bootpd
(or
.IR bootpgw )
to be started only when a boot request arrives. If it does not
receive another packet within fifteen minutes of the last one
it received, it will exit to conserve system resources. The
.B \-t
option controls this timeout (see OPTIONS).
.PP
It is also possible to run
.I bootpd
(or
.IR bootpgw )
in "standalone mode" (without
.IR inetd )
by simply invoking it from a shell like any other regular command.
Standalone mode is particularly useful when
.I bootpd
is used with a large configuration database, where the start up
delay might otherwise prevent timely response to client requests.
(Automatic start up in standalone mode can be done by invoking
.I bootpd
from within
.IR /etc/rc.local ,
for example.)
Standalone mode is less useful for
.I bootgw
which
has very little start up delay because
it does not read a configuration file.
.PP
Either program automatically detects whether it was invoked from inetd
or from a shell and automatically selects the appropriate mode.
The
.B \-s
or
.B \-i
option may be used to force standalone or inetd mode respectively
(see OPTIONS).
.SH OPTIONS
.TP
.BI \-t \ timeout
Specifies the
.I timeout
value (in minutes) that a
.I bootpd
or
.I bootpgw
process will wait for a BOOTP packet before exiting.
If no packets are recieved for
.I timeout
seconds, then the program will exit.
A timeout value of zero means "run forever".
In standalone mode, this option is forced to zero.
.TP
.BI \-d \ debug\-level
Sets the
.I debug\-level
variable that controls the amount of debugging messages generated.
For example, -d4 or -d 4 will set the debugging level to 4.
For compatibility with older versions of
.IR bootpd ,
omitting the numeric parameter (i.e. just -d) will
simply increment the debug level by one.
.TP
.BI \-c \ chdir\-path
Sets the current directory used by
.I bootpd
while checking the existence and size of client boot files. This is
useful when client boot files are specified as relative pathnames, and
.I bootpd
needs to use the same current directory as the TFTP server
(typically /tftpboot). This option is not recoginzed by
.IR bootpgw .
.TP
.B \-i
Force inetd mode. This option is obsolete, but remains for
compatibility with older versions of
.IR bootpd .
.TP
.B \-s
Force standalone mode. This option is obsolete, but remains for
compatibility with older versions of
.IR bootpd .
.TP
.I bootptab
Specifies the name of the configuration file from which
.I bootpd
loads its database of known clients and client options
.RI ( bootpd
only).
.TP
.I dumpfile
Specifies the name of the file that
.I bootpd
will dump its internal database into when it receives a
SIGUSR1 signal
.RI ( bootpd
only). This option is only recognized if
.I bootpd
was compiled with the -DDEBUG flag.
.TP
.I server
Specifies the name of a BOOTP server to which
.I bootpgw
will forward all BOOTREQUEST packets it receives
.RI ( bootpgw
only).
.SH OPERATION
.PP
Both
.I bootpd
and
.I bootpgw
operate similarly in that both listen for any packets sent to the
.I bootps
port, and both simply forward any BOOTREPLY packets.
They differ in their handling of BOOTREQUEST packets.
.PP
When
.I bootpgw
is started, it determines the address of a BOOTP server
whose name is provided as a command line parameter. When
.I bootpgw
receives a BOOTREQUEST packet, it sets the "gateway address"
and "hop count" fields in the packet and forwards the packet
to the BOOTP server at the address determined earlier.
Requests are forwarded only if they indicate that
the client has been waiting for at least three seconds.
.PP
When
.I bootpd
is started it reads a configuration file, (normally
.IR /etc/bootptab )
that initializes the internal database of known clients and client
options. This internal database is reloaded
from the configuration file when
.I bootpd
receives a hangup signal (SIGHUP) or when it discovers that the
configuration file has changed.
.PP
When
.I bootpd
receives a BOOTREQUEST packet, it
.\" checks the modification time of the
.\" configuration file and reloads the database if necessary. Then it
looks for a database entry matching the client request.
If the client is known,
.I bootpd
composes a BOOTREPLY packet using the database entry found above,
and sends the reply to the client (possibly using a gateway).
If the client is unknown, the request is discarded
(with a notice if debug > 0).
.PP
If
.I bootpd
is compiled with the -DDEBUG option, receipt of a SIGUSR1 signal causes
it to dump its internal database to the file
.I /etc/bootpd.dump
or the dumpfile specified as a command line parameter.
.PP
During initialization, both programs
determine the UDP port numbers to be used by calling
.I getservbyname
(which nomally uses
.IR /etc/services).
Two service names (and port numbers) are used:
.IP
bootps \- BOOTP Server listening port
.br
bootpc \- BOOTP Client destination port
.LP
If the port numbers cannot
be determined using
.I getservbyname
then the values default to boopts=67 and bootpc=68.
.SH FILES
.TP 20
/etc/bootptab
Database file read by
.IR bootpd .
.TP
/etc/bootpd.dump
Debugging dump file created by
.IR bootpd .
.TP
/etc/services
Internet service numbers.
.TP
/tftpboot
Current directory typically used by the TFTP server and
.IR bootpd .
.SH BUGS
Individual host entries must not exceed 1024 characters.
.SH CREDITS
.PP
This distribution is currently maintained by
Walter L. Wimer <walt+@cmu.edu>.
.PP
The original BOOTP server was created by
Bill Croft at Stanford University in January 1986.
.PP
The current version of
.I bootpd
is primarily the work of David Kovar,
Drew D. Perkins, and Walter L. Wimer,
at Carnegie Mellon University.
.TP
Enhancements and bug\-fixes have been contributed by:
(in alphabetical order)
.br
Danny Backx <db@sunbim.be>
.br
John Brezak <brezak@ch.hp.com>
.br
Frank da Cruz <fdc@cc.columbia.edu>
.br
David R. Linn <drl@vuse.vanderbilt.edu>
.br
Jim McKim <mckim@lerc.nasa.gov>
.br
Gordon W. Ross <gwr@mc.com>
.br
Jason Zions <jazz@hal.com>
.SH "SEE ALSO"
.LP
bootptab(5), inetd(8), tftpd(8)
.LP
DARPA Internet Request For Comments:
.TP 10
RFC951
Bootstrap Protocol
.TP 10
RFC1532
Clarifications and Extensions for the Bootstrap Protocol
.TP 10
RFC1533
DHCP Options and BOOTP Vendor Extensions

1380
libexec/bootpd/bootpd.c Normal file

File diff suppressed because it is too large Load Diff

211
libexec/bootpd/bootpd.h Normal file
View File

@ -0,0 +1,211 @@
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of Carnegie Mellon University not be used
in advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
/*
* bootpd.h -- common header file for all the modules of the bootpd program.
*/
#include "bptypes.h"
#include "hash.h"
#include "hwaddr.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef PRIVATE
#define PRIVATE static
#endif
#ifndef SIGUSR1
#define SIGUSR1 30 /* From 4.3 <signal.h> */
#endif
#define MAXSTRINGLEN 80 /* Max string length */
/* Local definitions: */
#define MAX_MSG_SIZE (3*512) /* Maximum packet size */
/*
* Return pointer to static string which gives full network error message.
*/
#define get_network_errmsg get_errmsg
/*
* Data structure used to hold an arbitrary-lengthed list of IP addresses.
* The list may be shared among multiple hosts by setting the linkcount
* appropriately.
*/
struct in_addr_list {
unsigned int linkcount, addrcount;
struct in_addr addr[1]; /* Dynamically extended */
};
/*
* Data structures used to hold shared strings and shared binary data.
* The linkcount must be set appropriately.
*/
struct shared_string {
unsigned int linkcount;
char string[1]; /* Dynamically extended */
};
struct shared_bindata {
unsigned int linkcount, length;
byte data[1]; /* Dynamically extended */
};
/*
* Flag structure which indicates which symbols have been defined for a
* given host. This information is used to determine which data should or
* should not be reported in the bootp packet vendor info field.
*/
struct flag {
unsigned bootfile :1,
bootserver :1,
bootsize :1,
bootsize_auto :1,
cookie_server :1,
domain_server :1,
gateway :1,
generic :1,
haddr :1,
homedir :1,
htype :1,
impress_server :1,
iaddr :1,
log_server :1,
lpr_server :1,
name_server :1,
name_switch :1,
rlp_server :1,
send_name :1,
subnet_mask :1,
tftpdir :1,
time_offset :1,
time_server :1,
dump_file :1,
domain_name :1,
swap_server :1,
root_path :1,
exten_file :1,
reply_addr :1,
nis_domain :1,
nis_server :1,
ntp_server :1,
exec_file :1,
msg_size :1,
min_wait :1,
/* XXX - Add new tags here */
vm_cookie :1;
};
/*
* The flags structure contains TRUE flags for all the fields which
* are considered valid, regardless of whether they were explicitly
* specified or indirectly inferred from another entry.
*
* The gateway and the various server fields all point to a shared list of
* IP addresses.
*
* The hostname, home directory, and bootfile are all shared strings.
*
* The generic data field is a shared binary data structure. It is used to
* hold future RFC1048 vendor data until bootpd is updated to understand it.
*
* The vm_cookie field specifies the four-octet vendor magic cookie to use
* if it is desired to always send the same response to a given host.
*
* Hopefully, the rest is self-explanatory.
*/
struct host {
unsigned linkcount; /* hash list inserts */
struct flag flags; /* ALL valid fields */
struct in_addr_list *cookie_server,
*domain_server,
*gateway,
*impress_server,
*log_server,
*lpr_server,
*name_server,
*rlp_server,
*time_server,
*nis_server,
*ntp_server;
struct shared_string *bootfile,
*hostname,
*domain_name,
*homedir,
*tftpdir,
*dump_file,
*exten_file,
*root_path,
*nis_domain,
*exec_file;
struct shared_bindata *generic;
byte vm_cookie[4],
htype, /* RFC826 says this should be 16-bits but
RFC951 only allocates 1 byte. . . */
haddr[MAXHADDRLEN];
int32 time_offset;
unsigned int32 bootsize,
msg_size,
min_wait;
struct in_addr bootserver,
iaddr,
swap_server,
reply_addr,
subnet_mask;
/* XXX - Add new tags here (or above as appropriate) */
};
/*
* Variables shared among modules.
*/
extern int debug;
extern char *bootptab;
extern char *progname;
extern u_char vm_cmu[4];
extern u_char vm_rfc1048[4];
extern hash_tbl *hwhashtable;
extern hash_tbl *iphashtable;
extern hash_tbl *nmhashtable;

395
libexec/bootpd/bootptab.5 Normal file
View File

@ -0,0 +1,395 @@
.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
.\"
.\" $Header: /home/ncvs/src/usr.sbin/bootpd/bootptab.5,v 1.1.1.1 1994/09/10 14:44:54 csgr Exp $
.\"
.TH BOOTPTAB 5 "October 31, 1991" "Carnegie Mellon University"
.UC 6
.SH NAME
bootptab \- Internet Bootstrap Protocol server database
.SH DESCRIPTION
The
.I bootptab
file is the configuration database file for
.IR bootpd ,
the Internet Bootstrap Protocol server.
It's format is similar to that of
.IR termcap (5)
in which two-character case-sensitive tag symbols are used to
represent host parameters. These parameter declarations are separated by
colons (:), with a general format of:
.PP
.I " hostname:tg=value. . . :tg=value. . . :tg=value. . . ."
.PP
where
.I hostname
is the actual name of a bootp client (or a "dummy entry"), and
.I tg
is a two-character tag symbol. Dummy entries have an invalid hostname
(one with a "." as the first character) and are used to provide
default values used by other entries via the
.B tc=.dummy-entry
mechanism. Most tags must be followed by an equals-sign
and a value as above. Some may also appear in a boolean form with no
value (i.e.
.RI : tg :).
The currently recognized tags are:
.PP
.br
bf Bootfile
.br
bs Bootfile size in 512-octet blocks
.br
cs Cookie server address list
.br
df Merit dump file
.br
dn Domain name
.br
ds Domain name server address list
.br
ef Extension file
.br
gw Gateway address list
.br
ha Host hardware address
.br
hd Bootfile home directory
.br
hn Send client's hostname to client
.br
ht Host hardware type (see Assigned Numbers RFC)
.br
im Impress server address list
.br
ip Host IP address
.br
lg Log server address list
.br
lp LPR server address list
.br
ns IEN-116 name server address list
.br
nt NTP (time) Server (RFC 1129)
.br
ra Reply address override
.br
rl Resource location protocol server address list
.br
rp Root path to mount as root
.br
sa TFTP server address client should use
.br
sm Host subnet mask
.br
sw Swap server address
.br
tc Table continuation (points to similar "template" host entry)
.br
td TFTP root directory used by "secure" TFTP servers
.br
to Time offset in seconds from UTC
.br
ts Time server address list
.br
vm Vendor magic cookie selector
.br
yd YP (NIS) domain name
.br
ys YP (NIS) server address
.PP
There is also a generic tag,
.RI T n ,
where
.I n
is an RFC1084 vendor field tag number. Thus it is possible to immediately
take advantage of future extensions to RFC1084 without being forced to modify
.I bootpd
first. Generic data may be represented as either a stream of hexadecimal
numbers or as a quoted string of ASCII characters. The length of the generic
data is automatically determined and inserted into the proper field(s) of the
RFC1084-style bootp reply.
.PP
The following tags take a whitespace-separated list of IP addresses:
.BR cs ,
.BR ds ,
.BR gw ,
.BR im ,
.BR lg ,
.BR lp ,
.BR ns ,
.BR nt ,
.BR ra ,
.BR rl ,
and
.BR ts .
The
.BR ip ,
.BR sa ,
.BR sw ,
.BR sm ,
and
.B ys
tags each take a single IP address.
All IP addresses are specified in standard Internet "dot" notation
and may use decimal, octal, or hexadecimal numbers
(octal numbers begin with 0, hexadecimal numbers begin with '0x' or '0X').
Any IP addresses may alternatively be specified as a hostname, causing
.I bootpd
to lookup the IP address for that host name using gethostbyname(3).
If the
.B ip
tag is not specified,
.I bootpd
will determine the IP address using the entry name as the host name.
(Dummy entries use an invalid host name to avoid automatic IP lookup.)
.PP
The
.B ht
tag specifies the hardware type code as either an unsigned decimal, octal, or
hexadecimal integer or one of the following symbolic names:
.B ethernet
or
.B ether
for 10Mb Ethernet,
.B ethernet3
or
.B ether3
for 3Mb experimental Ethernet,
.BR ieee802 ,
.BR tr ,
or
.B token-ring
for IEEE 802 networks,
.B pronet
for Proteon ProNET Token Ring, or
.BR chaos ,
.BR arcnet ,
or
.B ax.25
for Chaos, ARCNET, and AX.25 Amateur Radio networks, respectively.
The
.B ha
tag takes a hardware address which may be specified as a host name
or in numeric form. Note that the numeric form
.I must
be specified in hexadecimal; optional periods and/or a leading '0x' may be
included for readability. The
.B ha
tag must be preceded by the
.B ht
tag (either explicitly or implicitly; see
.B tc
below).
If the hardware address is not specified and the type is specified
as either "ethernet" or "ieee802", then
.I bootpd
will try to determine the hardware address using ether_hton(3).
.PP
The hostname, home directory, and bootfile are ASCII strings which may be
optionally surrounded by double quotes ("). The client's request and the
values of the
.B hd
and
.B bf
symbols determine how the server fills in the bootfile field of the bootp
reply packet.
.PP
If the client provides a file name it is left as is.
Otherwise, if the
.B bf
option is specified its value is copied into the reply packet.
If the
.B hd
option is specified as well, its value is prepended to the
boot file copied into the reply packet.
The existence of the boot file is checked only if the
.BR bs =auto
option is used (to determine the boot file size).
A reply may be sent whether or not the boot file exists.
.PP
Some newer versions of
.I tftpd
provide a security feature to change their root directory using
the
.IR chroot (2)
system call.
The
.B td
tag may be used to inform
.I bootpd
of this special root directory used by
.IR tftpd .
(One may alternatively use the
.I bootpd
"-c chdir" option.)
The
.B hd
tag is actually relative to the root directory specified by the
.B td
tag.
For example, if the real absolute path to your BOOTP client bootfile is
/tftpboot/bootfiles/bootimage, and
.IR tftpd
uses /tftpboot as its "secure" directory, then specify the following in
.IR bootptab :
.PP
.br
:td=/tftpboot:hd=/bootfiles:bf=bootimage:
.PP
If your bootfiles are located directly in /tftpboot, use:
.PP
.br
:td=/tftpboot:hd=/:bf=bootimage:
.PP
The
.B sa
tag may be used to specify the IP address of the particular TFTP server
you wish the client to use. In the absence of this tag,
.I bootpd
will tell the client to perform TFTP to the same machine
.I bootpd
is running on.
.PP
The time offset
.B to
may be either a signed decimal integer specifying the client's
time zone offset in seconds from UTC, or the keyword
.B auto
which uses the server's time zone offset. Specifying the
.B to
symbol as a boolean has the same effect as specifying
.B auto
as its value.
.PP
The bootfile size
.B bs
may be either a decimal, octal, or hexadecimal integer specifying the size of
the bootfile in 512-octet blocks, or the keyword
.B auto
which causes the server to automatically calculate the bootfile size at each
request. As with the time offset, specifying the
.B bs
symbol as a boolean has the same effect as specifying
.B auto
as its value.
.PP
The vendor magic cookie selector (the
.B vm
tag) may take one of the following keywords:
.B auto
(indicating that vendor information is determined by the client's request),
.B rfc1048
or
.B rfc1084
(which always forces an RFC1084-style reply), or
.B cmu
(which always forces a CMU-style reply).
.PP
The
.B hn
tag is strictly a boolean tag; it does not take the usual equals-sign and
value. It's presence indicates that the hostname should be sent to RFC1084
clients.
.I Bootpd
attempts to send the entire hostname as it is specified in the configuration
file; if this will not fit into the reply packet, the name is shortened to
just the host field (up to the first period, if present) and then tried.
In no case is an arbitrarily-truncated hostname sent (if nothing reasonable
will fit, nothing is sent).
.PP
Often, many host entries share common values for certain tags (such as name
servers, etc.). Rather than repeatedly specifying these tags, a full
specification can be listed for one host entry and shared by others via the
.B tc
(table continuation) mechanism.
Often, the template entry is a dummy host which doesn't actually exist and
never sends bootp requests. This feature is similar to the
.B tc
feature of
.IR termcap (5)
for similar terminals. Note that
.I bootpd
allows the
.B tc
tag symbol to appear anywhere in the host entry, unlike
.I termcap
which requires it to be the last tag. Information explicitly specified for a
host always overrides information implied by a
.B tc
tag symbol, regardless of its location within the entry. The
value of the
.B tc
tag may be the hostname or IP address of any host entry
previously listed in the configuration file.
.PP
Sometimes it is necessary to delete a specific tag after it has been inferred
via
.BR tc .
This can be done using the construction
.IB tag @
which removes the effect of
.I tag
as in
.IR termcap (5).
For example, to completely undo an IEN-116 name server specification, use
":ns@:" at an appropriate place in the configuration entry. After removal
with
.BR @ ,
a tag is eligible to be set again through the
.B tc
mechanism.
.PP
Blank lines and lines beginning with "#" are ignored in the configuration
file. Host entries are separated from one another by newlines; a single host
entry may be extended over multiple lines if the lines end with a backslash
(\\). It is also acceptable for lines to be longer than 80 characters. Tags
may appear in any order, with the following exceptions: the hostname must be
the very first field in an entry, and the hardware type must precede the
hardware address.
.PP
An example
.I /etc/bootptab
file follows:
.PP
.nf
# Sample bootptab file (domain=andrew.cmu.edu)
.default:\\
:hd=/usr/boot:bf=null:\\
:ds=netserver, lancaster:\\
:ns=pcs2, pcs1:\\
:ts=pcs2, pcs1:\\
:sm=255.255.255.0:\\
:gw=gw.cs.cmu.edu:\\
:hn:to=-18000:
carnegie:ht=6:ha=7FF8100000AF:tc=.default:
baldwin:ht=1:ha=0800200159C3:tc=.default:
wylie:ht=1:ha=00DD00CADF00:tc=.default:
arnold:ht=1:ha=0800200102AD:tc=.default:
bairdford:ht=1:ha=08002B02A2F9:tc=.default:
bakerstown:ht=1:ha=08002B0287C8:tc=.default:
# Special domain name server and option tags for next host
butlerjct:ha=08002001560D:ds=128.2.13.42:\\
:T37=0x12345927AD3BCF:\\
:T99="Special ASCII string":\\
:tc=.default:
gastonville:ht=6:ha=7FFF81000A47:tc=.default:
hahntown:ht=6:ha=7FFF81000434:tc=.default:
hickman:ht=6:ha=7FFF810001BA:tc=.default:
lowber:ht=1:ha=00DD00CAF000:tc=.default:
mtoliver:ht=1:ha=00DD00FE1600:tc=.default:
.fi
.SH FILES
/etc/bootptab
.SH "SEE ALSO"
.br
bootpd(8), tftpd(8),
.br
DARPA Internet Request For Comments RFC951, RFC1048, RFC1084, Assigned Numbers

124
libexec/bootpd/bootptab.cmu Normal file
View File

@ -0,0 +1,124 @@
# /etc/bootptab: database for bootp server (/etc/bootpd)
# (I've hacked on this but can't test it... -gwr)
# Blank lines and lines beginning with '#' are ignored.
#
# Legend: (see bootptab.5)
# first field -- hostname (not indented)
# bf -- bootfile
# bs -- bootfile size in 512-octet blocks
# cs -- cookie servers
# df -- dump file name
# dn -- domain name
# ds -- domain name servers
# ef -- extension file
# gw -- gateways
# ha -- hardware address
# hd -- home directory for bootfiles
# hn -- host name set for client
# ht -- hardware type
# im -- impress servers
# ip -- host IP address
# lg -- log servers
# lp -- LPR servers
# ns -- IEN-116 name servers
# ra -- reply address
# rl -- resource location protocol servers
# rp -- root path
# sa -- boot server address
# sm -- subnet mask
# sw -- swap server
# tc -- template host (points to similar host entry)
# td -- TFTP directory
# to -- time offset (seconds)
# ts -- time servers
# vm -- vendor magic number
# Tn -- generic option tag n
#
# Be careful about including backslashes where they're needed. Weird (bad)
# things can happen when a backslash is omitted where one is intended.
# Also, note that generic option data must be either a string or a
# sequence of bytes where each byte is a two-digit hex value.
# First, we define a global entry which specifies the stuff every host uses.
# (Host name lookups are relative to the domain: andrew.cmu.edu)
.default:\
:hn:dn=cmu.edu:\
:hd=/usr/boot:\
:ds=netserver, lancaster:\
:ns=pcs2, pcs1:\
:ts=pcs2, pcs1:\
:sm=255.255.0.0:\
:gw=gw.cs.cmu.edu:\
to=auto:
# Next, we can define different master entries for each subnet. . .
.subnet13 :sm=255.255.255.0:gw=128.2.13.1 :tc=.default:
.subnet19 :sm=255.255.255.0:gw=128.2.19.1 :tc=.default:
.subnet232 :sm=255.255.255.0:gw=128.2.232.1 :tc=.default:
#
# We should be able to use as many levels of indirection as desired. Use
# your imagination. . .
#
# Individual entries (could also have different servers for some/all of these
# hosts, but we don't really use this feature at CMU):
carnegie:tc=.subnet13:ht=ieee802:ha=7FF8100000AF:
baldwin:tc=.subnet19:ha=0800200159C3:
wylie:tc=.subnet232:ha=00DD00CADF00:
arnold:tc=.subnet19:ha=0800200102AD:
bairdford:tc=.subnet19:ha=08002B02A2F9:
bakerstown:tc=.subnet19:ha=08002B0287C8:
butlerjct:tc=.subnet232:ha=08002001560D:
gastonville:tc=.subnet232:ht=ieee802:ha=7FFF81000A47:
hahntown:tc=.subnet13:ht=ieee802:ha=7FFF81000434:
hickman:tc=.subnet19:ht=ieee802:ha=7FFF810001BA:
lowber:tc=.subnet13:ha=00DD00CAF000:
mtoliver:tc=.subnet19:ha=00DD00FE1600:
osborne:tc=.subnet232:ha=00DD00CAD600:
russelton:tc=.subnet232:ha=080020017FC3:
thornburg:tc=.subnet13:ha=080020012A33:
# Hmmm. . . Let's throw in some whitespace for readability. . . .
andrew: tc=.subnet19:ha=00DD00C88900:
birdville: tc=.subnet19:ha=00DD00FE2D00:
coudersport: tc=.subnet13:ha=00DD00CB1E00:
bridgeville: tc=.subnet232:ha=080020011394:
franklin: tc=.subnet19:ha=08002B02A5D5:
hollidaysburg: tc=.subnet19:ht=ieee802:ha=7FFF810002C8:
honesdale: tc=.subnet19:ha=08002B02F83F:
huntingdon: tc=.subnet19:ha=08002B02E410:
indiana: tc=.subnet13:ha=08002B029BEC:
jimthorpe: tc=.subnet232:ha=08002B02FBBA:
kittanning: tc=.subnet232:ha=08002B0273FC:
lebanon: tc=.subnet232:ha=08002B037F67:
lewisburg: tc=.subnet19:ha=50005A1A0DE4:
middleburg: tc=.subnet232:ha=00DD00FE1200:
aspinwall: tc=.subnet13:ha=08002B03C163:
berlin: tc=.subnet13:ha=00DD000A4400:
norristown: tc=.subnet13:ha=08002001455B:
pottsville: tc=.subnet13:ha=00DD000A3700:
ridgway: tc=.subnet19:ha=08002B029425:
scranton: tc=.subnet232:ha=0800200113A1:
chalfont: tc=.subnet13:ha=08002001124B:
washington: tc=.subnet19:ha=00DD00656E00:
wellsboro: tc=.subnet13:ha=00DD00CB1C00:
bb1: tc=.subnet19:ha=00DD000A1F00:
adamstown: tc=.subnet13:ha=08002B02D0E6:
beta: tc=.subnet19:ha=02070100B197:
carbondale: tc=.subnet232:ha=08002B022A73:
clairton: tc=.subnet19:ha=080020010FD1:
egypt: tc=.subnet13:ha=00DD00847B00:
fairchance: tc=.subnet232:ha=00DD000AB100:
fairhope: tc=.subnet232:ha=00DD00CB0800:
galeton: tc=.subnet232:ha=08002001138C:
imperial: tc=.subnet232:ha=08002001130C:
kingston: tc=.subnet232:ha=080020011382:
knox: tc=.subnet232:ha=50005A1A0D2A:
lakecity: tc=.subnet13:ha=080020011380:

View File

@ -0,0 +1,92 @@
# /etc/bootptab: database for bootp server (/etc/bootpd)
# Last update: gwr, Sun Dec 12 19:00:00 EDT 1993
# Blank lines and lines beginning with '#' are ignored.
#
# Legend: (see bootptab.5)
# first field -- hostname (not indented)
# bf -- bootfile
# bs -- bootfile size in 512-octet blocks
# cs -- cookie servers
# df -- dump file name
# dn -- domain name
# ds -- domain name servers
# ef -- extension file
# gw -- gateways
# ha -- hardware address
# hd -- home directory for bootfiles
# hn -- host name set for client
# ht -- hardware type
# im -- impress servers
# ip -- host IP address
# lg -- log servers
# lp -- LPR servers
# ns -- IEN-116 name servers
# ra -- reply address
# rl -- resource location protocol servers
# rp -- root path
# sa -- boot server address
# sm -- subnet mask
# sw -- swap server
# tc -- template host (points to similar host entry)
# td -- TFTP directory
# to -- time offset (seconds)
# ts -- time servers
# vm -- vendor magic number
# Tn -- generic option tag n
#
# Be careful about including backslashes where they're needed. Weird (bad)
# things can happen when a backslash is omitted where one is intended.
# Also, note that generic option data must be either a string or a
# sequence of bytes where each byte is a two-digit hex value.
# First, we define a global entry which specifies the stuff every host uses.
# If you leave "td" empty, run bootpd with the "-c /tftpboot" switch
# so path names (boot files) will be interpreted relative to the same
# directory as tftpd will use when opening files.
.default:\
:hn:dn="mc.com":\
:td=/tftpboot:\
:ds=merlin, jericho:\
:to=auto:
# Next, we can define different master entries for each subnet. . .
.subnet16:\
:tc=.default:\
:sm=255.255.255.0:\
:gw=merlin:\
:sa=merlin:
.subnet17:\
:tc=.default:\
:sm=255.255.255.0:\
:gw=merlin-gw:\
:sa=merlin-gw:
#
# We should be able to use as many levels of indirection as desired. Use
# your imagination. . .
#
# Individual entries (could also have different servers for some/all of these
# hosts, but we don't really use this feature at CMU):
# Emulex terminal server
emulex: tc=.subnet16:ha=00.00.C9.00.42.E0:bf=P4KTL0E:
# Lantronix eps1
eps1: tc=.subnet16:ha=00.80.A3.04.1D.78:
# Tadpole 885 board.
tp885: tc=.subnet17:ha=08.00.4C.00.2F.74:bf=tp885sys2.cfe:
# MVME147 VxWorks board.
#mvme147:tc=.subnet17:ha=08.00.3e.20.da.47:bf=mv147vxw.st:
# These are just for testing
walnut:tc=.subnet16:ha=walnut:
banana:tc=.subnet17:ha=banana:
thor:tc=.subnet17:ha=thor:
classic:tc=.subnet16:ha=classic:

23
libexec/bootpd/bptypes.h Normal file
View File

@ -0,0 +1,23 @@
/* bptypes.h */
#ifndef BPTYPES_H
#define BPTYPES_H
/*
* 32 bit integers are different types on various architectures
*/
#ifndef int32
#define int32 long
#endif
typedef unsigned int32 u_int32;
/*
* Nice typedefs. . .
*/
typedef int boolean;
typedef unsigned char byte;
#endif /* BPTYPES_H */

413
libexec/bootpd/dovend.c Normal file
View File

@ -0,0 +1,413 @@
/*
* dovend.c : Inserts all but the first few vendor options.
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h> /* inet_ntoa */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#ifndef USE_BFUNCS
# include <memory.h>
/* Yes, memcpy is OK here (no overlapped copies). */
# define bcopy(a,b,c) memcpy(b,a,c)
# define bzero(p,l) memset(p,0,l)
# define bcmp(a,b,c) memcmp(a,b,c)
# define index strchr
#endif
#include "bootp.h"
#include "bootpd.h"
#include "report.h"
#include "dovend.h"
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
PRIVATE int insert_generic P((struct shared_bindata *, byte **, int *));
/*
* Insert the 2nd part of the options into an option buffer.
* Return amount of space used.
*
* This inserts everything EXCEPT:
* magic cookie, subnet mask, gateway, bootsize, extension file
* Those are handled separately (in bootpd.c) to allow this function
* to be shared between bootpd and bootpef.
*
* When an "extension file" is in use, the options inserted by
* this function go into the exten_file, not the bootp response.
*/
int
dovend_rfc1497(hp, buf, len)
struct host *hp;
byte *buf;
int len;
{
int bytesleft = len;
byte *vp = buf;
char *tmpstr;
static char noroom[] = "%s: No room for \"%s\" option";
#define NEED(LEN, MSG) do \
if (bytesleft < (LEN)) { \
report(LOG_NOTICE, noroom, \
hp->hostname->string, MSG); \
return (vp - buf); \
} while (0)
/*
* Note that the following have already been inserted:
* magic_cookie, subnet_mask, gateway, bootsize
*
* The remaining options are inserted in order of importance.
* (Of course the importance of each is a matter of opinion.)
* The option insertion order should probably be configurable.
*
* This is the order used in the NetBSD version. Can anyone
* explain why the time_offset and swap_server are first?
* Also, why is the hostname so far down the list? -gwr
*/
if (hp->flags.time_offset) {
NEED(6, "to");
*vp++ = TAG_TIME_OFFSET;/* -1 byte */
*vp++ = 4; /* -1 byte */
insert_u_long(htonl(hp->time_offset), &vp); /* -4 bytes */
bytesleft -= 6;
}
/*
* swap server, root path, dump path
*/
if (hp->flags.swap_server) {
NEED(6, "sw");
/* There is just one SWAP_SERVER, so it is not an iplist. */
*vp++ = TAG_SWAP_SERVER;/* -1 byte */
*vp++ = 4; /* -1 byte */
insert_u_long(hp->swap_server.s_addr, &vp); /* -4 bytes */
bytesleft -= 6; /* Fix real count */
}
if (hp->flags.root_path) {
/*
* Check for room for root_path. Add 2 to account for
* TAG_ROOT_PATH and length.
*/
len = strlen(hp->root_path->string);
NEED((len + 2), "rp");
*vp++ = TAG_ROOT_PATH;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->root_path->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
if (hp->flags.dump_file) {
/*
* Check for room for dump_file. Add 2 to account for
* TAG_DUMP_FILE and length.
*/
len = strlen(hp->dump_file->string);
NEED((len + 2), "df");
*vp++ = TAG_DUMP_FILE;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->dump_file->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
/*
* DNS server and domain
*/
if (hp->flags.domain_server) {
if (insert_ip(TAG_DOMAIN_SERVER,
hp->domain_server,
&vp, &bytesleft))
NEED(8, "ds");
}
if (hp->flags.domain_name) {
/*
* Check for room for domain_name. Add 2 to account for
* TAG_DOMAIN_NAME and length.
*/
len = strlen(hp->domain_name->string);
NEED((len + 2), "dn");
*vp++ = TAG_DOMAIN_NAME;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->domain_name->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
/*
* NIS (YP) server and domain
*/
if (hp->flags.nis_server) {
if (insert_ip(TAG_NIS_SERVER,
hp->nis_server,
&vp, &bytesleft))
NEED(8, "ds");
}
if (hp->flags.nis_domain) {
/*
* Check for room for nis_domain. Add 2 to account for
* TAG_NIS_DOMAIN and length.
*/
len = strlen(hp->nis_domain->string);
NEED((len + 2), "dn");
*vp++ = TAG_NIS_DOMAIN;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->nis_domain->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
/* IEN 116 name server */
if (hp->flags.name_server) {
if (insert_ip(TAG_NAME_SERVER,
hp->name_server,
&vp, &bytesleft))
NEED(8, "ns");
}
if (hp->flags.rlp_server) {
if (insert_ip(TAG_RLP_SERVER,
hp->rlp_server,
&vp, &bytesleft))
NEED(8, "rl");
}
/* Time server (RFC 868) */
if (hp->flags.time_server) {
if (insert_ip(TAG_TIME_SERVER,
hp->time_server,
&vp, &bytesleft))
NEED(8, "ts");
}
/* NTP (time) Server (RFC 1129) */
if (hp->flags.ntp_server) {
if (insert_ip(TAG_NTP_SERVER,
hp->ntp_server,
&vp, &bytesleft))
NEED(8, "ts");
}
/*
* I wonder: If the hostname were "promoted" into the BOOTP
* response part, might these "extension" files possibly be
* shared between several clients?
*
* Also, why not just use longer BOOTP packets with all the
* additional length used as option data. This bootpd version
* already supports that feature by replying with the same
* packet length as the client request packet. -gwr
*/
if (hp->flags.name_switch && hp->flags.send_name) {
/*
* Check for room for hostname. Add 2 to account for
* TAG_HOST_NAME and length.
*/
len = strlen(hp->hostname->string);
#if 0
/*
* XXX - Too much magic. The user can always set the hostname
* to the short version in the bootptab file. -gwr
*/
if ((len + 2) > bytesleft) {
/*
* Not enough room for full (domain-qualified) hostname, try
* stripping it down to just the first field (host).
*/
tmpstr = hp->hostname->string;
len = 0;
while (*tmpstr && (*tmpstr != '.')) {
tmpstr++;
len++;
}
}
#endif
NEED((len + 2), "hn");
*vp++ = TAG_HOST_NAME;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->hostname->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
/*
* The rest of these are less important, so they go last.
*/
if (hp->flags.lpr_server) {
if (insert_ip(TAG_LPR_SERVER,
hp->lpr_server,
&vp, &bytesleft))
NEED(8, "lp");
}
if (hp->flags.cookie_server) {
if (insert_ip(TAG_COOKIE_SERVER,
hp->cookie_server,
&vp, &bytesleft))
NEED(8, "cs");
}
if (hp->flags.log_server) {
if (insert_ip(TAG_LOG_SERVER,
hp->log_server,
&vp, &bytesleft))
NEED(8, "lg");
}
/*
* XXX - Add new tags here (to insert options)
*/
if (hp->flags.generic) {
if (insert_generic(hp->generic, &vp, &bytesleft))
NEED(64, "(generic)");
}
/*
* The end marker is inserted by the caller.
*/
return (vp - buf);
#undef NEED
} /* dovend_rfc1497 */
/*
* Insert a tag value, a length value, and a list of IP addresses into the
* memory buffer indirectly pointed to by "dest". "tag" is the RFC1048 tag
* number to use, "iplist" is a pointer to a list of IP addresses
* (struct in_addr_list), and "bytesleft" points to an integer which
* indicates the size of the "dest" buffer.
*
* Return zero if everything fits.
*
* This is used to fill the vendor-specific area of a bootp packet in
* conformance to RFC1048.
*/
int
insert_ip(tag, iplist, dest, bytesleft)
byte tag;
struct in_addr_list *iplist;
byte **dest;
int *bytesleft;
{
struct in_addr *addrptr;
unsigned addrcount = 1;
byte *d;
if (iplist == NULL)
return (0);
if (*bytesleft >= 6) {
d = *dest; /* Save pointer for later */
**dest = tag;
(*dest) += 2;
(*bytesleft) -= 2; /* Account for tag and length */
addrptr = iplist->addr;
addrcount = iplist->addrcount;
while ((*bytesleft >= 4) && (addrcount > 0)) {
insert_u_long(addrptr->s_addr, dest);
addrptr++;
addrcount--;
(*bytesleft) -= 4; /* Four bytes per address */
}
d[1] = (byte) ((*dest - d - 2) & 0xFF);
}
return (addrcount);
}
/*
* Insert generic data into a bootp packet. The data is assumed to already
* be in RFC1048 format. It is inserted using a first-fit algorithm which
* attempts to insert as many tags as possible. Tags and data which are
* too large to fit are skipped; any remaining tags are tried until they
* have all been exhausted.
* Return zero if everything fits.
*/
static int
insert_generic(gendata, buff, bytesleft)
struct shared_bindata *gendata;
byte **buff;
int *bytesleft;
{
byte *srcptr;
int length, numbytes;
int skipped = 0;
if (gendata == NULL)
return (0);
srcptr = gendata->data;
length = gendata->length;
while ((length > 0) && (*bytesleft > 0)) {
switch (*srcptr) {
case TAG_END:
length = 0; /* Force an exit on next iteration */
break;
case TAG_PAD:
*(*buff)++ = *srcptr++;
(*bytesleft)--;
length--;
break;
default:
numbytes = srcptr[1] + 2;
if (*bytesleft < numbytes)
skipped += numbytes;
else {
bcopy(srcptr, *buff, numbytes);
(*buff) += numbytes;
(*bytesleft) -= numbytes;
}
srcptr += numbytes;
length -= numbytes;
break;
}
} /* while */
return (skipped);
}
/*
* Insert the unsigned long "value" into memory starting at the byte
* pointed to by the byte pointer (*dest). (*dest) is updated to
* point to the next available byte.
*
* Since it is desirable to internally store network addresses in network
* byte order (in struct in_addr's), this routine expects longs to be
* passed in network byte order.
*
* However, due to the nature of the main algorithm, the long must be in
* host byte order, thus necessitating the use of ntohl() first.
*/
void
insert_u_long(value, dest)
u_int32 value;
byte **dest;
{
byte *temp;
int n;
value = ntohl(value); /* Must use host byte order here */
temp = (*dest += 4);
for (n = 4; n > 0; n--) {
*--temp = (byte) (value & 0xFF);
value >>= 8;
}
/* Final result is network byte order */
}
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

13
libexec/bootpd/dovend.h Normal file
View File

@ -0,0 +1,13 @@
/* dovend.h */
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
extern int dovend_rfc1497 P((struct host *hp, u_char *buf, int len));
extern int insert_ip P((int, struct in_addr_list *, u_char **, int *));
extern void insert_u_long P((u_int32, u_char **));
#undef P

382
libexec/bootpd/dumptab.c Normal file
View File

@ -0,0 +1,382 @@
/*
* dumptab.c - handles dumping the database
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h> /* inet_ntoa */
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <time.h>
#ifndef USE_BFUNCS
#include <memory.h>
/* Yes, memcpy is OK here (no overlapped copies). */
#define bcopy(a,b,c) memcpy(b,a,c)
#define bzero(p,l) memset(p,0,l)
#define bcmp(a,b,c) memcmp(a,b,c)
#endif
#include "bootp.h"
#include "hash.h"
#include "hwaddr.h"
#include "report.h"
#include "patchlevel.h"
#include "bootpd.h"
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
static void dump_generic P((FILE *, struct shared_bindata *));
static void dump_host P((FILE *, struct host *));
static void list_ipaddresses P((FILE *, struct in_addr_list *));
#undef P
#ifndef DEBUG
void
dumptab(filename)
char *filename;
{
report(LOG_INFO, "No dumptab support!");
}
#else /* DEBUG */
/*
* Dump the internal memory database to bootpd_dump.
*/
void
dumptab(filename)
char *filename;
{
int n;
struct host *hp;
FILE *fp;
long t;
/* Print symbols in alphabetical order for reader's convenience. */
static char legend[] = "#\n# Legend:\t(see bootptab.5)\n\
#\tfirst field -- hostname (not indented)\n\
#\tbf -- bootfile\n\
#\tbs -- bootfile size in 512-octet blocks\n\
#\tcs -- cookie servers\n\
#\tdf -- dump file name\n\
#\tdn -- domain name\n\
#\tds -- domain name servers\n\
#\tef -- extension file\n\
#\tex -- exec file (YORK_EX_OPTION)\n\
#\tgw -- gateways\n\
#\tha -- hardware address\n\
#\thd -- home directory for bootfiles\n\
#\thn -- host name set for client\n\
#\tht -- hardware type\n\
#\tim -- impress servers\n\
#\tip -- host IP address\n\
#\tlg -- log servers\n\
#\tlp -- LPR servers\n\
#\tms -- message size\n\
#\tmw -- min wait (secs)\n\
#\tns -- IEN-116 name servers\n\
#\tnt -- NTP servers (RFC 1129)\n\
#\tra -- reply address override\n\
#\trl -- resource location protocol servers\n\
#\trp -- root path\n\
#\tsa -- boot server address\n\
#\tsm -- subnet mask\n\
#\tsw -- swap server\n\
#\ttc -- template host (points to similar host entry)\n\
#\ttd -- TFTP directory\n\
#\tto -- time offset (seconds)\n\
#\tts -- time servers\n\
#\tvm -- vendor magic number\n\
#\tyd -- YP (NIS) domain\n\
#\tys -- YP (NIS) servers\n\
#\tTn -- generic option tag n\n\
\n";
/*
* Open bootpd.dump file.
*/
if ((fp = fopen(filename, "w")) == NULL) {
report(LOG_ERR, "error opening \"%s\": %s",
filename, get_errmsg());
exit(1);
}
t = time(NULL);
fprintf(fp, "\n# %s %s.%d\n", progname, VERSION, PATCHLEVEL);
fprintf(fp, "# %s: dump of bootp server database.\n", filename);
fprintf(fp, "# Dump taken %s", ctime(&t));
fwrite(legend, 1, sizeof(legend) - 1, fp);
n = 0;
for (hp = (struct host *) hash_FirstEntry(nmhashtable); hp != NULL;
hp = (struct host *) hash_NextEntry(nmhashtable)) {
dump_host(fp, hp);
fprintf(fp, "\n");
n++;
}
fclose(fp);
report(LOG_INFO, "dumped %d entries to \"%s\".", n, filename);
}
/*
* Dump all the available information on the host pointed to by "hp".
* The output is sent to the file pointed to by "fp".
*/
static void
dump_host(fp, hp)
FILE *fp;
struct host *hp;
{
/* Print symbols in alphabetical order for reader's convenience. */
if (hp) {
fprintf(fp, "%s:", (hp->hostname ?
hp->hostname->string : "?"));
if (hp->flags.bootfile) {
fprintf(fp, "\\\n\t:bf=%s:", hp->bootfile->string);
}
if (hp->flags.bootsize) {
fprintf(fp, "\\\n\t:bs=");
if (hp->flags.bootsize_auto) {
fprintf(fp, "auto:");
} else {
fprintf(fp, "%d:", hp->bootsize);
}
}
if (hp->flags.cookie_server) {
fprintf(fp, "\\\n\t:cs=");
list_ipaddresses(fp, hp->cookie_server);
fprintf(fp, ":");
}
if (hp->flags.dump_file) {
fprintf(fp, "\\\n\t:df=%s:", hp->dump_file->string);
}
if (hp->flags.domain_name) {
fprintf(fp, "\\\n\t:dn=%s:", hp->domain_name->string);
}
if (hp->flags.domain_server) {
fprintf(fp, "\\\n\t:ds=");
list_ipaddresses(fp, hp->domain_server);
fprintf(fp, ":");
}
if (hp->flags.exten_file) {
fprintf(fp, "\\\n\t:ef=%s:", hp->exten_file->string);
}
if (hp->flags.exec_file) {
fprintf(fp, "\\\n\t:ex=%s:", hp->exec_file->string);
}
if (hp->flags.gateway) {
fprintf(fp, "\\\n\t:gw=");
list_ipaddresses(fp, hp->gateway);
fprintf(fp, ":");
}
/* FdC: swap_server (see below) */
if (hp->flags.homedir) {
fprintf(fp, "\\\n\t:hd=%s:", hp->homedir->string);
}
/* FdC: dump_file (see above) */
/* FdC: domain_name (see above) */
/* FdC: root_path (see below) */
if (hp->flags.name_switch && hp->flags.send_name) {
fprintf(fp, "\\\n\t:hn:");
}
if (hp->flags.htype) {
int hlen = haddrlength(hp->htype);
fprintf(fp, "\\\n\t:ht=%u:", (unsigned) hp->htype);
if (hp->flags.haddr) {
fprintf(fp, "ha=\"%s\":",
haddrtoa(hp->haddr, hlen));
}
}
if (hp->flags.impress_server) {
fprintf(fp, "\\\n\t:im=");
list_ipaddresses(fp, hp->impress_server);
fprintf(fp, ":");
}
/* NetBSD: swap_server (see below) */
if (hp->flags.iaddr) {
fprintf(fp, "\\\n\t:ip=%s:", inet_ntoa(hp->iaddr));
}
if (hp->flags.log_server) {
fprintf(fp, "\\\n\t:lg=");
list_ipaddresses(fp, hp->log_server);
fprintf(fp, ":");
}
if (hp->flags.lpr_server) {
fprintf(fp, "\\\n\t:lp=");
list_ipaddresses(fp, hp->lpr_server);
fprintf(fp, ":");
}
if (hp->flags.msg_size) {
fprintf(fp, "\\\n\t:ms=%d:", hp->msg_size);
}
if (hp->flags.min_wait) {
fprintf(fp, "\\\n\t:mw=%d:", hp->min_wait);
}
if (hp->flags.name_server) {
fprintf(fp, "\\\n\t:ns=");
list_ipaddresses(fp, hp->name_server);
fprintf(fp, ":");
}
if (hp->flags.ntp_server) {
fprintf(fp, "\\\n\t:nt=");
list_ipaddresses(fp, hp->ntp_server);
fprintf(fp, ":");
}
if (hp->flags.reply_addr) {
fprintf(fp, "\\\n\t:ra=%s:", inet_ntoa(hp->reply_addr));
}
if (hp->flags.rlp_server) {
fprintf(fp, "\\\n\t:rl=");
list_ipaddresses(fp, hp->rlp_server);
fprintf(fp, ":");
}
if (hp->flags.root_path) {
fprintf(fp, "\\\n\t:rp=%s:", hp->root_path->string);
}
if (hp->flags.bootserver) {
fprintf(fp, "\\\n\t:sa=%s:", inet_ntoa(hp->bootserver));
}
if (hp->flags.subnet_mask) {
fprintf(fp, "\\\n\t:sm=%s:", inet_ntoa(hp->subnet_mask));
}
if (hp->flags.swap_server) {
fprintf(fp, "\\\n\t:sw=%s:", inet_ntoa(hp->subnet_mask));
}
if (hp->flags.tftpdir) {
fprintf(fp, "\\\n\t:td=%s:", hp->tftpdir->string);
}
/* NetBSD: rootpath (see above) */
/* NetBSD: domainname (see above) */
/* NetBSD: dumpfile (see above) */
if (hp->flags.time_offset) {
fprintf(fp, "\\\n\t:to=%ld:", hp->time_offset);
}
if (hp->flags.time_server) {
fprintf(fp, "\\\n\t:ts=");
list_ipaddresses(fp, hp->time_server);
fprintf(fp, ":");
}
if (hp->flags.vm_cookie) {
fprintf(fp, "\\\n\t:vm=");
if (!bcmp(hp->vm_cookie, vm_rfc1048, 4)) {
fprintf(fp, "rfc1048:");
} else if (!bcmp(hp->vm_cookie, vm_cmu, 4)) {
fprintf(fp, "cmu:");
} else {
fprintf(fp, "%d.%d.%d.%d:",
(int) ((hp->vm_cookie)[0]),
(int) ((hp->vm_cookie)[1]),
(int) ((hp->vm_cookie)[2]),
(int) ((hp->vm_cookie)[3]));
}
}
if (hp->flags.nis_domain) {
fprintf(fp, "\\\n\t:yd=%s:",
hp->nis_domain->string);
}
if (hp->flags.nis_server) {
fprintf(fp, "\\\n\t:ys=");
list_ipaddresses(fp, hp->nis_server);
fprintf(fp, ":");
}
/*
* XXX - Add new tags here (or above,
* so they print in alphabetical order).
*/
if (hp->flags.generic) {
dump_generic(fp, hp->generic);
}
}
}
static void
dump_generic(fp, generic)
FILE *fp;
struct shared_bindata *generic;
{
u_char *bp = generic->data;
u_char *ep = bp + generic->length;
u_char tag;
int len;
while (bp < ep) {
tag = *bp++;
if (tag == TAG_PAD)
continue;
if (tag == TAG_END)
return;
len = *bp++;
if (bp + len > ep) {
fprintf(fp, " #junk in generic! :");
return;
}
fprintf(fp, "\\\n\t:T%d=", tag);
while (len) {
fprintf(fp, "%02X", *bp);
bp++;
len--;
if (len)
fprintf(fp, ".");
}
fprintf(fp, ":");
}
}
/*
* Dump an entire struct in_addr_list of IP addresses to the indicated file.
*
* The addresses are printed in standard ASCII "dot" notation and separated
* from one another by a single space. A single leading space is also
* printed before the first adddress.
*
* Null lists produce no output (and no error).
*/
static void
list_ipaddresses(fp, ipptr)
FILE *fp;
struct in_addr_list *ipptr;
{
unsigned count;
struct in_addr *addrptr;
if (ipptr) {
count = ipptr->addrcount;
addrptr = ipptr->addr;
while (count > 0) {
fprintf(fp, "%s", inet_ntoa(*addrptr++));
count--;
if (count)
fprintf(fp, ", ");
}
}
}
#endif /* DEBUG */
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

374
libexec/bootpd/getether.c Normal file
View File

@ -0,0 +1,374 @@
/*
* getether.c : get the ethernet address of an interface
*
* All of this code is quite system-specific. As you may well
* guess, it took a good bit of detective work to figure out!
*
* If you figure out how to do this on another system,
* please let me know. <gwr@mc.com>
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <ctype.h>
#include <syslog.h>
#include "report.h"
#define EALEN 6
#if defined(ultrix) || (defined(__osf__) && defined(__alpha))
/*
* This is really easy on Ultrix! Thanks to
* Harald Lundberg <hl@tekla.fi> for this code.
*
* The code here is not specific to the Alpha, but that was the
* only symbol we could find to identify DEC's version of OSF.
* (Perhaps we should just define DEC in the Makefile... -gwr)
*/
#include <sys/ioctl.h>
#include <net/if.h> /* struct ifdevea */
getether(ifname, eap)
char *ifname, *eap;
{
int rc = -1;
int fd;
struct ifdevea phys;
bzero(&phys, sizeof(phys));
strcpy(phys.ifr_name, ifname);
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
return -1;
}
if (ioctl(fd, SIOCRPHYSADDR, &phys) < 0) {
report(LOG_ERR, "getether: ioctl SIOCRPHYSADDR failed");
} else {
bcopy(&phys.current_pa[0], eap, EALEN);
rc = 0;
}
close(fd);
return rc;
}
#define GETETHER
#endif /* ultrix|osf1 */
#ifdef SUNOS
#include <sys/sockio.h>
#include <sys/time.h> /* needed by net_if.h */
#include <net/nit_if.h> /* for NIOCBIND */
#include <net/if.h> /* for struct ifreq */
getether(ifname, eap)
char *ifname; /* interface name from ifconfig structure */
char *eap; /* Ether address (output) */
{
int rc = -1;
struct ifreq ifrnit;
int nit;
bzero((char *) &ifrnit, sizeof(ifrnit));
strncpy(&ifrnit.ifr_name[0], ifname, IFNAMSIZ);
nit = open("/dev/nit", 0);
if (nit < 0) {
report(LOG_ERR, "getether: open /dev/nit: %s",
get_errmsg());
return rc;
}
do {
if (ioctl(nit, NIOCBIND, &ifrnit) < 0) {
report(LOG_ERR, "getether: NIOCBIND on nit");
break;
}
if (ioctl(nit, SIOCGIFADDR, &ifrnit) < 0) {
report(LOG_ERR, "getether: SIOCGIFADDR on nit");
break;
}
bcopy(&ifrnit.ifr_addr.sa_data[0], eap, EALEN);
rc = 0;
} while (0);
close(nit);
return rc;
}
#define GETETHER
#endif /* SUNOS */
#if defined(__386BSD__) || defined(__NetBSD__)
/* Thanks to John Brezak <brezak@ch.hp.com> for this code. */
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
getether(ifname, eap)
char *ifname; /* interface name from ifconfig structure */
char *eap; /* Ether address (output) */
{
int fd, rc = -1;
register int n;
struct ifreq ibuf[16], ifr;
struct ifconf ifc;
register struct ifreq *ifrp, *ifend;
/* Fetch the interface configuration */
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
report(LOG_ERR, "getether: socket %s: %s", ifname, get_errmsg());
return (fd);
}
ifc.ifc_len = sizeof(ibuf);
ifc.ifc_buf = (caddr_t) ibuf;
if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) < 0 ||
ifc.ifc_len < sizeof(struct ifreq)) {
report(LOG_ERR, "getether: SIOCGIFCONF: %s", get_errmsg);
goto out;
}
/* Search interface configuration list for link layer address. */
ifrp = ibuf;
ifend = (struct ifreq *) ((char *) ibuf + ifc.ifc_len);
while (ifrp < ifend) {
/* Look for interface */
if (strcmp(ifname, ifrp->ifr_name) == 0 &&
ifrp->ifr_addr.sa_family == AF_LINK &&
((struct sockaddr_dl *) &ifrp->ifr_addr)->sdl_type == IFT_ETHER) {
bcopy(LLADDR((struct sockaddr_dl *) &ifrp->ifr_addr), eap, EALEN);
rc = 0;
break;
}
/* Bump interface config pointer */
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
if (n < sizeof(*ifrp))
n = sizeof(*ifrp);
ifrp = (struct ifreq *) ((char *) ifrp + n);
}
out:
close(fd);
return (rc);
}
#define GETETHER
#endif /* __NetBSD__ */
#ifdef SVR4
/*
* This is for "Streams TCP/IP" by Lachman Associates.
* They sure made this cumbersome! -gwr
*/
#include <sys/sockio.h>
#include <sys/dlpi.h>
#include <stropts.h>
#ifndef NULL
#define NULL 0
#endif
getether(ifname, eap)
char *ifname; /* interface name from ifconfig structure */
char *eap; /* Ether address (output) */
{
int rc = -1;
char devname[32];
char tmpbuf[sizeof(union DL_primitives) + 16];
struct strbuf cbuf;
int fd, flags;
union DL_primitives *dlp;
char *enaddr;
int unit = -1; /* which unit to attach */
sprintf(devname, "/dev/%s", ifname);
fd = open(devname, 2);
if (fd < 0) {
/* Try without the trailing digit. */
char *p = devname + 5;
while (isalpha(*p))
p++;
if (isdigit(*p)) {
unit = *p - '0';
*p = '\0';
}
fd = open(devname, 2);
if (fd < 0) {
report(LOG_ERR, "getether: open %s: %s",
devname, get_errmsg());
return rc;
}
}
#ifdef DL_ATTACH_REQ
/*
* If this is a "Style 2" DLPI, then we must "attach" first
* to tell the driver which unit (board, port) we want.
* For now, decide this based on the device name.
* (Should do "info_req" and check dl_provider_style ...)
*/
if (unit >= 0) {
memset(tmpbuf, 0, sizeof(tmpbuf));
dlp = (union DL_primitives *) tmpbuf;
dlp->dl_primitive = DL_ATTACH_REQ;
dlp->attach_req.dl_ppa = unit;
cbuf.buf = tmpbuf;
cbuf.len = DL_ATTACH_REQ_SIZE;
if (putmsg(fd, &cbuf, NULL, 0) < 0) {
report(LOG_ERR, "getether: attach: putmsg: %s", get_errmsg());
goto out;
}
/* Recv the ack. */
cbuf.buf = tmpbuf;
cbuf.maxlen = sizeof(tmpbuf);
flags = 0;
if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
report(LOG_ERR, "getether: attach: getmsg: %s", get_errmsg());
goto out;
}
/*
* Check the type, etc.
*/
if (dlp->dl_primitive == DL_ERROR_ACK) {
report(LOG_ERR, "getether: attach: dlpi_errno=%d, unix_errno=%d",
dlp->error_ack.dl_errno,
dlp->error_ack.dl_unix_errno);
goto out;
}
if (dlp->dl_primitive != DL_OK_ACK) {
report(LOG_ERR, "getether: attach: not OK or ERROR");
goto out;
}
} /* unit >= 0 */
#endif /* DL_ATTACH_REQ */
/*
* Get the Ethernet address the same way the ARP module
* does when it is pushed onto a new stream (bind).
* One should instead be able just do an dl_info_req
* but many drivers do not supply the hardware address
* in the response to dl_info_req (they MUST supply it
* for dl_bind_ack because the ARP module requires it).
*/
memset(tmpbuf, 0, sizeof(tmpbuf));
dlp = (union DL_primitives *) tmpbuf;
dlp->dl_primitive = DL_BIND_REQ;
dlp->bind_req.dl_sap = 0x8FF; /* XXX - Unused SAP */
cbuf.buf = tmpbuf;
cbuf.len = DL_BIND_REQ_SIZE;
if (putmsg(fd, &cbuf, NULL, 0) < 0) {
report(LOG_ERR, "getether: bind: putmsg: %s", get_errmsg());
goto out;
}
/* Recv the ack. */
cbuf.buf = tmpbuf;
cbuf.maxlen = sizeof(tmpbuf);
flags = 0;
if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
report(LOG_ERR, "getether: bind: getmsg: %s", get_errmsg());
goto out;
}
/*
* Check the type, etc.
*/
if (dlp->dl_primitive == DL_ERROR_ACK) {
report(LOG_ERR, "getether: bind: dlpi_errno=%d, unix_errno=%d",
dlp->error_ack.dl_errno,
dlp->error_ack.dl_unix_errno);
goto out;
}
if (dlp->dl_primitive != DL_BIND_ACK) {
report(LOG_ERR, "getether: bind: not OK or ERROR");
goto out;
}
if (dlp->bind_ack.dl_addr_offset == 0) {
report(LOG_ERR, "getether: bind: ack has no address");
goto out;
}
if (dlp->bind_ack.dl_addr_length < EALEN) {
report(LOG_ERR, "getether: bind: ack address truncated");
goto out;
}
/*
* Copy the Ethernet address out of the message.
*/
enaddr = tmpbuf + dlp->bind_ack.dl_addr_offset;
memcpy(eap, enaddr, EALEN);
rc = 0;
out:
close(fd);
return rc;
}
#define GETETHER
#endif /* SVR4 */
#ifdef linux
/*
* This is really easy on Linux! This version (for linux)
* written by Nigel Metheringham <nigelm@ohm.york.ac.uk>
*
* The code is almost identical to the Ultrix code - however
* the names are different to confuse the innocent :-)
* Most of this code was stolen from the Ultrix bit above.
*/
#include <sys/ioctl.h>
#include <net/if.h> /* struct ifreq */
/* In a properly configured system this should be either sys/socketio.h
or sys/sockios.h, but on my distribution these don't line up correctly */
#include <linux/sockios.h> /* Needed for IOCTL defs */
getether(ifname, eap)
char *ifname, *eap;
{
int rc = -1;
int fd;
struct ifreq phys;
bzero(&phys, sizeof(phys));
strcpy(phys.ifr_name, ifname);
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
return -1;
}
if (ioctl(fd, SIOCGIFHWADDR, &phys) < 0) {
report(LOG_ERR, "getether: ioctl SIOCGIFHWADDR failed");
} else {
bcopy(phys.ifr_hwaddr, eap, EALEN);
rc = 0;
}
close(fd);
return rc;
}
#define GETETHER
#endif /* linux */
/* If we don't know how on this system, just return an error. */
#ifndef GETETHER
getether(ifname, eap)
char *ifname, *eap;
{
return -1;
}
#endif /* !GETETHER */
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

145
libexec/bootpd/getif.c Normal file
View File

@ -0,0 +1,145 @@
/*
* getif.c : get an interface structure
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#if defined(SUNOS) || defined(SVR4)
#include <sys/sockio.h>
#endif
#ifdef SVR4
#include <sys/stropts.h>
#endif
#include <net/if.h> /* for struct ifreq */
#include <netinet/in.h>
#ifndef NO_UNISTD
#include <unistd.h>
#endif
#include <syslog.h>
#include <errno.h>
#include <assert.h>
#include "getif.h"
#include "report.h"
#ifdef __bsdi__
#define BSD 43
#endif
static struct ifreq ifreq[10]; /* Holds interface configuration */
static struct ifconf ifconf; /* points to ifreq */
static int nmatch();
/* Return a pointer to the interface struct for the passed address. */
struct ifreq *
getif(s, addrp)
int s; /* socket file descriptor */
struct in_addr *addrp; /* destination address on interface */
{
int maxmatch;
int len, m, incr;
struct ifreq *ifrq, *ifrmax;
struct sockaddr_in *sip;
char *p;
/* If no address was supplied, just return NULL. */
if (!addrp)
return (struct ifreq *) 0;
/* Get the interface config if not done already. */
if (ifconf.ifc_len == 0) {
#ifdef SVR4
/*
* SysVr4 returns garbage if you do this the obvious way!
* This one took a while to figure out... -gwr
*/
struct strioctl ioc;
ioc.ic_cmd = SIOCGIFCONF;
ioc.ic_timout = 0;
ioc.ic_len = sizeof(ifreq);
ioc.ic_dp = (char *) ifreq;
m = ioctl(s, I_STR, (char *) &ioc);
ifconf.ifc_len = ioc.ic_len;
ifconf.ifc_req = ifreq;
#else /* SVR4 */
ifconf.ifc_len = sizeof(ifreq);
ifconf.ifc_req = ifreq;
m = ioctl(s, SIOCGIFCONF, (caddr_t) & ifconf);
#endif /* SVR4 */
if ((m < 0) || (ifconf.ifc_len <= 0)) {
report(LOG_ERR, "ioctl SIOCGIFCONF");
return (struct ifreq *) 0;
}
}
maxmatch = 7; /* this many bits or less... */
ifrmax = (struct ifreq *) 0;/* ... is not a valid match */
p = (char *) ifreq;
len = ifconf.ifc_len;
while (len > 0) {
ifrq = (struct ifreq *) p;
sip = (struct sockaddr_in *) &ifrq->ifr_addr;
m = nmatch(addrp, &(sip->sin_addr));
if (m > maxmatch) {
maxmatch = m;
ifrmax = ifrq;
}
/* XXX - Could this be just #ifndef IFNAMSIZ instead? -gwr */
#if (BSD - 0) < 43
/* BSD not defined or earlier than 4.3 */
incr = sizeof(*ifrq);
#else /* NetBSD */
incr = ifrq->ifr_addr.sa_len + IFNAMSIZ;
#endif /* NetBSD */
p += incr;
len -= incr;
}
return ifrmax;
}
/*
* Return the number of leading bits matching in the
* internet addresses supplied.
*/
static int
nmatch(ca, cb)
u_char *ca, *cb; /* ptrs to IP address, network order */
{
u_int m = 0; /* count of matching bits */
u_int n = 4; /* bytes left, then bitmask */
/* Count matching bytes. */
while (n && (*ca == *cb)) {
ca++;
cb++;
m += 8;
n--;
}
/* Now count matching bits. */
if (n) {
n = 0x80;
while (n && ((*ca & n) == (*cb & n))) {
m++;
n >>= 1;
}
}
return (m);
}
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

7
libexec/bootpd/getif.h Normal file
View File

@ -0,0 +1,7 @@
/* getif.h */
#ifdef __STDC__
extern struct ifreq *getif(int, struct in_addr *);
#else
extern struct ifreq *getif();
#endif

425
libexec/bootpd/hash.c Normal file
View File

@ -0,0 +1,425 @@
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of Carnegie Mellon University not be used
in advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
#ifndef lint
static char rcsid[] = "$Id: hash.c,v 1.1.1.1 1994/09/10 14:44:55 csgr Exp $";
#endif
/*
* Generalized hash table ADT
*
* Provides multiple, dynamically-allocated, variable-sized hash tables on
* various data and keys.
*
* This package attempts to follow some of the coding conventions suggested
* by Bob Sidebotham and the AFS Clean Code Committee of the
* Information Technology Center at Carnegie Mellon.
*/
#include <sys/types.h>
#include <stdlib.h>
#ifndef USE_BFUNCS
#include <memory.h>
/* Yes, memcpy is OK here (no overlapped copies). */
#define bcopy(a,b,c) memcpy(b,a,c)
#define bzero(p,l) memset(p,0,l)
#define bcmp(a,b,c) memcmp(a,b,c)
#endif
#include "hash.h"
#define TRUE 1
#define FALSE 0
#ifndef NULL
#define NULL 0
#endif
/*
* This can be changed to make internal routines visible to debuggers, etc.
*/
#ifndef PRIVATE
#define PRIVATE static
#endif
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
PRIVATE void hashi_FreeMembers P((hash_member *, hash_freefp));
#undef P
/*
* Hash table initialization routine.
*
* This routine creates and intializes a hash table of size "tablesize"
* entries. Successful calls return a pointer to the hash table (which must
* be passed to other hash routines to identify the hash table). Failed
* calls return NULL.
*/
hash_tbl *
hash_Init(tablesize)
unsigned tablesize;
{
register hash_tbl *hashtblptr;
register unsigned totalsize;
if (tablesize > 0) {
totalsize = sizeof(hash_tbl)
+ sizeof(hash_member *) * (tablesize - 1);
hashtblptr = (hash_tbl *) malloc(totalsize);
if (hashtblptr) {
bzero((char *) hashtblptr, totalsize);
hashtblptr->size = tablesize; /* Success! */
hashtblptr->bucketnum = 0;
hashtblptr->member = (hashtblptr->table)[0];
}
} else {
hashtblptr = NULL; /* Disallow zero-length tables */
}
return hashtblptr; /* NULL if failure */
}
/*
* Frees an entire linked list of bucket members (used in the open
* hashing scheme). Does nothing if the passed pointer is NULL.
*/
PRIVATE void
hashi_FreeMembers(bucketptr, free_data)
hash_member *bucketptr;
hash_freefp free_data;
{
hash_member *nextbucket;
while (bucketptr) {
nextbucket = bucketptr->next;
(*free_data) (bucketptr->data);
free((char *) bucketptr);
bucketptr = nextbucket;
}
}
/*
* This routine re-initializes the hash table. It frees all the allocated
* memory and resets all bucket pointers to NULL.
*/
void
hash_Reset(hashtable, free_data)
hash_tbl *hashtable;
hash_freefp free_data;
{
hash_member **bucketptr;
unsigned i;
bucketptr = hashtable->table;
for (i = 0; i < hashtable->size; i++) {
hashi_FreeMembers(*bucketptr, free_data);
*bucketptr++ = NULL;
}
hashtable->bucketnum = 0;
hashtable->member = (hashtable->table)[0];
}
/*
* Generic hash function to calculate a hash code from the given string.
*
* For each byte of the string, this function left-shifts the value in an
* accumulator and then adds the byte into the accumulator. The contents of
* the accumulator is returned after the entire string has been processed.
* It is assumed that this result will be used as the "hashcode" parameter in
* calls to other functions in this package. These functions automatically
* adjust the hashcode for the size of each hashtable.
*
* This algorithm probably works best when the hash table size is a prime
* number.
*
* Hopefully, this function is better than the previous one which returned
* the sum of the squares of all the bytes. I'm still open to other
* suggestions for a default hash function. The programmer is more than
* welcome to supply his/her own hash function as that is one of the design
* features of this package.
*/
unsigned
hash_HashFunction(string, len)
unsigned char *string;
register unsigned len;
{
register unsigned accum;
accum = 0;
for (; len > 0; len--) {
accum <<= 1;
accum += (unsigned) (*string++ & 0xFF);
}
return accum;
}
/*
* Returns TRUE if at least one entry for the given key exists; FALSE
* otherwise.
*/
int
hash_Exists(hashtable, hashcode, compare, key)
hash_tbl *hashtable;
unsigned hashcode;
hash_cmpfp compare;
hash_datum *key;
{
register hash_member *memberptr;
memberptr = (hashtable->table)[hashcode % (hashtable->size)];
while (memberptr) {
if ((*compare) (key, memberptr->data)) {
return TRUE; /* Entry does exist */
}
memberptr = memberptr->next;
}
return FALSE; /* Entry does not exist */
}
/*
* Insert the data item "element" into the hash table using "hashcode"
* to determine the bucket number, and "compare" and "key" to determine
* its uniqueness.
*
* If the insertion is successful 0 is returned. If a matching entry
* already exists in the given bucket of the hash table, or some other error
* occurs, -1 is returned and the insertion is not done.
*/
int
hash_Insert(hashtable, hashcode, compare, key, element)
hash_tbl *hashtable;
unsigned hashcode;
hash_cmpfp compare;
hash_datum *key, *element;
{
hash_member *temp;
hashcode %= hashtable->size;
if (hash_Exists(hashtable, hashcode, compare, key)) {
return -1; /* At least one entry already exists */
}
temp = (hash_member *) malloc(sizeof(hash_member));
if (!temp)
return -1; /* malloc failed! */
temp->data = element;
temp->next = (hashtable->table)[hashcode];
(hashtable->table)[hashcode] = temp;
return 0; /* Success */
}
/*
* Delete all data elements which match the given key. If at least one
* element is found and the deletion is successful, 0 is returned.
* If no matching elements can be found in the hash table, -1 is returned.
*/
int
hash_Delete(hashtable, hashcode, compare, key, free_data)
hash_tbl *hashtable;
unsigned hashcode;
hash_cmpfp compare;
hash_datum *key;
hash_freefp free_data;
{
hash_member *memberptr, *tempptr;
hash_member *previous = NULL;
int retval;
retval = -1;
hashcode %= hashtable->size;
/*
* Delete the first member of the list if it matches. Since this moves
* the second member into the first position we have to keep doing this
* over and over until it no longer matches.
*/
memberptr = (hashtable->table)[hashcode];
while (memberptr && (*compare) (key, memberptr->data)) {
(hashtable->table)[hashcode] = memberptr->next;
/*
* Stop hashi_FreeMembers() from deleting the whole list!
*/
memberptr->next = NULL;
hashi_FreeMembers(memberptr, free_data);
memberptr = (hashtable->table)[hashcode];
retval = 0;
}
/*
* Now traverse the rest of the list
*/
if (memberptr) {
previous = memberptr;
memberptr = memberptr->next;
}
while (memberptr) {
if ((*compare) (key, memberptr->data)) {
tempptr = memberptr;
previous->next = memberptr = memberptr->next;
/*
* Put the brakes on hashi_FreeMembers(). . . .
*/
tempptr->next = NULL;
hashi_FreeMembers(tempptr, free_data);
retval = 0;
} else {
previous = memberptr;
memberptr = memberptr->next;
}
}
return retval;
}
/*
* Locate and return the data entry associated with the given key.
*
* If the data entry is found, a pointer to it is returned. Otherwise,
* NULL is returned.
*/
hash_datum *
hash_Lookup(hashtable, hashcode, compare, key)
hash_tbl *hashtable;
unsigned hashcode;
hash_cmpfp compare;
hash_datum *key;
{
hash_member *memberptr;
memberptr = (hashtable->table)[hashcode % (hashtable->size)];
while (memberptr) {
if ((*compare) (key, memberptr->data)) {
return (memberptr->data);
}
memberptr = memberptr->next;
}
return NULL;
}
/*
* Return the next available entry in the hashtable for a linear search
*/
hash_datum *
hash_NextEntry(hashtable)
hash_tbl *hashtable;
{
register unsigned bucket;
register hash_member *memberptr;
/*
* First try to pick up where we left off.
*/
memberptr = hashtable->member;
if (memberptr) {
hashtable->member = memberptr->next; /* Set up for next call */
return memberptr->data; /* Return the data */
}
/*
* We hit the end of a chain, so look through the array of buckets
* until we find a new chain (non-empty bucket) or run out of buckets.
*/
bucket = hashtable->bucketnum + 1;
while ((bucket < hashtable->size) &&
!(memberptr = (hashtable->table)[bucket])) {
bucket++;
}
/*
* Check to see if we ran out of buckets.
*/
if (bucket >= hashtable->size) {
/*
* Reset to top of table for next call.
*/
hashtable->bucketnum = 0;
hashtable->member = (hashtable->table)[0];
/*
* But return end-of-table indication to the caller this time.
*/
return NULL;
}
/*
* Must have found a non-empty bucket.
*/
hashtable->bucketnum = bucket;
hashtable->member = memberptr->next; /* Set up for next call */
return memberptr->data; /* Return the data */
}
/*
* Return the first entry in a hash table for a linear search
*/
hash_datum *
hash_FirstEntry(hashtable)
hash_tbl *hashtable;
{
hashtable->bucketnum = 0;
hashtable->member = (hashtable->table)[0];
return hash_NextEntry(hashtable);
}
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

158
libexec/bootpd/hash.h Normal file
View File

@ -0,0 +1,158 @@
#ifndef HASH_H
#define HASH_H
/* hash.h */
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of Carnegie Mellon University not be used
in advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
/*
* Generalized hash table ADT
*
* Provides multiple, dynamically-allocated, variable-sized hash tables on
* various data and keys.
*
* This package attempts to follow some of the coding conventions suggested
* by Bob Sidebotham and the AFS Clean Code Committee.
*/
/*
* The user must supply the following:
*
* 1. A comparison function which is declared as:
*
* int compare(data1, data2)
* hash_datum *data1, *data2;
*
* This function must compare the desired fields of data1 and
* data2 and return TRUE (1) if the data should be considered
* equivalent (i.e. have the same key value) or FALSE (0)
* otherwise. This function is called through a pointer passed to
* the various hashtable functions (thus pointers to different
* functions may be passed to effect different tests on different
* hash tables).
*
* Internally, all the functions of this package always call the
* compare function with the "key" parameter as the first parameter,
* and a full data element as the second parameter. Thus, the key
* and element arguments to functions such as hash_Lookup() may
* actually be of different types and the programmer may provide a
* compare function which compares the two different object types
* as desired.
*
* Example:
*
* int compare(key, element)
* char *key;
* struct some_complex_structure *element;
* {
* return !strcmp(key, element->name);
* }
*
* key = "John C. Doe"
* element = &some_complex_structure
* hash_Lookup(table, hashcode, compare, key);
*
* 2. A hash function yielding an unsigned integer value to be used
* as the hashcode (index into the hashtable). Thus, the user
* may hash on whatever data is desired and may use several
* different hash functions for various different hash tables.
* The actual hash table index will be the passed hashcode modulo
* the hash table size.
*
* A generalized hash function, hash_HashFunction(), is included
* with this package to make things a little easier. It is not
* guarenteed to use the best hash algorithm in existence. . . .
*/
/*
* Various hash table definitions
*/
/*
* Define "hash_datum" as a universal data type
*/
#ifdef __STDC__
typedef void hash_datum;
#else
typedef char hash_datum;
#endif
typedef struct hash_memberstruct hash_member;
typedef struct hash_tblstruct hash_tbl;
typedef struct hash_tblstruct_hdr hash_tblhdr;
struct hash_memberstruct {
hash_member *next;
hash_datum *data;
};
struct hash_tblstruct_hdr {
unsigned size, bucketnum;
hash_member *member;
};
struct hash_tblstruct {
unsigned size, bucketnum;
hash_member *member; /* Used for linear dump */
hash_member *table[1]; /* Dynamically extended */
};
/* ANSI function prototypes or empty arg list? */
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
typedef int (*hash_cmpfp) P((hash_datum *, hash_datum *));
typedef void (*hash_freefp) P((hash_datum *));
extern hash_tbl *hash_Init P((u_int tablesize));
extern void hash_Reset P((hash_tbl *tbl, hash_freefp));
extern unsigned hash_HashFunction P((u_char *str, u_int len));
extern int hash_Exists P((hash_tbl *, u_int code,
hash_cmpfp, hash_datum *key));
extern int hash_Insert P((hash_tbl *, u_int code,
hash_cmpfp, hash_datum *key,
hash_datum *element));
extern int hash_Delete P((hash_tbl *, u_int code,
hash_cmpfp, hash_datum *key,
hash_freefp));
extern hash_datum *hash_Lookup P((hash_tbl *, u_int code,
hash_cmpfp, hash_datum *key));
extern hash_datum *hash_FirstEntry P((hash_tbl *));
extern hash_datum *hash_NextEntry P((hash_tbl *));
#undef P
#endif /* HASH_H */

294
libexec/bootpd/hwaddr.c Normal file
View File

@ -0,0 +1,294 @@
/*
* hwaddr.c - routines that deal with hardware addresses.
* (i.e. Ethernet)
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#if defined(SUNOS) || defined(SVR4)
#include <sys/sockio.h>
#endif
#ifdef SVR4
#include <sys/stream.h>
#include <stropts.h>
#include <fcntl.h>
#endif
#include <net/if_arp.h>
#include <netinet/in.h>
#include <stdio.h>
#ifndef NO_UNISTD
#include <unistd.h>
#endif
#include <syslog.h>
#ifndef USE_BFUNCS
/* Yes, memcpy is OK here (no overlapped copies). */
#include <memory.h>
#define bcopy(a,b,c) memcpy(b,a,c)
#define bzero(p,l) memset(p,0,l)
#define bcmp(a,b,c) memcmp(a,b,c)
#endif
/* For BSD 4.4, set arp entry by writing to routing socket */
#if defined(BSD)
#if BSD >= 199306
extern int bsd_arp_set __P((struct in_addr *, char *, int));
#endif
#endif
#include "bptypes.h"
#include "hwaddr.h"
#include "report.h"
extern int debug;
/*
* Hardware address lengths (in bytes) and network name based on hardware
* type code. List in order specified by Assigned Numbers RFC; Array index
* is hardware type code. Entries marked as zero are unknown to the author
* at this time. . . .
*/
struct hwinfo hwinfolist[] =
{
{0, "Reserved"}, /* Type 0: Reserved (don't use this) */
{6, "Ethernet"}, /* Type 1: 10Mb Ethernet (48 bits) */
{1, "3Mb Ethernet"}, /* Type 2: 3Mb Ethernet (8 bits) */
{0, "AX.25"}, /* Type 3: Amateur Radio AX.25 */
{1, "ProNET"}, /* Type 4: Proteon ProNET Token Ring */
{0, "Chaos"}, /* Type 5: Chaos */
{6, "IEEE 802"}, /* Type 6: IEEE 802 Networks */
{0, "ARCNET"} /* Type 7: ARCNET */
};
int hwinfocnt = sizeof(hwinfolist) / sizeof(hwinfolist[0]);
/*
* Setup the arp cache so that IP address 'ia' will be temporarily
* bound to hardware address 'ha' of length 'len'.
*/
void
setarp(s, ia, ha, len)
int s; /* socket fd */
struct in_addr *ia;
u_char *ha;
int len;
{
#ifdef SIOCSARP
struct arpreq arpreq; /* Arp request ioctl block */
struct sockaddr_in *si;
#ifdef SVR4
int fd;
struct strioctl iocb;
#endif /* SVR4 */
bzero((caddr_t) & arpreq, sizeof(arpreq));
arpreq.arp_flags = ATF_INUSE | ATF_COM;
/* Set up the protocol address. */
arpreq.arp_pa.sa_family = AF_INET;
si = (struct sockaddr_in *) &arpreq.arp_pa;
si->sin_addr = *ia;
/* Set up the hardware address. */
bcopy(ha, arpreq.arp_ha.sa_data, len);
#ifdef SVR4
/*
* And now the stuff for System V Rel 4.x which does not
* appear to allow SIOCxxx ioctls on a socket descriptor.
* Thanks to several people: (all sent the same fix)
* Barney Wolff <barney@databus.com>,
* bear@upsys.se (Bj|rn Sj|holm),
* Michael Kuschke <Michael.Kuschke@Materna.DE>,
*/
if ((fd=open("/dev/arp", O_RDWR)) < 0) {
report(LOG_ERR, "open /dev/arp: %s\n", get_errmsg());
}
iocb.ic_cmd = SIOCSARP;
iocb.ic_timout = 0;
iocb.ic_dp = (char *)&arpreq;
iocb.ic_len = sizeof(arpreq);
if (ioctl(fd, I_STR, (caddr_t)&iocb) < 0) {
report(LOG_ERR, "ioctl I_STR: %s\n", get_errmsg());
}
close (fd);
#else /* SVR4 */
/*
* On SunOS, the ioctl sometimes returns ENXIO, and it
* appears to happen when the ARP cache entry you tried
* to add is already in the cache. (Sigh...)
* XXX - Should this error simply be ignored? -gwr
*/
if (ioctl(s, SIOCSARP, (caddr_t) & arpreq) < 0) {
report(LOG_ERR, "ioctl SIOCSARP: %s", get_errmsg());
}
#endif /* SVR4 */
#else /* SIOCSARP */
#if defined(BSD) && (BSD >= 199306)
bsd_arp_set(ia, ha, len);
#else /* Not BSD 4.4, and SIOCSARP not defined */
/*
* Oh well, SIOCSARP is not defined. Just run arp(8).
* XXX - Gag!
*/
char buf[256];
int status;
sprintf(buf, "arp -s %s %s temp",
inet_ntoa(*ia), haddrtoa(ha, len));
if (debug > 2)
report(LOG_INFO, buf);
status = system(buf);
if (status)
report(LOG_ERR, "arp failed, exit code=0x%x", status);
return;
#endif /* ! 4.4 BSD */
#endif /* SIOCSARP */
}
/*
* Convert a hardware address to an ASCII string.
*/
char *
haddrtoa(haddr, hlen)
u_char *haddr;
int hlen;
{
static char haddrbuf[3 * MAXHADDRLEN + 1];
char *bufptr;
if (hlen > MAXHADDRLEN)
hlen = MAXHADDRLEN;
bufptr = haddrbuf;
while (hlen > 0) {
sprintf(bufptr, "%02X:", (unsigned) (*haddr++ & 0xFF));
bufptr += 3;
hlen--;
}
bufptr[-1] = 0;
return (haddrbuf);
}
/*
* haddr_conv802()
* --------------
*
* Converts a backwards address to a canonical address and a canonical address
* to a backwards address.
*
* INPUTS:
* adr_in - pointer to six byte string to convert (unsigned char *)
* addr_len - how many bytes to convert
*
* OUTPUTS:
* addr_out - The string is updated to contain the converted address.
*
* CALLER:
* many
*
* DATA:
* Uses conv802table to bit-reverse the address bytes.
*/
static u_char conv802table[256] =
{
/* 0x00 */ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
/* 0x08 */ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
/* 0x10 */ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
/* 0x18 */ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
/* 0x20 */ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
/* 0x28 */ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
/* 0x30 */ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
/* 0x38 */ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
/* 0x40 */ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
/* 0x48 */ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
/* 0x50 */ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
/* 0x58 */ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
/* 0x60 */ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
/* 0x68 */ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
/* 0x70 */ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
/* 0x78 */ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
/* 0x80 */ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
/* 0x88 */ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
/* 0x90 */ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
/* 0x98 */ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
/* 0xA0 */ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
/* 0xA8 */ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
/* 0xB0 */ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
/* 0xB8 */ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
/* 0xC0 */ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
/* 0xC8 */ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
/* 0xD0 */ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
/* 0xD8 */ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
/* 0xE0 */ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
/* 0xE8 */ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
/* 0xF0 */ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
/* 0xF8 */ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
};
void
haddr_conv802(addr_in, addr_out, len)
register u_char *addr_in, *addr_out;
int len;
{
u_char *lim;
lim = addr_out + len;
while (addr_out < lim)
*addr_out++ = conv802table[*addr_in++];
}
#if 0
/*
* For the record, here is a program to generate the
* bit-reverse table above.
*/
static int
bitrev(n)
int n;
{
int i, r;
r = 0;
for (i = 0; i < 8; i++) {
r <<= 1;
r |= (n & 1);
n >>= 1;
}
return r;
}
main()
{
int i;
for (i = 0; i <= 0xFF; i++) {
if ((i & 7) == 0)
printf("/* 0x%02X */", i);
printf(" 0x%02X,", bitrev(i));
if ((i & 7) == 7)
printf("\n");
}
}
#endif
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

39
libexec/bootpd/hwaddr.h Normal file
View File

@ -0,0 +1,39 @@
/* hwaddr.h */
#ifndef HWADDR_H
#define HWADDR_H
#define MAXHADDRLEN 8 /* Max hw address length in bytes */
/*
* This structure holds information about a specific network type. The
* length of the network hardware address is stored in "hlen".
* The string pointed to by "name" is the cononical name of the network.
*/
struct hwinfo {
unsigned int hlen;
char *name;
};
extern struct hwinfo hwinfolist[];
extern int hwinfocnt;
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
extern void setarp P((int, struct in_addr *, u_char *, int));
extern char *haddrtoa P((u_char *, int));
extern void haddr_conv802 P((u_char *, u_char *, int));
#undef P
/*
* Return the length in bytes of a hardware address of the given type.
* Return the canonical name of the network of the given type.
*/
#define haddrlength(type) ((hwinfolist[(int) (type)]).hlen)
#define netname(type) ((hwinfolist[(int) (type)]).name)
#endif /* HWADDR_H */

126
libexec/bootpd/lookup.c Normal file
View File

@ -0,0 +1,126 @@
/*
* lookup.c - Lookup IP address, HW address, netmask
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#ifdef ETC_ETHERS
#include <netinet/if_ether.h>
extern int ether_hostton();
#endif
#include <netdb.h>
#include <syslog.h>
#ifndef USE_BFUNCS
#include <memory.h>
/* Yes, memcpy is OK here (no overlapped copies). */
#define bcopy(a,b,c) memcpy(b,a,c)
#endif
#include "bootp.h"
#include "lookup.h"
#include "report.h"
/*
* Lookup an Ethernet address and return it.
* Return NULL if addr not found.
*/
u_char *
lookup_hwa(hostname, htype)
char *hostname;
int htype;
{
switch (htype) {
/* XXX - How is this done on other systems? -gwr */
#ifdef ETC_ETHERS
case HTYPE_ETHERNET:
case HTYPE_IEEE802:
{
static struct ether_addr ea;
/* This does a lookup in /etc/ethers */
if (ether_hostton(hostname, &ea)) {
report(LOG_ERR, "no HW addr for host \"%s\"",
hostname);
return (u_char *) 0;
}
return (u_char *) & ea;
}
#endif /* ETC_ETHERS */
default:
report(LOG_ERR, "no lookup for HW addr type %d", htype);
} /* switch */
/* If the system can't do it, just return an error. */
return (u_char *) 0;
}
/*
* Lookup an IP address.
* Return non-zero on failure.
*/
int
lookup_ipa(hostname, result)
char *hostname;
u_int32 *result;
{
struct hostent *hp;
hp = gethostbyname(hostname);
if (!hp)
return -1;
bcopy(hp->h_addr, result, sizeof(*result));
return 0;
}
/*
* Lookup a netmask
* Return non-zero on failure.
*
* XXX - This is OK as a default, but to really make this automatic,
* we would need to get the subnet mask from the ether interface.
* If this is wrong, specify the correct value in the bootptab.
*/
int
lookup_netmask(addr, result)
u_int32 addr; /* both in network order */
u_int32 *result;
{
int32 m, a;
a = ntohl(addr);
m = 0;
if (IN_CLASSA(a))
m = IN_CLASSA_NET;
if (IN_CLASSB(a))
m = IN_CLASSB_NET;
if (IN_CLASSC(a))
m = IN_CLASSC_NET;
if (!m)
return -1;
*result = htonl(m);
return 0;
}
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

15
libexec/bootpd/lookup.h Normal file
View File

@ -0,0 +1,15 @@
/* lookup.h */
#include "bptypes.h" /* for int32, u_int32 */
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
extern u_char *lookup_hwa P((char *hostname, int htype));
extern int lookup_ipa P((char *hostname, u_int32 *addr));
extern int lookup_netmask P((u_int32 addr, u_int32 *mask));
#undef P

View File

@ -0,0 +1,3 @@
/* patchlevel.h */
#define VERSION "2.4"
#define PATCHLEVEL 1

2097
libexec/bootpd/readfile.c Normal file

File diff suppressed because it is too large Load Diff

19
libexec/bootpd/readfile.h Normal file
View File

@ -0,0 +1,19 @@
/* readfile.h */
#include "bptypes.h"
#include "hash.h"
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
extern boolean hwlookcmp P((hash_datum *, hash_datum *));
extern boolean iplookcmp P((hash_datum *, hash_datum *));
extern boolean nmcmp P((hash_datum *, hash_datum *));
extern void readtab P((int));
extern void rdtab_init P((void));
#undef P

154
libexec/bootpd/report.c Normal file
View File

@ -0,0 +1,154 @@
/*
* report() - calls syslog
*/
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <stdio.h>
#include <syslog.h>
#include "report.h"
#ifndef LOG_NDELAY
#define LOG_NDELAY 0
#endif
#ifndef LOG_DAEMON
#define LOG_DAEMON 0
#endif
#ifndef LOG_BOOTP
#define LOG_BOOTP LOG_DAEMON
#endif
extern int debug;
extern char *progname;
/*
* This is initialized so you get stderr until you call
* report_init()
*/
static int stderr_only = 1;
void
report_init(nolog)
int nolog;
{
stderr_only = nolog;
#ifdef SYSLOG
if (!stderr_only) {
openlog(progname, LOG_PID | LOG_NDELAY, LOG_BOOTP);
}
#endif
}
/*
* This routine reports errors and such via stderr and syslog() if
* appopriate. It just helps avoid a lot of "#ifdef SYSLOG" constructs
* from being scattered throughout the code.
*
* The syntax is identical to syslog(3), but %m is not considered special
* for output to stderr (i.e. you'll see "%m" in the output. . .). Also,
* control strings should normally end with \n since newlines aren't
* automatically generated for stderr output (whereas syslog strips out all
* newlines and adds its own at the end).
*/
static char *levelnames[] = {
#ifdef LOG_SALERT
"level(0): ",
"alert(1): ",
"alert(2): ",
"emerg(3): ",
"error(4): ",
"crit(5): ",
"warn(6): ",
"note(7): ",
"info(8): ",
"debug(9): ",
"level(?): "
#else
"emerg(0): ",
"alert(1): ",
"crit(2): ",
"error(3): ",
"warn(4): ",
"note(5): ",
"info(6): ",
"debug(7): ",
"level(?): "
#endif
};
static int numlevels = sizeof(levelnames) / sizeof(levelnames[0]);
/*
* Print a log message using syslog(3) and/or stderr.
* The message passed in should not include a newline.
*/
#ifdef __STDC__
void
report(int priority, char *fmt,...)
#else
/*VARARGS2*/
void
report(priority, fmt, va_alist)
int priority;
char *fmt;
va_dcl
#endif
{
va_list ap;
static char buf[128];
if ((priority < 0) || (priority >= numlevels)) {
priority = numlevels - 1;
}
#ifdef __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
vsprintf(buf, fmt, ap);
va_end(ap);
/*
* Print the message
*/
if (stderr_only || (debug > 2)) {
fprintf(stderr, "%s: %s %s\n",
progname, levelnames[priority], buf);
}
#ifdef SYSLOG
if (!stderr_only)
syslog((priority | LOG_BOOTP), "%s", buf);
#endif
}
/*
* Return pointer to static string which gives full filesystem error message.
*/
char *
get_errmsg()
{
extern int errno;
extern char *strerror();
return strerror(errno);
}
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

13
libexec/bootpd/report.h Normal file
View File

@ -0,0 +1,13 @@
/* report.h */
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
extern void report_init P((int nolog));
extern void report P((int, char *, ...));
extern char *get_errmsg P((void));
#undef P

View File

@ -0,0 +1,63 @@
#
# syslog configuration file for SunOS 4.X
# (modified to do local2 separately)
#
# This file is processed by m4 so be careful to quote (`') names
# that match m4 reserved words. Also, within ifdef's, arguments
# containing commas must be quoted.
#
# Note: Have to exclude user from most lines so that user.alert
# and user.emerg are not included, because old sendmails
# will generate them for debugging information. If you
# have no 4.2BSD based systems doing network logging, you
# can remove all the special cases for "user" logging.
#*.err;kern.debug;auth.notice;user.none /dev/console
kern.debug;user,mail.crit;auth.notice /dev/console
daemon,syslog,lpr,news,uucp,cron.err /dev/console
#*.err;kern.debug;daemon,auth.notice;mail.crit;user.none /var/adm/messages
kern.debug;user,mail.crit;auth.notice /var/adm/messages
daemon.notice;syslog,news,uucp,cron.err /var/adm/messages
lpr.debug /var/adm/lpd-errs
*.alert;kern.err;daemon.err;user.none operator
*.alert;user.none root
*.emerg;user.none *
# for loghost machines, to have authentication messages (su, login, etc.)
# logged to a file, un-comment out the following line and adjust the file name
# as appropriate.
#
# if a non-loghost machine chooses to have such messages
# sent to the loghost machine, un-comment out the following line.
#
#auth.notice ifdef(`LOGHOST', /var/log/authlog, @loghost)
mail.debug ifdef(`LOGHOST', /var/log/syslog, @loghost)
# following line for compatibility with old sendmails. they will send
# messages with no facility code, which will be turned into "user" messages
# by the local syslog daemon. only the "loghost" machine needs the following
# line, to cause these old sendmail log messages to be logged in the
# mail syslog file.
#
ifdef(`LOGHOST',
user.alert /var/log/syslog
)
#
# non-loghost machines will use the following lines to cause "user"
# log messages to be logged locally.
#
ifdef(`LOGHOST', ,
user.err /dev/console
user.err /var/adm/messages
user.alert `root, operator'
user.emerg *
)
# Local2: (bootpd, pppd)
local2.debug /dev/console
#local2.debug /var/log/local2

View File

@ -0,0 +1,52 @@
.\" bootpef.8
.TH BOOTPEF 8 "4 Dec 1993" "MAINTENANCE COMMANDS"
.SH NAME
bootpef \- BOOTP Extension File compiler
.SH SYNOPSIS
.LP
.B bootpef
.RI [ "-c chdir" ]
.RI [ "-d debug-level" ]
.RI [ "-f config-file" ]
.RI [ client-name " [...]]"
.SH DESCRIPTION
.B bootpef
builds the
.I Extension Path
files described by RFC 1497 (tag 18).
If any
.I client-name
arguments are specified, then
.I bootpef
compiles the extension files for only those clients.
.SH OPTIONS
.TP
.BI \-c \ chdir\-path
Sets the current directory used by
.I bootpef
while creating extension files. This is useful when the
extension file names are specified as relative pathnames, and
.I bootpef
needs to use the same current directory as the TFTP server
(typically /tftpboot).
.TP
.BI \-d \ debug\-level
Sets the
.I debug\-level
variable that controls the amount of debugging messages generated.
For example, -d4 or -d 4 will set the debugging level to 4.
.TP
.BI \-f \ config\-file
Set the name of the config file that specifies the option
data to be sent to each client.
.SH "SEE ALSO"
bootpd(8), tftpd(8)
.SH REFERENCES
.TP
RFC951
BOOTSTRAP PROTOCOL (BOOTP)
.TP
RFC1497
BOOTP Vendor Information Extensions

View File

@ -0,0 +1,347 @@
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of Carnegie Mellon University not be used
in advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
#ifndef lint
static char rcsid[] = "$Id: bootpef.c,v 1.1.1.1 1994/09/10 14:44:54 csgr Exp $";
#endif
/*
* bootpef - BOOTP Extension File generator
* Makes an "Extension File" for each host entry that
* defines an and Extension File. (See RFC1497, tag 18.)
*
* HISTORY
* See ./Changes
*
* BUGS
* See ./ToDo
*/
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h> /* inet_ntoa */
#ifndef NO_UNISTD
#include <unistd.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <syslog.h>
#ifndef USE_BFUNCS
#include <memory.h>
/* Yes, memcpy is OK here (no overlapped copies). */
#define bcopy(a,b,c) memcpy(b,a,c)
#define bzero(p,l) memset(p,0,l)
#define bcmp(a,b,c) memcmp(a,b,c)
#endif
#include "bootp.h"
#include "hash.h"
#include "hwaddr.h"
#include "bootpd.h"
#include "dovend.h"
#include "readfile.h"
#include "report.h"
#include "tzone.h"
#include "patchlevel.h"
#define BUFFERSIZE 0x4000
#ifndef CONFIG_FILE
#define CONFIG_FILE "/etc/bootptab"
#endif
/*
* Externals, forward declarations, and global variables
*/
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
static void dovend_rfc1048 P((struct bootp *, struct host *, int32));
static void mktagfile P((struct host *));
static void usage P((void));
#undef P
/*
* General
*/
char *progname;
char *chdir_path;
int debug = 0; /* Debugging flag (level) */
byte *buffer;
/*
* Globals below are associated with the bootp database file (bootptab).
*/
char *bootptab = CONFIG_FILE;
/*
* Print "usage" message and exit
*/
static void
usage()
{
fprintf(stderr,
"usage: $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
fprintf(stderr, "\t -c n\tset current directory\n");
fprintf(stderr, "\t -d n\tset debug level\n");
fprintf(stderr, "\t -f n\tconfig file name\n");
exit(1);
}
/*
* Initialization such as command-line processing is done and then the
* main server loop is started.
*/
void
main(argc, argv)
int argc;
char **argv;
{
struct host *hp;
char *stmp;
int n;
progname = strrchr(argv[0], '/');
if (progname) progname++;
else progname = argv[0];
/* Get work space for making tag 18 files. */
buffer = (byte *) malloc(BUFFERSIZE);
if (!buffer) {
report(LOG_ERR, "malloc failed");
exit(1);
}
/*
* Set defaults that might be changed by option switches.
*/
stmp = NULL;
/*
* Read switches.
*/
for (argc--, argv++; argc > 0; argc--, argv++) {
if (argv[0][0] != '-')
break;
switch (argv[0][1]) {
case 'c': /* chdir_path */
if (argv[0][2]) {
stmp = &(argv[0][2]);
} else {
argc--;
argv++;
stmp = argv[0];
}
if (!stmp || (stmp[0] != '/')) {
fprintf(stderr,
"bootpd: invalid chdir specification\n");
break;
}
chdir_path = stmp;
break;
case 'd': /* debug */
if (argv[0][2]) {
stmp = &(argv[0][2]);
} else if (argv[1] && argv[1][0] == '-') {
/*
* Backwards-compatible behavior:
* no parameter, so just increment the debug flag.
*/
debug++;
break;
} else {
argc--;
argv++;
stmp = argv[0];
}
if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
fprintf(stderr,
"bootpd: invalid debug level\n");
break;
}
debug = n;
break;
case 'f': /* config file */
if (argv[0][2]) {
stmp = &(argv[0][2]);
} else {
argc--;
argv++;
stmp = argv[0];
}
bootptab = stmp;
break;
default:
fprintf(stderr, "bootpd: unknown switch: -%c\n",
argv[0][1]);
usage();
break;
}
}
/* Get the timezone. */
tzone_init();
/* Allocate hash tables. */
rdtab_init();
/*
* Read the bootptab file.
*/
readtab(1); /* force read */
/* Set the cwd (i.e. to /tftpboot) */
if (chdir_path) {
if (chdir(chdir_path) < 0)
report(LOG_ERR, "%s: chdir failed", chdir_path);
}
/* If there are host names on the command line, do only those. */
if (argc > 0) {
unsigned int tlen, hashcode;
while (argc) {
tlen = strlen(argv[0]);
hashcode = hash_HashFunction((u_char *)argv[0], tlen);
hp = (struct host *) hash_Lookup(nmhashtable,
hashcode,
nmcmp, argv[0]);
if (!hp) {
printf("%s: no matching entry\n", argv[0]);
exit(1);
}
if (!hp->flags.exten_file) {
printf("%s: no extension file\n", argv[0]);
exit(1);
}
mktagfile(hp);
argv++;
argc--;
}
exit(0);
}
/* No host names specified. Do them all. */
hp = (struct host *) hash_FirstEntry(nmhashtable);
while (hp != NULL) {
mktagfile(hp);
hp = (struct host *) hash_NextEntry(nmhashtable);
}
}
/*
* Make a "TAG 18" file for this host.
* (Insert the RFC1497 options.)
*/
static void
mktagfile(hp)
struct host *hp;
{
FILE *fp;
int bytesleft, len;
byte *vp;
char *tmpstr;
if (!hp->flags.exten_file)
return;
vp = buffer;
bytesleft = BUFFERSIZE;
bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
vp += 4;
bytesleft -= 4;
/*
* The "extension file" options are appended by the following
* function (which is shared with bootpd.c).
*/
len = dovend_rfc1497(hp, vp, bytesleft);
vp += len;
bytesleft -= len;
if (bytesleft < 1) {
report(LOG_ERR, "%s: too much option data",
hp->exten_file->string);
return;
}
*vp++ = TAG_END;
bytesleft--;
/* Write the buffer to the extension file. */
printf("Updating \"%s\"\n", hp->exten_file->string);
if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
report(LOG_ERR, "error opening \"%s\": %s",
hp->exten_file->string, get_errmsg());
return;
}
len = vp - buffer;
if (len != fwrite(buffer, 1, len, fp)) {
report(LOG_ERR, "write failed on \"%s\" : %s",
hp->exten_file->string, get_errmsg());
}
fclose(fp);
} /* dovend_rfc1048 */
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

View File

@ -0,0 +1,74 @@
.\" bootptest.8
.TH BOOTPTEST 8 "10 June 1993" "MAINTENANCE COMMANDS"
.SH NAME
bootptest \- send BOOTP queries and print responses
.SH SYNOPSIS
.LP
.B bootptest
[
.B \-f
.I bootfile
]
[
.B \-h
]
[
.B \-m
.I magic_number
]
.I server\-name
.RI [ template-file ]
.SH DESCRIPTION
.B bootptest
sends BOOTP requests to the host specified as
.I server\-name
at one\-second intervals until either a response is received,
or until ten requests have gone unanswered.
After a response is received,
.B bootptest
will wait one more second listening for additional responses.
.SH OPTIONS
.TP
.B \-f
.I bootfile
Fill in the boot file field of the request with
.IR bootfile .
.TP
.B \-h
Use the hardware (Ethernet) address to identify the client.
By default, the IP address is copied into the request
indicating that this client already knows its IP address.
.TP
.B \-m
.I magic_number
Initialize the first word of the vendor options field with
.IR magic_number .
.LP
A
.I template-file
may be specified, in which case
.B bootptest
uses the (binary) contents of this file to initialize the
.I options
area of the request packet.
.SH CREDITS
.LP
The bootptest program is a combination of original and derived works.
The main program module (bootptest.c) is original work by
Gordon W. Ross <gwr@mc.com>.
The packet printing module (print-bootp.c) is a slightly modified
version of a file from the BSD tcpdump program.
.LP
This program includes software developed by the University of
California, Lawrence Berkeley Laboratory and its contributors.
(See the copyright notice in print-bootp.c)
.SH "SEE ALSO"
.LP
bootpd(8)
.SH REFERENCES
.TP
RFC951
BOOTSTRAP PROTOCOL (BOOTP)
.TP
RFC1048
BOOTP Vendor Information Extensions

View File

@ -0,0 +1,500 @@
/*
* bootptest.c - Test out a bootp server.
*
* This simple program was put together from pieces taken from
* various places, including the CMU BOOTP client and server.
* The packet printing routine is from the Berkeley "tcpdump"
* program with some enhancements I added. The print-bootp.c
* file was shared with my copy of "tcpdump" and therefore uses
* some unusual utility routines that would normally be provided
* by various parts of the tcpdump program. Gordon W. Ross
*
* Boilerplate:
*
* This program includes software developed by the University of
* California, Lawrence Berkeley Laboratory and its contributors.
* (See the copyright notice in print-bootp.c)
*
* The remainder of this program is public domain. You may do
* whatever you like with it except claim that you wrote it.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* HISTORY:
*
* 12/02/93 Released version 1.4 (with bootp-2.3.2)
* 11/05/93 Released version 1.3
* 10/14/93 Released version 1.2
* 10/11/93 Released version 1.1
* 09/28/93 Released version 1.0
* 09/93 Original developed by Gordon W. Ross <gwr@mc.com>
*/
char *usage = "bootptest [-h] server-name [vendor-data-template-file]";
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h> /* inet_ntoa */
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <netdb.h>
#include <assert.h>
#include "bootp.h"
#include "bootptest.h"
#include "getif.h"
#include "patchlevel.h"
#define LOG_ERR 1
#define BUFLEN 1024
#define WAITSECS 1
#define MAXWAIT 10
int vflag = 1;
int tflag = 0;
int thiszone;
char *progname;
unsigned char *packetp;
unsigned char *snapend;
int snaplen;
/*
* IP port numbers for client and server obtained from /etc/services
*/
u_short bootps_port, bootpc_port;
/*
* Internet socket and interface config structures
*/
struct sockaddr_in sin_server; /* where to send requests */
struct sockaddr_in sin_client; /* for bind and listen */
struct sockaddr_in sin_from; /* Packet source */
u_char eaddr[16]; /* Ethernet address */
/*
* General
*/
int debug = 1; /* Debugging flag (level) */
char hostname[64];
char *sndbuf; /* Send packet buffer */
char *rcvbuf; /* Receive packet buffer */
/*
* Vendor magic cookies for CMU and RFC1048
*/
unsigned char vm_cmu[4] = VM_CMU;
unsigned char vm_rfc1048[4] = VM_RFC1048;
short secs; /* How long client has waited */
char *get_errmsg();
extern void bootp_print();
/*
* Initialization such as command-line processing is done, then
* the receiver loop is started. Die when interrupted.
*/
main(argc, argv)
int argc;
char **argv;
{
struct bootp *bp;
struct servent *sep;
struct hostent *hep;
char *servername = NULL;
char *vendor_file = NULL;
char *bp_file = NULL;
int32 server_addr; /* inet addr, network order */
int s; /* Socket file descriptor */
int n, tolen, fromlen, recvcnt;
int use_hwa = 0;
int32 vend_magic;
int32 xid;
progname = strrchr(argv[0], '/');
if (progname)
progname++;
else
progname = argv[0];
argc--;
argv++;
if (debug)
printf("%s: version %s.%d\n", progname, VERSION, PATCHLEVEL);
/*
* Verify that "struct bootp" has the correct official size.
* (Catch evil compilers that do struct padding.)
*/
assert(sizeof(struct bootp) == BP_MINPKTSZ);
sndbuf = malloc(BUFLEN);
rcvbuf = malloc(BUFLEN);
if (!sndbuf || !rcvbuf) {
printf("malloc failed\n");
exit(1);
}
/* default magic number */
bcopy(vm_rfc1048, (char*)&vend_magic, 4);
/* Handle option switches. */
while (argc > 0) {
if (argv[0][0] != '-')
break;
switch (argv[0][1]) {
case 'f': /* File name to reqest. */
if (argc < 2)
goto error;
argc--; argv++;
bp_file = *argv;
break;
case 'h': /* Use hardware address. */
use_hwa = 1;
break;
case 'm': /* Magic number value. */
if (argc < 2)
goto error;
argc--; argv++;
vend_magic = inet_addr(*argv);
break;
error:
default:
puts(usage);
exit(1);
}
argc--;
argv++;
}
/* Get server name (or address) for query. */
if (argc > 0) {
servername = *argv;
argc--;
argv++;
}
/* Get optional vendor-data-template-file. */
if (argc > 0) {
vendor_file = *argv;
argc--;
argv++;
}
if (!servername) {
printf("missing server name.\n");
puts(usage);
exit(1);
}
/*
* Create a socket.
*/
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(1);
}
/*
* Get server's listening port number
*/
sep = getservbyname("bootps", "udp");
if (sep) {
bootps_port = ntohs((u_short) sep->s_port);
} else {
fprintf(stderr, "udp/bootps: unknown service -- using port %d\n",
IPPORT_BOOTPS);
bootps_port = (u_short) IPPORT_BOOTPS;
}
/*
* Set up server socket address (for send)
*/
if (servername) {
if (isdigit(servername[0]))
server_addr = inet_addr(servername);
else {
hep = gethostbyname(servername);
if (!hep) {
fprintf(stderr, "%s: unknown host\n", servername);
exit(1);
}
bcopy(hep->h_addr, &server_addr, sizeof(server_addr));
}
} else {
/* Get broadcast address */
/* XXX - not yet */
server_addr = INADDR_ANY;
}
sin_server.sin_family = AF_INET;
sin_server.sin_port = htons(bootps_port);
sin_server.sin_addr.s_addr = server_addr;
/*
* Get client's listening port number
*/
sep = getservbyname("bootpc", "udp");
if (sep) {
bootpc_port = ntohs(sep->s_port);
} else {
fprintf(stderr, "udp/bootpc: unknown service -- using port %d\n",
IPPORT_BOOTPC);
bootpc_port = (u_short) IPPORT_BOOTPC;
}
/*
* Set up client socket address (for listen)
*/
sin_client.sin_family = AF_INET;
sin_client.sin_port = htons(bootpc_port);
sin_client.sin_addr.s_addr = INADDR_ANY;
/*
* Bind client socket to BOOTPC port.
*/
if (bind(s, (struct sockaddr *) &sin_client, sizeof(sin_client)) < 0) {
perror("bind BOOTPC port");
if (errno == EACCES)
fprintf(stderr, "You need to run this as root\n");
exit(1);
}
/*
* Build a request.
*/
bp = (struct bootp *) sndbuf;
bzero(bp, sizeof(*bp));
bp->bp_op = BOOTREQUEST;
xid = (int32) getpid();
bp->bp_xid = (u_int32) htonl(xid);
if (bp_file)
strncpy(bp->bp_file, bp_file, BP_FILE_LEN);
/*
* Fill in the hardware address (or client IP address)
*/
if (use_hwa) {
struct ifreq *ifr;
ifr = getif(s, &sin_server.sin_addr);
if (!ifr) {
printf("No interface for %s\n", servername);
exit(1);
}
if (getether(ifr->ifr_name, eaddr)) {
printf("Can not get ether addr for %s\n", ifr->ifr_name);
exit(1);
}
/* Copy Ethernet address into request packet. */
bp->bp_htype = 1;
bp->bp_hlen = 6;
bcopy(eaddr, bp->bp_chaddr, bp->bp_hlen);
} else {
/* Fill in the client IP address. */
gethostname(hostname, sizeof(hostname));
hep = gethostbyname(hostname);
if (!hep) {
printf("Can not get my IP address\n");
exit(1);
}
bcopy(hep->h_addr, &bp->bp_ciaddr, hep->h_length);
}
/*
* Copy in the default vendor data.
*/
bcopy((char*)&vend_magic, bp->bp_vend, 4);
if (vend_magic)
bp->bp_vend[4] = TAG_END;
/*
* Read in the "options" part of the request.
* This also determines the size of the packet.
*/
snaplen = sizeof(*bp);
if (vendor_file) {
int fd = open(vendor_file, 0);
if (fd < 0) {
perror(vendor_file);
exit(1);
}
/* Compute actual space for options. */
n = BUFLEN - sizeof(*bp) + BP_VEND_LEN;
n = read(fd, bp->bp_vend, n);
close(fd);
if (n < 0) {
perror(vendor_file);
exit(1);
}
printf("read %d bytes of vendor template\n", n);
if (n > BP_VEND_LEN) {
printf("warning: extended options in use (len > %d)\n",
BP_VEND_LEN);
snaplen += (n - BP_VEND_LEN);
}
}
/*
* Set globals needed by print_bootp
* (called by send_request)
*/
packetp = (unsigned char *) eaddr;
snapend = (unsigned char *) sndbuf + snaplen;
/* Send a request once per second while waiting for replies. */
recvcnt = 0;
bp->bp_secs = secs = 0;
send_request(s);
while (1) {
struct timeval tv;
int readfds;
tv.tv_sec = WAITSECS;
tv.tv_usec = 0L;
readfds = (1 << s);
n = select(s + 1, (fd_set *) & readfds, NULL, NULL, &tv);
if (n < 0) {
perror("select");
break;
}
if (n == 0) {
/*
* We have not received a response in the last second.
* If we have ever received any responses, exit now.
* Otherwise, bump the "wait time" field and re-send.
*/
if (recvcnt > 0)
exit(0);
secs += WAITSECS;
if (secs > MAXWAIT)
break;
bp->bp_secs = htons(secs);
send_request(s);
continue;
}
fromlen = sizeof(sin_from);
n = recvfrom(s, rcvbuf, BUFLEN, 0,
(struct sockaddr *) &sin_from, &fromlen);
if (n <= 0) {
continue;
}
if (n < sizeof(struct bootp)) {
printf("received short packet\n");
continue;
}
recvcnt++;
/* Print the received packet. */
printf("Recvd from %s", inet_ntoa(sin_from.sin_addr));
/* set globals needed by bootp_print() */
snaplen = n;
snapend = (unsigned char *) rcvbuf + snaplen;
bootp_print(rcvbuf, n, sin_from.sin_port, 0);
putchar('\n');
/*
* This no longer exits immediately after receiving
* one response because it is useful to know if the
* client might get multiple responses. This code
* will now listen for one second after a response.
*/
}
fprintf(stderr, "no response from %s\n", servername);
exit(1);
}
send_request(s)
int s;
{
/* Print the request packet. */
printf("Sending to %s", inet_ntoa(sin_server.sin_addr));
bootp_print(sndbuf, snaplen, sin_from.sin_port, 0);
putchar('\n');
/* Send the request packet. */
if (sendto(s, sndbuf, snaplen, 0,
(struct sockaddr *) &sin_server,
sizeof(sin_server)) < 0)
{
perror("sendto server");
exit(1);
}
}
/*
* Print out a filename (or other ascii string).
* Return true if truncated.
*/
int
printfn(s, ep)
register u_char *s, *ep;
{
register u_char c;
putchar('"');
while (c = *s++) {
if (s > ep) {
putchar('"');
return (1);
}
if (!isascii(c)) {
c = toascii(c);
putchar('M');
putchar('-');
}
if (!isprint(c)) {
c ^= 0x40; /* DEL to ?, others to alpha */
putchar('^');
}
putchar(c);
}
putchar('"');
return (0);
}
/*
* Convert an IP addr to a string.
* (like inet_ntoa, but ina is a pointer)
*/
char *
ipaddr_string(ina)
struct in_addr *ina;
{
static char b[24];
u_char *p;
p = (u_char *) ina;
sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return (b);
}
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

View File

@ -0,0 +1,30 @@
/* bootptest.h */
/*
* Hacks for sharing print-bootp.c between tcpdump and bootptest.
*/
#define ESRC(p) (p)
#define EDST(p) (p)
#ifndef USE_BFUNCS
/* Use mem/str functions */
/* There are no overlapped copies, so memcpy is OK. */
#define bcopy(a,b,c) memcpy(b,a,c)
#define bzero(p,l) memset(p,0,l)
#define bcmp(a,b,c) memcmp(a,b,c)
#endif
extern int vflag; /* verbose flag */
/* global pointers to beginning and end of current packet (during printing) */
extern unsigned char *packetp;
extern unsigned char *snapend;
#ifdef __STDC__
#define P(args) args
#else
#define P(args) ()
#endif
extern char *ipaddr_string P((struct in_addr *));
#undef P

View File

@ -0,0 +1,493 @@
/*
* Copyright (c) 1988-1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Format and print bootp packets.
*
* This file was copied from tcpdump-2.1.1 and modified.
* There is an e-mail list for tcpdump: <tcpdump@ee.lbl.gov>
*/
#ifndef lint
static char rcsid[] = "$Id: print-bootp.c,v 1.1.1.1 1994/09/10 14:44:55 csgr Exp $";
/* 93/10/10 <gwr@mc.com> New data-driven option print routine. */
#endif
#include <stdio.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <string.h>
#include <ctype.h>
#include "bootp.h"
#include "bootptest.h"
/* These decode the vendor data. */
static void rfc1048_print();
static void cmu_print();
static void other_print();
static void dump_hex();
/*
* Print bootp requests
*/
void
bootp_print(bp, length, sport, dport)
struct bootp *bp;
int length;
u_short sport, dport;
{
static char tstr[] = " [|bootp]";
static unsigned char vm_cmu[4] = VM_CMU;
static unsigned char vm_rfc1048[4] = VM_RFC1048;
u_char *ep;
int vdlen;
#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
/* Note funny sized packets */
if (length != sizeof(struct bootp))
(void) printf(" [len=%d]", length);
/* 'ep' points to the end of avaible data. */
ep = (u_char *) snapend;
switch (bp->bp_op) {
case BOOTREQUEST:
/* Usually, a request goes from a client to a server */
if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS)
printf(" (request)");
break;
case BOOTREPLY:
/* Usually, a reply goes from a server to a client */
if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC)
printf(" (reply)");
break;
default:
printf(" bootp-#%d", bp->bp_op);
}
/* The usual hardware address type is 1 (10Mb Ethernet) */
if (bp->bp_htype != 1)
printf(" htype:%d", bp->bp_htype);
/* The usual length for 10Mb Ethernet address is 6 bytes */
if (bp->bp_hlen != 6)
printf(" hlen:%d", bp->bp_hlen);
/* Client's Hardware address */
if (bp->bp_hlen) {
register struct ether_header *eh;
register char *e;
TCHECK(bp->bp_chaddr[0], 6);
eh = (struct ether_header *) packetp;
if (bp->bp_op == BOOTREQUEST)
e = (char *) ESRC(eh);
else if (bp->bp_op == BOOTREPLY)
e = (char *) EDST(eh);
else
e = 0;
if (e == 0 || bcmp((char *) bp->bp_chaddr, e, 6))
dump_hex(bp->bp_chaddr, bp->bp_hlen);
}
/* Only print interesting fields */
if (bp->bp_hops)
printf(" hops:%d", bp->bp_hops);
if (bp->bp_xid)
printf(" xid:%d", ntohl(bp->bp_xid));
if (bp->bp_secs)
printf(" secs:%d", ntohs(bp->bp_secs));
/* Client's ip address */
TCHECK(bp->bp_ciaddr, sizeof(bp->bp_ciaddr));
if (bp->bp_ciaddr.s_addr)
printf(" C:%s", ipaddr_string(&bp->bp_ciaddr));
/* 'your' ip address (bootp client) */
TCHECK(bp->bp_yiaddr, sizeof(bp->bp_yiaddr));
if (bp->bp_yiaddr.s_addr)
printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr));
/* Server's ip address */
TCHECK(bp->bp_siaddr, sizeof(bp->bp_siaddr));
if (bp->bp_siaddr.s_addr)
printf(" S:%s", ipaddr_string(&bp->bp_siaddr));
/* Gateway's ip address */
TCHECK(bp->bp_giaddr, sizeof(bp->bp_giaddr));
if (bp->bp_giaddr.s_addr)
printf(" G:%s", ipaddr_string(&bp->bp_giaddr));
TCHECK(bp->bp_sname[0], sizeof(bp->bp_sname));
if (*bp->bp_sname) {
printf(" sname:");
if (printfn(bp->bp_sname, ep)) {
fputs(tstr + 1, stdout);
return;
}
}
TCHECK(bp->bp_file[0], sizeof(bp->bp_file));
if (*bp->bp_file) {
printf(" file:");
if (printfn(bp->bp_file, ep)) {
fputs(tstr + 1, stdout);
return;
}
}
/* Don't try to decode the vendor buffer unless we're verbose */
if (vflag <= 0)
return;
vdlen = sizeof(bp->bp_vend);
/* Vendor data can extend to the end of the packet. */
if (vdlen < (ep - bp->bp_vend))
vdlen = (ep - bp->bp_vend);
TCHECK(bp->bp_vend[0], vdlen);
printf(" vend");
if (!bcmp(bp->bp_vend, vm_rfc1048, sizeof(u_int32)))
rfc1048_print(bp->bp_vend, vdlen);
else if (!bcmp(bp->bp_vend, vm_cmu, sizeof(u_int32)))
cmu_print(bp->bp_vend, vdlen);
else
other_print(bp->bp_vend, vdlen);
return;
trunc:
fputs(tstr, stdout);
#undef TCHECK
}
/*
* Option description data follows.
* These are decribed in: RFC-1048, RFC-1395, RFC-1497, RFC-1533
*
* The first char of each option string encodes the data format:
* ?: unknown
* a: ASCII
* b: byte (8-bit)
* i: inet address
* l: int32
* s: short (16-bit)
*/
char *
rfc1048_opts[] = {
/* Originally from RFC-1048: */
"?PAD", /* 0: Padding - special, no data. */
"iSM", /* 1: subnet mask (RFC950)*/
"lTZ", /* 2: time offset, seconds from UTC */
"iGW", /* 3: gateways (or routers) */
"iTS", /* 4: time servers (RFC868) */
"iINS", /* 5: IEN name servers (IEN116) */
"iDNS", /* 6: domain name servers (RFC1035)(1034?) */
"iLOG", /* 7: MIT log servers */
"iCS", /* 8: cookie servers (RFC865) */
"iLPR", /* 9: lpr server (RFC1179) */
"iIPS", /* 10: impress servers (Imagen) */
"iRLP", /* 11: resource location servers (RFC887) */
"aHN", /* 12: host name (ASCII) */
"sBFS", /* 13: boot file size (in 512 byte blocks) */
/* Added by RFC-1395: */
"aDUMP", /* 14: Merit Dump File */
"aDNAM", /* 15: Domain Name (for DNS) */
"iSWAP", /* 16: Swap Server */
"aROOT", /* 17: Root Path */
/* Added by RFC-1497: */
"aEXTF", /* 18: Extensions Path (more options) */
/* Added by RFC-1533: (many, many options...) */
#if 1 /* These might not be worth recognizing by name. */
/* IP Layer Parameters, per-host (RFC-1533, sect. 4) */
"bIP-forward", /* 19: IP Forwarding flag */
"bIP-srcroute", /* 20: IP Source Routing Enable flag */
"iIP-filters", /* 21: IP Policy Filter (addr pairs) */
"sIP-maxudp", /* 22: IP Max-UDP reassembly size */
"bIP-ttlive", /* 23: IP Time to Live */
"lIP-pmtuage", /* 24: IP Path MTU aging timeout */
"sIP-pmtutab", /* 25: IP Path MTU plateau table */
/* IP parameters, per-interface (RFC-1533, sect. 5) */
"sIP-mtu-sz", /* 26: IP MTU size */
"bIP-mtu-sl", /* 27: IP MTU all subnets local */
"bIP-bcast1", /* 28: IP Broadcast Addr ones flag */
"bIP-mask-d", /* 29: IP do mask discovery */
"bIP-mask-s", /* 30: IP do mask supplier */
"bIP-rt-dsc", /* 31: IP do router discovery */
"iIP-rt-sa", /* 32: IP router solicitation addr */
"iIP-routes", /* 33: IP static routes (dst,router) */
/* Link Layer parameters, per-interface (RFC-1533, sect. 6) */
"bLL-trailer", /* 34: do tralier encapsulation */
"lLL-arp-tmo", /* 35: ARP cache timeout */
"bLL-ether2", /* 36: Ethernet version 2 (IEEE 802.3) */
/* TCP parameters (RFC-1533, sect. 7) */
"bTCP-def-ttl", /* 37: default time to live */
"lTCP-KA-tmo", /* 38: keepalive time interval */
"bTCP-KA-junk", /* 39: keepalive sends extra junk */
/* Application and Service Parameters (RFC-1533, sect. 8) */
"aNISDOM", /* 40: NIS Domain (Sun YP) */
"iNISSRV", /* 41: NIS Servers */
"iNTPSRV", /* 42: NTP (time) Servers (RFC 1129) */
"?VSINFO", /* 43: Vendor Specific Info (encapsulated) */
"iNBiosNS", /* 44: NetBIOS Name Server (RFC-1001,1..2) */
"iNBiosDD", /* 45: NetBIOS Datagram Dist. Server. */
"bNBiosNT", /* 46: NetBIOS Note Type */
"?NBiosS", /* 47: NetBIOS Scope */
"iXW-FS", /* 48: X Window System Font Servers */
"iXW-DM", /* 49: X Window System Display Managers */
/* DHCP extensions (RFC-1533, sect. 9) */
#endif
};
#define KNOWN_OPTIONS (sizeof(rfc1048_opts) / sizeof(rfc1048_opts[0]))
static void print_string();
static void
rfc1048_print(bp, length)
register u_char *bp;
int length;
{
u_char tag;
u_char *ep;
register int len, j;
u_int32 ul;
u_short us;
struct in_addr ia;
char *optstr;
printf("-rfc1395");
/* Step over magic cookie */
bp += sizeof(int32);
/* Setup end pointer */
ep = bp + length;
while (bp < ep) {
tag = *bp++;
/* Check for tags with no data first. */
if (tag == TAG_PAD)
continue;
if (tag == TAG_END)
return;
if (tag < KNOWN_OPTIONS) {
optstr = rfc1048_opts[tag];
printf(" %s:", optstr + 1);
} else {
printf(" T%d:", tag);
optstr = "?";
}
/* Now scan the length byte. */
len = *bp++;
if (bp + len > ep) {
/* truncated option */
printf(" |(%d>%d)", len, ep - bp);
return;
}
/* Print the option value(s). */
switch (optstr[0]) {
case 'a': /* ASCII string */
printfn(bp, bp + len);
bp += len;
len = 0;
break;
case 's': /* Word formats */
while (len >= 2) {
bcopy((char *) bp, (char *) &us, 2);
printf("%d", ntohs(us));
bp += 2;
len -= 2;
if (len) printf(",");
}
if (len) printf("(junk=%d)", len);
break;
case 'l': /* Long words */
while (len >= 4) {
bcopy((char *) bp, (char *) &ul, 4);
printf("%d", ntohl(ul));
bp += 4;
len -= 4;
if (len) printf(",");
}
if (len) printf("(junk=%d)", len);
break;
case 'i': /* INET addresses */
while (len >= 4) {
bcopy((char *) bp, (char *) &ia, 4);
printf("%s", ipaddr_string(&ia));
bp += 4;
len -= 4;
if (len) printf(",");
}
if (len) printf("(junk=%d)", len);
break;
case 'b':
default:
break;
} /* switch */
/* Print as characters, if appropriate. */
if (len) {
dump_hex(bp, len);
if (isascii(*bp) && isprint(*bp)) {
printf("(");
printfn(bp, bp + len);
printf(")");
}
bp += len;
len = 0;
}
} /* while bp < ep */
}
static void
cmu_print(bp, length)
register u_char *bp;
int length;
{
struct cmu_vend *v;
u_char *ep;
printf("-cmu");
v = (struct cmu_vend *) bp;
if (length < sizeof(*v)) {
printf(" |L=%d", length);
return;
}
/* Setup end pointer */
ep = bp + length;
/* Subnet mask */
if (v->v_flags & VF_SMASK) {
printf(" SM:%s", ipaddr_string(&v->v_smask));
}
/* Default gateway */
if (v->v_dgate.s_addr)
printf(" GW:%s", ipaddr_string(&v->v_dgate));
/* Domain name servers */
if (v->v_dns1.s_addr)
printf(" DNS1:%s", ipaddr_string(&v->v_dns1));
if (v->v_dns2.s_addr)
printf(" DNS2:%s", ipaddr_string(&v->v_dns2));
/* IEN-116 name servers */
if (v->v_ins1.s_addr)
printf(" INS1:%s", ipaddr_string(&v->v_ins1));
if (v->v_ins2.s_addr)
printf(" INS2:%s", ipaddr_string(&v->v_ins2));
/* Time servers */
if (v->v_ts1.s_addr)
printf(" TS1:%s", ipaddr_string(&v->v_ts1));
if (v->v_ts2.s_addr)
printf(" TS2:%s", ipaddr_string(&v->v_ts2));
}
/*
* Print out arbitrary, unknown vendor data.
*/
static void
other_print(bp, length)
register u_char *bp;
int length;
{
u_char *ep; /* end pointer */
u_char *zp; /* points one past last non-zero byte */
register int i, j;
/* Setup end pointer */
ep = bp + length;
/* Find the last non-zero byte. */
for (zp = ep; zp > bp; zp--) {
if (zp[-1] != 0)
break;
}
/* Print the all-zero case in a compact representation. */
if (zp == bp) {
printf("-all-zero");
return;
}
printf("-unknown");
/* Are there enough trailing zeros to make "00..." worthwhile? */
if (zp + 2 > ep)
zp = ep; /* print them all normally */
/* Now just print all the non-zero data. */
while (bp < zp) {
printf(".%02X", *bp);
bp++;
}
if (zp < ep)
printf(".00...");
return;
}
static void
dump_hex(bp, len)
u_char *bp;
int len;
{
while (len > 0) {
printf("%02X", *bp);
bp++;
len--;
if (len) printf(".");
}
}
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/

46
libexec/bootpd/trygetea.c Normal file
View File

@ -0,0 +1,46 @@
/*
* trygetea.c - test program for getether.c
*/
#include <sys/types.h>
#include <sys/socket.h>
#if defined(SUNOS) || defined(SVR4)
#include <sys/sockio.h>
#endif
#include <net/if.h> /* for struct ifreq */
#include <netinet/in.h>
#include <arpa/inet.h> /* inet_ntoa */
#include <netdb.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
int debug = 0;
char *progname;
main(argc, argv)
char **argv;
{
u_char ea[16]; /* Ethernet address */
int i;
progname = argv[0]; /* for report */
if (argc < 2) {
printf("need interface name\n");
exit(1);
}
if ((i = getether(argv[1], ea)) < 0) {
printf("Could not get Ethernet address (rc=%d)\n", i);
exit(1);
}
printf("Ether-addr");
for (i = 0; i < 6; i++)
printf(":%x", ea[i] & 0xFF);
printf("\n");
exit(0);
}

68
libexec/bootpd/trygetif.c Normal file
View File

@ -0,0 +1,68 @@
/*
* trygetif.c - test program for getif.c
*/
#include <sys/types.h>
#include <sys/socket.h>
#if defined(SUNOS) || defined(SVR4)
#include <sys/sockio.h>
#endif
#include <net/if.h> /* for struct ifreq */
#include <netinet/in.h>
#include <arpa/inet.h> /* inet_ntoa */
#include <netdb.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "getif.h"
int debug = 0;
char *progname;
main(argc, argv)
char **argv;
{
struct hostent *hep;
struct sockaddr ea; /* Ethernet address */
struct sockaddr_in *sip; /* Interface address */
struct ifreq *ifr;
struct in_addr dst_addr;
struct in_addr *dap;
int i, s;
progname = argv[0]; /* for report */
dap = NULL;
if (argc > 1) {
dap = &dst_addr;
if (isdigit(argv[1][0]))
dst_addr.s_addr = inet_addr(argv[1]);
else {
hep = gethostbyname(argv[1]);
if (!hep) {
printf("gethostbyname(%s)\n", argv[1]);
exit(1);
}
memcpy(&dst_addr, hep->h_addr, sizeof(dst_addr));
}
}
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket open");
exit(1);
}
ifr = getif(s, dap);
if (!ifr) {
printf("no interface for address\n");
exit(1);
}
printf("Intf-name:%s\n", ifr->ifr_name);
sip = (struct sockaddr_in *) &(ifr->ifr_addr);
printf("Intf-addr:%s\n", inet_ntoa(sip->sin_addr));
exit(0);
}

50
libexec/bootpd/trylook.c Normal file
View File

@ -0,0 +1,50 @@
/*
* trylook.c - test program for lookup.c
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include "report.h"
#include "lookup.h"
extern char *ether_ntoa();
extern char *inet_ntoa();
int debug = 0;
char *progname;
main(argc, argv)
char **argv;
{
int i;
struct in_addr in;
char *a;
u_char *hwa;
progname = argv[0]; /* for report */
for (i = 1; i < argc; i++) {
/* Host name */
printf("%s:", argv[i]);
/* IP addr */
if (lookup_ipa(argv[i], &in.s_addr))
a = "?";
else
a = inet_ntoa(in);
printf(" ipa=%s", a);
/* Ether addr */
hwa = lookup_hwa(argv[i], 1);
if (!hwa)
a = "?";
else
a = ether_ntoa(hwa);
printf(" hwa=%s\n", a);
}
exit(0);
}

44
libexec/bootpd/tzone.c Normal file
View File

@ -0,0 +1,44 @@
/*
* tzone.c - get the timezone
*
* This is shared by bootpd and bootpef
*/
#ifdef SVR4
/* XXX - Is this really SunOS specific? -gwr */
/* This is in <time.h> but only visible if (__STDC__ == 1). */
extern long timezone;
#else /* SVR4 */
/* BSD or SunOS */
# include <sys/time.h>
# include <syslog.h>
#endif /* SVR4 */
#include "bptypes.h"
#include "report.h"
#include "tzone.h"
/* This is what other modules use. */
int32 secondswest;
/*
* Get our timezone offset so we can give it to clients if the
* configuration file doesn't specify one.
*/
void
tzone_init()
{
#ifdef SVR4
/* XXX - Is this really SunOS specific? -gwr */
secondswest = timezone;
#else /* SVR4 */
struct timezone tzp; /* Time zone offset for clients */
struct timeval tp; /* Time (extra baggage) */
if (gettimeofday(&tp, &tzp) < 0) {
secondswest = 0; /* Assume GMT for lack of anything better */
report(LOG_ERR, "gettimeofday: %s", get_errmsg());
} else {
secondswest = 60L * tzp.tz_minuteswest; /* Convert to seconds */
}
#endif /* SVR4 */
}

3
libexec/bootpd/tzone.h Normal file
View File

@ -0,0 +1,3 @@
/* tzone.h */
extern int32 secondswest;
extern void tzone_init();