diff options
Diffstat (limited to 'libexec/bootpd/tools')
| -rw-r--r-- | libexec/bootpd/tools/Makefile | 5 | ||||
| -rw-r--r-- | libexec/bootpd/tools/Makefile.inc | 7 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootpef/Makefile | 12 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootpef/Makefile.depend | 16 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootpef/bootpef.8 | 63 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootpef/bootpef.c | 318 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootptest/Makefile | 11 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootptest/Makefile.depend | 16 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootptest/bootptest.8 | 76 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootptest/bootptest.c | 510 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootptest/bootptest.h | 17 | ||||
| -rw-r--r-- | libexec/bootpd/tools/bootptest/print-bootp.c | 476 |
12 files changed, 1527 insertions, 0 deletions
diff --git a/libexec/bootpd/tools/Makefile b/libexec/bootpd/tools/Makefile new file mode 100644 index 000000000000..175a2cc2fa60 --- /dev/null +++ b/libexec/bootpd/tools/Makefile @@ -0,0 +1,5 @@ +# Makefile + +SUBDIR= bootpef bootptest + +.include <bsd.subdir.mk> diff --git a/libexec/bootpd/tools/Makefile.inc b/libexec/bootpd/tools/Makefile.inc new file mode 100644 index 000000000000..1017c3e74630 --- /dev/null +++ b/libexec/bootpd/tools/Makefile.inc @@ -0,0 +1,7 @@ +# Makefile.inc + +BINDIR= /usr/sbin + +WARNS?= 1 + +.include "../Makefile.inc" diff --git a/libexec/bootpd/tools/bootpef/Makefile b/libexec/bootpd/tools/bootpef/Makefile new file mode 100644 index 000000000000..bf51013c39c7 --- /dev/null +++ b/libexec/bootpd/tools/bootpef/Makefile @@ -0,0 +1,12 @@ +# Makefile + +PROG= bootpef +MAN= bootpef.8 +SRCS= bootpef.c dovend.c readfile.c hash.c dumptab.c lookup.c \ + hwaddr.c report.c tzone.c rtmsg.c + +SRCDIR= ${.CURDIR}/../.. +CFLAGS+=-I${SRCDIR} +.PATH: ${SRCDIR} + +.include <bsd.prog.mk> diff --git a/libexec/bootpd/tools/bootpef/Makefile.depend b/libexec/bootpd/tools/bootpef/Makefile.depend new file mode 100644 index 000000000000..344a5d0e9310 --- /dev/null +++ b/libexec/bootpd/tools/bootpef/Makefile.depend @@ -0,0 +1,16 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/arpa \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/libexec/bootpd/tools/bootpef/bootpef.8 b/libexec/bootpd/tools/bootpef/bootpef.8 new file mode 100644 index 000000000000..f410dfd9c635 --- /dev/null +++ b/libexec/bootpd/tools/bootpef/bootpef.8 @@ -0,0 +1,63 @@ +.\" +.\" bootpef.8 +.Dd December 4, 1993 +.Dt BOOTPEF 8 +.Os +.Sh NAME +.Nm bootpef +.Nd "BOOTP Extension File compiler" +.Sh SYNOPSIS +.Bk -words +.Nm +.Op Fl c Ar chdir\-path +.Op Fl d Ar debug\-level +.Op Fl f Ar config\-file +.Op Ar client\-name ... +.Ek +.Sh DESCRIPTION +The +.Nm +utility builds the +.Em "Extension Path" +files described by +.%T "RFC 1497" +(tag 18). +If any +.Ar client\-name +arguments are specified, then +.Nm +compiles the extension files for only those clients. +.Sh OPTIONS +.Bl -tag -width indent +.It Fl c Ar chdir\-path +Sets the current directory used by +.Nm +while creating extension files. +This is useful when the +extension file names are specified as relative pathnames, and +.Nm +needs to use the same current directory as the TFTP server +(typically +.Pa /tftpboot ) . +.It Fl d Ar debug\-level +Sets the +.Ar debug\-level +variable that controls the amount of debugging messages generated. +For example, +.Fl d Ar 4 +will set the debugging level to 4. +.It Fl f Ar config\-file +Set the name of the config file that specifies the option +data to be sent to each client. +.El +.Sh SEE ALSO +.Xr bootpd 8 , +.Xr tftpd 8 +.Rs +.%O RFC951 +.%T "BOOTSTRAP PROTOCOL (BOOTP)" +.Re +.Rs +.%O RFC1497 +.%T "BOOTP Vendor Information Extensions" +.Re diff --git a/libexec/bootpd/tools/bootpef/bootpef.c b/libexec/bootpd/tools/bootpef/bootpef.c new file mode 100644 index 000000000000..f8b2eeeaaf2d --- /dev/null +++ b/libexec/bootpd/tools/bootpef/bootpef.c @@ -0,0 +1,318 @@ +/************************************************************************ + 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. + +************************************************************************/ + +/* + * 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 + */ + + + +#include <stdarg.h> + +#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> + +#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 + */ + +static void mktagfile(struct host *); +static void usage(void) __dead2; + +/* + * 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(void) +{ + 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. + */ +int +main(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); + } + return (0); +} + + + +/* + * Make a "TAG 18" file for this host. + * (Insert the RFC1497 options.) + */ + +static void +mktagfile(struct host *hp) +{ + FILE *fp; + int bytesleft, len; + byte *vp; + + 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); + +} /* mktagfile */ + +/* + * 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: + */ diff --git a/libexec/bootpd/tools/bootptest/Makefile b/libexec/bootpd/tools/bootptest/Makefile new file mode 100644 index 000000000000..3a6fbd584606 --- /dev/null +++ b/libexec/bootpd/tools/bootptest/Makefile @@ -0,0 +1,11 @@ +# Makefile + +PROG= bootptest +MAN= bootptest.8 +SRCS= bootptest.c getether.c getif.c print-bootp.c report.c + +SRCDIR= ${.CURDIR}/../.. +CFLAGS+=-I${SRCDIR} +.PATH: ${SRCDIR} + +.include <bsd.prog.mk> diff --git a/libexec/bootpd/tools/bootptest/Makefile.depend b/libexec/bootpd/tools/bootptest/Makefile.depend new file mode 100644 index 000000000000..344a5d0e9310 --- /dev/null +++ b/libexec/bootpd/tools/bootptest/Makefile.depend @@ -0,0 +1,16 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/arpa \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/libexec/bootpd/tools/bootptest/bootptest.8 b/libexec/bootpd/tools/bootptest/bootptest.8 new file mode 100644 index 000000000000..97de293d6590 --- /dev/null +++ b/libexec/bootpd/tools/bootptest/bootptest.8 @@ -0,0 +1,76 @@ +.\" +.\" bootptest.8 +.Dd June 10, 1993 +.Dt BOOTPTEST 8 +.Os +.Sh NAME +.Nm bootptest +.Nd "send BOOTP queries and print responses" +.Sh SYNOPSIS +.Nm +.Op Fl f Ar bootfile +.Op Fl h +.Op Fl m Ar magic_number +.Ar server\-name +.Op Ar template\-file +.Sh DESCRIPTION +The +.Nm +utility sends BOOTP requests to the host specified as +.Ar server\-name +at one\-second intervals until either a response is received, +or until ten requests have gone unanswered. +After a response is received, +.Nm +will wait one more second listening for additional responses. +.Sh OPTIONS +.Bl -tag -width indent +.It Fl f Ar bootfile +Fill in the boot file field of the request with +.Ar bootfile . +.It Fl 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. +.It Fl m Ar magic_number +Initialize the first word of the vendor options field with +.Ar magic_number . +.El +.Pp +A +.Ar template\-file +may be specified, in which case +.Nm +uses the (binary) contents of this file to initialize the +.Em options +area of the request packet. +.Sh SEE ALSO +.Xr bootpd 8 +.Rs +.%O RFC951 +.%T "BOOTSTRAP PROTOCOL (BOOTP)" +.Re +.Rs +.%O RFC1048 +.%T "BOOTP Vendor Information Extensions" +.Re +.Sh AUTHORS +The +.Nm +utility is a combination of original and derived works. +The main program module +.Pq Pa bootptest.c +is original work by +.An Gordon W. Ross Aq Mt gwr@mc.com . +The packet printing module +.Pq Pa print\-bootp.c +is a slightly modified +version of a file from the +.Bx +.Xr tcpdump 1 +program. +.Pp +This program includes software developed by the University of +California, Lawrence Berkeley Laboratory and its contributors. +(See the copyright notice in +.Pa print\-bootp.c . ) diff --git a/libexec/bootpd/tools/bootptest/bootptest.c b/libexec/bootpd/tools/bootptest/bootptest.c new file mode 100644 index 000000000000..1797bcb9574d --- /dev/null +++ b/libexec/bootpd/tools/bootptest/bootptest.c @@ -0,0 +1,510 @@ +/* + * 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> + * + */ + +#include <sys/cdefs.h> +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 <sys/utsname.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> /* inet_ntoa */ + +#ifndef NO_UNISTD +#include <unistd.h> +#endif + +#include <err.h> +#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 "getether.h" + +#include "patchlevel.h" + +static void send_request(int s); + +#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 *sndbuf; /* Send packet buffer */ +char *rcvbuf; /* Receive packet buffer */ + +struct utsname my_uname; +char *hostname; + +/* + * 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 */ + +/* + * Initialization such as command-line processing is done, then + * the receiver loop is started. Die when interrupted. + */ + +int +main(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, 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); + + if (uname(&my_uname) < 0) + errx(1, "can't get hostname"); + hostname = my_uname.nodename; + + 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 request. */ + 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 { + warnx("bootps/udp: unknown service -- using port %d", + 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) + errx(1, "%s: unknown host", servername); + 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 { + warnx("bootpc/udp: unknown service -- using port %d", + 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) { + if (errno == EACCES) { + warn("bind BOOTPC port"); + errx(1, "you need to run this as root"); + } + else + err(1, "bind BOOTPC port"); + } + /* + * 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, (char*)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. */ + 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((struct bootp *)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. + */ + } + errx(1, "no response from %s", servername); +} + +static void +send_request(int s) +{ + /* Print the request packet. */ + printf("Sending to %s", inet_ntoa(sin_server.sin_addr)); + bootp_print((struct bootp *)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(u_char *s, u_char *ep) +{ + u_char c; + + putchar('"'); + while ((c = *s++) != '\0') { + 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(struct in_addr *ina) +{ + static char b[24]; + u_char *p; + + p = (u_char *) ina; + snprintf(b, sizeof(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: + */ diff --git a/libexec/bootpd/tools/bootptest/bootptest.h b/libexec/bootpd/tools/bootptest/bootptest.h new file mode 100644 index 000000000000..e4da8c6bbb47 --- /dev/null +++ b/libexec/bootpd/tools/bootptest/bootptest.h @@ -0,0 +1,17 @@ +/* bootptest.h */ +/* + * Hacks for sharing print-bootp.c between tcpdump and bootptest. + */ +#define ESRC(p) (p) +#define EDST(p) (p) + +extern int vflag; /* verbose flag */ + +/* global pointers to beginning and end of current packet (during printing) */ +extern unsigned char *packetp; +extern unsigned char *snapend; + +void bootp_print(struct bootp *bp, int length, u_short sport, + u_short dport); +char *ipaddr_string(struct in_addr *); +int printfn(u_char *s, u_char *ep); diff --git a/libexec/bootpd/tools/bootptest/print-bootp.c b/libexec/bootpd/tools/bootptest/print-bootp.c new file mode 100644 index 000000000000..dabab8115313 --- /dev/null +++ b/libexec/bootpd/tools/bootptest/print-bootp.c @@ -0,0 +1,476 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * 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. 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> + */ + +#include <stdio.h> + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <sys/time.h> /* for struct timeval in net/if.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(u_char *bp, int length); +static void cmu_print(u_char *bp, int length); +static void other_print(u_char *bp, int length); +static void dump_hex(u_char *bp, int len); + +/* + * Print bootp requests + */ +void +bootp_print(struct bootp *bp, int length, u_short sport, u_short 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 available 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) { + struct ether_header *eh; + 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 = NULL; + if (e == NULL || 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:%ld", (long)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 described 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 trailer 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 +rfc1048_print(u_char *bp, int length) +{ + u_char tag; + u_char *ep; + int len; + 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>%td)", 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("%ld", (long)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(u_char *bp, int length) +{ + struct cmu_vend *v; + + printf("-cmu"); + + v = (struct cmu_vend *) bp; + if (length < sizeof(*v)) { + printf(" |L=%d", length); + return; + } + + /* 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(u_char *bp, int length) +{ + u_char *ep; /* end pointer */ + u_char *zp; /* points one past last non-zero byte */ + + /* 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(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: + */ |
