1 /************************************************************************
2 Copyright 1988, 1991 by Carnegie Mellon University
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted, provided
8 that the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation, and that the name of Carnegie Mellon University not be used
11 in advertising or publicity pertaining to distribution of the software
12 without specific, written prior permission.
14 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16 IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22 ************************************************************************/
25 * BOOTP (bootstrap protocol) server daemon.
27 * Answers BOOTP request packets from booting client machines.
28 * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
29 * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
30 * See RFC 1395 for option tags 14-17.
31 * See accompanying man page -- bootpd.8
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
50 #include <sys/utsname.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h> /* inet_ntoa */
72 # include <fcntl.h> /* for O_RDONLY, etc */
77 /* Yes, memcpy is OK here (no overlapped copies). */
78 # define bcopy(a,b,c) memcpy(b,a,c)
79 # define bzero(p,l) memset(p,0,l)
80 # define bcmp(a,b,c) memcmp(a,b,c)
92 #include "patchlevel.h"
95 #define CONFIG_FILE "/etc/bootptab"
98 #define DUMPTAB_FILE "/tmp/bootpd.dump"
104 * Externals, forward declarations, and global variables
107 extern void dumptab(char *);
109 PRIVATE void catcher(int);
110 PRIVATE int chk_access(char *, int32 *);
112 PRIVATE void dovend_cmu(struct bootp *, struct host *);
114 PRIVATE void dovend_rfc1048(struct bootp *, struct host *, int32);
115 PRIVATE void handle_reply(void);
116 PRIVATE void handle_request(void);
117 PRIVATE void sendreply(int forward, int32 dest_override);
118 PRIVATE void usage(void);
121 * IP port numbers for client and server obtained from /etc/services
124 u_short bootps_port, bootpc_port;
128 * Internet socket and interface config structures
131 struct sockaddr_in bind_addr; /* Listening */
132 struct sockaddr_in recv_addr; /* Packet source */
133 struct sockaddr_in send_addr; /* destination */
139 int debug = 0; /* Debugging flag (level) */
140 struct timeval actualtimeout =
141 { /* fifteen minutes */
142 15 * 60L, /* tv_sec */
150 int s; /* Socket file descriptor */
151 char *pktbuf; /* Receive packet buffer */
155 struct in_addr my_ip_addr;
157 static const char *hostname;
158 static char default_hostname[MAXHOSTNAMELEN];
160 /* Flags set by signal catcher. */
161 PRIVATE int do_readtab = 0;
162 PRIVATE int do_dumptab = 0;
165 * Globals below are associated with the bootp database file (bootptab).
168 char *bootptab = CONFIG_FILE;
169 char *bootpd_dump = DUMPTAB_FILE;
174 * Initialization such as command-line processing is done and then the
175 * main server loop is started.
183 struct timeval *timeout;
185 struct servent *servp;
188 int n, ba_len, ra_len;
192 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
196 progname = strrchr(argv[0], '/');
197 if (progname) progname++;
198 else progname = argv[0];
201 * Initialize logging.
203 report_init(0); /* uses progname */
208 report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
210 /* Debugging for compilers with struct padding. */
211 assert(sizeof(struct bootp) == BP_MINPKTSZ);
213 /* Get space for receiving packets and composing replies. */
214 pktbuf = malloc(MAX_MSG_SIZE);
216 report(LOG_ERR, "malloc failed");
219 bp = (struct bootp *) pktbuf;
222 * Check to see if a socket was passed to us from inetd.
224 * Use getsockname() to determine if descriptor 0 is indeed a socket
225 * (and thus we are probably a child of inetd) or if it is instead
226 * something else and we are running standalone.
229 ba_len = sizeof(bind_addr);
230 bzero((char *) &bind_addr, ba_len);
233 if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
235 * Descriptor 0 is a socket. Assume we are a child of inetd.
237 if (bind_addr.sin_family == AF_INET) {
239 bootps_port = ntohs(bind_addr.sin_port);
241 /* Some other type of socket? */
242 report(LOG_ERR, "getsockname: not an INET socket");
247 * Set defaults that might be changed by option switches.
250 timeout = &actualtimeout;
252 if (gethostname(default_hostname, sizeof(default_hostname) - 1) < 0) {
253 report(LOG_ERR, "bootpd: can't get hostname\n");
256 default_hostname[sizeof(default_hostname) - 1] = '\0';
257 hostname = default_hostname;
262 for (argc--, argv++; argc > 0; argc--, argv++) {
263 if (argv[0][0] != '-')
265 switch (argv[0][1]) {
267 case 'c': /* chdir_path */
269 stmp = &(argv[0][2]);
275 if (!stmp || (stmp[0] != '/')) {
277 "bootpd: invalid chdir specification\n");
283 case 'd': /* debug level */
285 stmp = &(argv[0][2]);
286 } else if (argv[1] && argv[1][0] == '-') {
288 * Backwards-compatible behavior:
289 * no parameter, so just increment the debug flag.
298 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
300 "%s: invalid debug level\n", progname);
306 case 'h': /* override hostname */
308 stmp = &(argv[0][2]);
316 "bootpd: missing hostname\n");
322 case 'i': /* inetd mode */
326 case 's': /* standalone mode */
330 case 't': /* timeout */
332 stmp = &(argv[0][2]);
338 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
340 "%s: invalid timeout specification\n", progname);
343 actualtimeout.tv_sec = (int32) (60 * n);
345 * If the actual timeout is zero, pass a NULL pointer
346 * to select so it blocks indefinitely, otherwise,
347 * point to the actual timeout value.
349 timeout = (n > 0) ? &actualtimeout : NULL;
353 report(LOG_ERR, "%s: unknown switch: -%c\n",
354 progname, argv[0][1]);
362 * Override default file names if specified on the command line.
368 bootpd_dump = argv[1];
371 * Get my hostname and IP address.
374 hep = gethostbyname(hostname);
376 report(LOG_ERR, "Can not get my IP address\n");
379 bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
383 * Go into background and disassociate from controlling terminal.
391 n = open(_PATH_TTY, O_RDWR);
393 ioctl(n, TIOCNOTTY, (char *) 0);
396 #endif /* TIOCNOTTY */
404 * Nuke any timeout value
408 } /* if standalone (1st) */
410 /* Set the cwd (i.e. to /tftpboot) */
412 if (chdir(chdir_path) < 0)
413 report(LOG_ERR, "%s: chdir failed", chdir_path);
416 /* Get the timezone. */
419 /* Allocate hash tables. */
423 * Read the bootptab file.
425 readtab(1); /* force read */
432 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
433 report(LOG_ERR, "socket: %s", get_network_errmsg());
438 * Get server's listening port number
440 servp = getservbyname("bootps", "udp");
442 bootps_port = ntohs((u_short) servp->s_port);
444 bootps_port = (u_short) IPPORT_BOOTPS;
446 "bootps/udp: unknown service -- using port %d",
451 * Bind socket to BOOTPS port.
453 bind_addr.sin_family = AF_INET;
454 bind_addr.sin_addr.s_addr = INADDR_ANY;
455 bind_addr.sin_port = htons(bootps_port);
456 if (bind(s, (struct sockaddr *) &bind_addr,
457 sizeof(bind_addr)) < 0)
459 report(LOG_ERR, "bind: %s", get_network_errmsg());
462 } /* if standalone (2nd)*/
465 * Get destination port number so we can reply to client
467 servp = getservbyname("bootpc", "udp");
469 bootpc_port = ntohs(servp->s_port);
472 "bootpc/udp: unknown service -- using port %d",
474 bootpc_port = (u_short) IPPORT_BOOTPC;
478 * Set up signals to read or dump the table.
480 #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */
481 sa.sa_handler = catcher;
482 sigemptyset(&sa.sa_mask);
484 if (sigaction(SIGHUP, &sa, NULL) < 0) {
485 report(LOG_ERR, "sigaction: %s", get_errmsg());
488 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
489 report(LOG_ERR, "sigaction: %s", get_errmsg());
492 #else /* SA_NOCLDSTOP */
493 /* Old-fashioned UNIX signals */
494 if ((int) signal(SIGHUP, catcher) < 0) {
495 report(LOG_ERR, "signal: %s", get_errmsg());
498 if ((int) signal(SIGUSR1, catcher) < 0) {
499 report(LOG_ERR, "signal: %s", get_errmsg());
502 #endif /* SA_NOCLDSTOP */
505 * Process incoming requests.
515 nfound = select(s + 1, &readfds, NULL, NULL,
516 (timeout) ? &tv : NULL);
518 if (errno != EINTR) {
519 report(LOG_ERR, "select: %s", get_errmsg());
522 * Call readtab() or dumptab() here to avoid the
523 * dangers of doing I/O from a signal handler.
527 readtab(1); /* force read */
531 dumptab(bootpd_dump);
535 if (!FD_ISSET(s, &readfds)) {
537 report(LOG_INFO, "exiting after %ld minutes of inactivity",
538 actualtimeout.tv_sec / 60);
541 ra_len = sizeof(recv_addr);
542 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
543 (struct sockaddr *) &recv_addr, &ra_len);
548 report(LOG_INFO, "recvd pkt from IP addr %s",
549 inet_ntoa(recv_addr.sin_addr));
551 if (n < sizeof(struct bootp)) {
553 report(LOG_NOTICE, "received short packet");
559 readtab(0); /* maybe re-read bootptab */
577 * Print "usage" message and exit
584 "usage: bootpd [-i | -s] [-c chdir-path] [-d level] [-h hostname] [-t timeout]\n");
585 fprintf(stderr, " [bootptab [dumpfile]]\n");
586 fprintf(stderr, "\t -c n\tset current directory\n");
587 fprintf(stderr, "\t -d n\tset debug level\n");
588 fprintf(stderr, "\t -h n\tset the hostname to listen on\n");
589 fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
590 fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
591 fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
595 /* Signal catchers */
604 #if !defined(SA_NOCLDSTOP) && defined(SYSV)
605 /* For older "System V" derivatives with no sigaction(). */
606 signal(sig, catcher);
613 * Process BOOTREQUEST packet.
615 * Note: This version of the bootpd.c server never forwards
616 * a request to another server. That is the job of a gateway
617 * program such as the "bootpgw" program included here.
619 * (Also this version does not interpret the hostname field of
620 * the request packet; it COULD do a name->address lookup and
621 * forward the request there.)
626 struct bootp *bp = (struct bootp *) pktbuf;
627 struct host *hp = NULL;
628 struct host dummyhost;
630 unsigned hlen, hashcode;
634 char *homedir, *bootfile;
637 bp->bp_file[sizeof(bp->bp_file)-1] = '\0';
639 /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
642 * If the servername field is set, compare it against us.
643 * If we're not being addressed, ignore this request.
644 * If the server name field is null, throw in our name.
646 if (strlen(bp->bp_sname)) {
647 if (strcmp(bp->bp_sname, hostname)) {
650 ignoring request for server %s from client at %s address %s",
651 bp->bp_sname, netname(bp->bp_htype),
652 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
653 /* XXX - Is it correct to ignore such a request? -gwr */
657 strcpy(bp->bp_sname, hostname);
660 /* Convert the request into a reply. */
661 bp->bp_op = BOOTREPLY;
662 if (bp->bp_ciaddr.s_addr == 0) {
664 * client doesnt know his IP address,
665 * search by hardware address.
668 report(LOG_INFO, "request from %s address %s",
669 netname(bp->bp_htype),
670 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
672 hlen = haddrlength(bp->bp_htype);
673 if (hlen != bp->bp_hlen) {
674 report(LOG_NOTICE, "bad addr len from %s address %s",
675 netname(bp->bp_htype),
676 haddrtoa(bp->bp_chaddr, hlen));
678 dummyhost.htype = bp->bp_htype;
679 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
680 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
681 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
684 bp->bp_htype == HTYPE_IEEE802)
686 /* Try again with address in "canonical" form. */
687 haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
690 HW addr type is IEEE 802. convert to %s and check again\n",
691 haddrtoa(dummyhost.haddr, bp->bp_hlen));
693 hashcode = hash_HashFunction(dummyhost.haddr, hlen);
694 hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
695 hwlookcmp, &dummyhost);
699 * XXX - Add dynamic IP address assignment?
702 report(LOG_NOTICE, "unknown client %s address %s",
703 netname(bp->bp_htype),
704 haddrtoa(bp->bp_chaddr, bp->bp_hlen));
705 return; /* not found */
707 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
712 * search by IP address.
715 report(LOG_INFO, "request from IP addr %s",
716 inet_ntoa(bp->bp_ciaddr));
718 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
719 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
720 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
724 report(LOG_NOTICE, "IP address not found: %s",
725 inet_ntoa(bp->bp_ciaddr));
732 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
733 hp->hostname->string);
737 * If there is a response delay threshold, ignore requests
738 * with a timestamp lower than the threshold.
740 if (hp->flags.min_wait) {
741 u_int32 t = (u_int32) ntohs(bp->bp_secs);
742 if (t < hp->min_wait) {
745 "ignoring request due to timestamp (%d < %d)",
751 #ifdef YORK_EX_OPTION
753 * The need for the "ex" tag arose out of the need to empty
754 * shared networked drives on diskless PCs. This solution is
755 * not very clean but it does work fairly well.
756 * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
758 * XXX - This could compromise security if a non-trusted user
759 * managed to write an entry in the bootptab with :ex=trojan:
760 * so I would leave this turned off unless you need it. -gwr
762 /* Run a program, passing the client name as a parameter. */
763 if (hp->flags.exec_file) {
765 /* XXX - Check string lengths? -gwr */
766 strcpy (tst, hp->exec_file->string);
768 strcat (tst, hp->hostname->string);
771 report(LOG_INFO, "executing %s", tst);
772 system(tst); /* Hope this finishes soon... */
774 #endif /* YORK_EX_OPTION */
777 * If a specific TFTP server address was specified in the bootptab file,
778 * fill it in, otherwise zero it.
779 * XXX - Rather than zero it, should it be the bootpd address? -gwr
781 (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
782 hp->bootserver.s_addr : 0L;
784 #ifdef STANFORD_PROM_COMPAT
786 * Stanford bootp PROMs (for a Sun?) have no way to leave
787 * the boot file name field blank (because the boot file
788 * name is automatically generated from some index).
789 * As a work-around, this little hack allows those PROMs to
790 * specify "sunboot14" with the same effect as a NULL name.
791 * (The user specifies boot device 14 or some such magic.)
793 if (strcmp(bp->bp_file, "sunboot14") == 0)
794 bp->bp_file[0] = '\0'; /* treat it as unspecified */
798 * Fill in the client's proper bootfile.
800 * If the client specifies an absolute path, try that file with a
801 * ".host" suffix and then without. If the file cannot be found, no
802 * reply is made at all.
804 * If the client specifies a null or relative file, use the following
805 * table to determine the appropriate action:
807 * Homedir Bootfile Client's file
808 * specified? specified? specification Action
809 * -------------------------------------------------------------------
810 * No No Null Send null filename
811 * No No Relative Discard request
812 * No Yes Null Send if absolute else null
813 * No Yes Relative Discard request *XXX
814 * Yes No Null Send null filename
815 * Yes No Relative Lookup with ".host"
816 * Yes Yes Null Send home/boot or bootfile
817 * Yes Yes Relative Lookup with ".host" *XXX
822 * XXX - I don't like the policy of ignoring a client when the
823 * boot file is not accessible. The TFTP server might not be
824 * running on the same machine as the BOOTP server, in which
825 * case checking accessibility of the boot file is pointless.
827 * Therefore, file accessibility is now demanded ONLY if you
828 * define CHECK_FILE_ACCESS in the Makefile options. -gwr
832 * The "real" path is as seen by the BOOTP daemon on this
833 * machine, while the client path is relative to the TFTP
834 * daemon chroot directory (i.e. /tftpboot).
836 if (hp->flags.tftpdir) {
837 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string);
838 clntpath = &realpath[strlen(realpath)];
845 * Determine client's requested homedir and bootfile.
849 if (bp->bp_file[0]) {
850 homedir = bp->bp_file;
851 bootfile = strrchr(homedir, '/');
853 if (homedir == bootfile)
857 /* no "/" in the string */
862 report(LOG_INFO, "requested path=\"%s\" file=\"%s\"",
863 (homedir) ? homedir : "",
864 (bootfile) ? bootfile : "");
869 * Specifications in bootptab override client requested values.
871 if (hp->flags.homedir)
872 homedir = hp->homedir->string;
873 if (hp->flags.bootfile)
874 bootfile = hp->bootfile->string;
877 * Construct bootfile path.
880 if (homedir[0] != '/')
881 strcat(clntpath, "/");
882 strcat(clntpath, homedir);
886 if (bootfile[0] != '/')
887 strcat(clntpath, "/");
888 strcat(clntpath, bootfile);
893 * First try to find the file with a ".host" suffix
895 n = strlen(clntpath);
896 strcat(clntpath, ".");
897 strcat(clntpath, hp->hostname->string);
898 if (chk_access(realpath, &bootsize) < 0) {
899 clntpath[n] = 0; /* Try it without the suffix */
900 if (chk_access(realpath, &bootsize) < 0) {
901 /* neither "file.host" nor "file" was found */
902 #ifdef CHECK_FILE_ACCESS
904 if (bp->bp_file[0]) {
906 * Client wanted specific file
907 * and we didn't have it.
910 "requested file not found: \"%s\"", clntpath);
914 * Client didn't ask for a specific file and we couldn't
915 * access the default file, so just zero-out the bootfile
916 * field in the packet and continue processing the reply.
918 bzero(bp->bp_file, sizeof(bp->bp_file));
921 #else /* CHECK_FILE_ACCESS */
923 /* Complain only if boot file size was needed. */
924 if (hp->flags.bootsize_auto) {
925 report(LOG_ERR, "can not determine size of file \"%s\"",
929 #endif /* CHECK_FILE_ACCESS */
932 strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
934 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
936 #ifdef CHECK_FILE_ACCESS
938 #endif /* CHECK_FILE_ACCESS */
942 * Handle vendor options based on magic number.
946 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
947 (int) ((bp->bp_vend)[0]),
948 (int) ((bp->bp_vend)[1]),
949 (int) ((bp->bp_vend)[2]),
950 (int) ((bp->bp_vend)[3]));
953 * If this host isn't set for automatic vendor info then copy the
954 * specific cookie into the bootp packet, thus forcing a certain
955 * reply format. Only force reply format if user specified it.
957 if (hp->flags.vm_cookie) {
958 /* Slam in the user specified magic number. */
959 bcopy(hp->vm_cookie, bp->bp_vend, 4);
962 * Figure out the format for the vendor-specific info.
963 * Note that bp->bp_vend may have been set above.
965 if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
966 /* RFC1048 conformant bootp client */
967 dovend_rfc1048(bp, hp, bootsize);
969 report(LOG_INFO, "sending reply (with RFC1048 options)");
973 else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
976 report(LOG_INFO, "sending reply (with CMU options)");
982 report(LOG_INFO, "sending reply (with no options)");
986 dest = (hp->flags.reply_addr) ?
987 hp->reply_addr.s_addr : 0L;
995 * Process BOOTREPLY packet.
1001 report(LOG_INFO, "processing boot reply");
1003 /* forwarded, no destination override */
1009 * Send a reply packet to the client. 'forward' flag is set if we are
1010 * not the originator of this reply packet.
1013 sendreply(forward, dst_override)
1017 struct bootp *bp = (struct bootp *) pktbuf;
1019 u_short port = bootpc_port;
1024 * XXX - Should honor bp_flags "broadcast" bit here.
1025 * Temporary workaround: use the :ra=ADDR: option to
1026 * set the reply address to the broadcast address.
1030 * If the destination address was specified explicitly
1031 * (i.e. the broadcast address for HP compatibility)
1032 * then send the response to that address. Otherwise,
1033 * act in accordance with RFC951:
1034 * If the client IP address is specified, use that
1035 * else if gateway IP address is specified, use that
1036 * else make a temporary arp cache entry for the client's
1037 * NEW IP/hardware address and use that.
1040 dst.s_addr = dst_override;
1042 report(LOG_INFO, "reply address override: %s",
1045 } else if (bp->bp_ciaddr.s_addr) {
1046 dst = bp->bp_ciaddr;
1047 } else if (bp->bp_giaddr.s_addr && forward == 0) {
1048 dst = bp->bp_giaddr;
1051 report(LOG_INFO, "sending reply to gateway %s",
1055 dst = bp->bp_yiaddr;
1058 if (len > MAXHADDRLEN)
1060 haf = (int) bp->bp_htype;
1062 haf = HTYPE_ETHERNET;
1065 report(LOG_INFO, "setarp %s - %s",
1066 inet_ntoa(dst), haddrtoa(ha, len));
1067 setarp(s, &dst, haf, ha, len);
1070 if ((forward == 0) &&
1071 (bp->bp_siaddr.s_addr == 0))
1074 struct in_addr siaddr;
1076 * If we are originating this reply, we
1077 * need to find our own interface address to
1078 * put in the bp_siaddr field of the reply.
1079 * If this server is multi-homed, pick the
1080 * 'best' interface (the one on the same net
1081 * as the client). Of course, the client may
1082 * be on the other side of a BOOTP gateway...
1084 ifr = getif(s, &dst);
1086 struct sockaddr_in *sip;
1087 sip = (struct sockaddr_in *) &(ifr->ifr_addr);
1088 siaddr = sip->sin_addr;
1090 /* Just use my "official" IP address. */
1091 siaddr = my_ip_addr;
1094 /* XXX - No need to set bp_giaddr here. */
1096 /* Finally, set the server address field. */
1097 bp->bp_siaddr = siaddr;
1099 /* Set up socket address for send. */
1100 send_addr.sin_family = AF_INET;
1101 send_addr.sin_port = htons(port);
1102 send_addr.sin_addr = dst;
1104 /* Send reply with same size packet as request used. */
1105 if (sendto(s, pktbuf, pktlen, 0,
1106 (struct sockaddr *) &send_addr,
1107 sizeof(send_addr)) < 0)
1109 report(LOG_ERR, "sendto: %s", get_network_errmsg());
1114 /* nmatch() - now in getif.c */
1115 /* setarp() - now in hwaddr.c */
1119 * This call checks read access to a file. It returns 0 if the file given
1120 * by "path" exists and is publically readable. A value of -1 is returned if
1121 * access is not permitted or an error occurs. Successful calls also
1122 * return the file size in bytes using the long pointer "filesize".
1124 * The read permission bit for "other" users is checked. This bit must be
1125 * set for tftpd(8) to allow clients to read the file.
1129 chk_access(path, filesize)
1135 if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
1136 *filesize = (int32) st.st_size;
1145 * Now in dumptab.c :
1148 * list_ipaddresses()
1154 * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1155 * bootp packet pointed to by "bp".
1163 struct cmu_vend *vendp;
1164 struct in_addr_list *taddr;
1167 * Initialize the entire vendor field to zeroes.
1169 bzero(bp->bp_vend, sizeof(bp->bp_vend));
1172 * Fill in vendor information. Subnet mask, default gateway,
1173 * domain name server, ien name server, time server
1175 vendp = (struct cmu_vend *) bp->bp_vend;
1176 strcpy(vendp->v_magic, (char *)vm_cmu);
1177 if (hp->flags.subnet_mask) {
1178 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
1179 (vendp->v_flags) |= VF_SMASK;
1180 if (hp->flags.gateway) {
1181 (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
1184 if (hp->flags.domain_server) {
1185 taddr = hp->domain_server;
1186 if (taddr->addrcount > 0) {
1187 (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
1188 if (taddr->addrcount > 1) {
1189 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
1193 if (hp->flags.name_server) {
1194 taddr = hp->name_server;
1195 if (taddr->addrcount > 0) {
1196 (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
1197 if (taddr->addrcount > 1) {
1198 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
1202 if (hp->flags.time_server) {
1203 taddr = hp->time_server;
1204 if (taddr->addrcount > 0) {
1205 (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
1206 if (taddr->addrcount > 1) {
1207 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
1211 /* Log message now done by caller. */
1214 #endif /* VEND_CMU */
1219 * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1220 * bootp packet pointed to by "bp".
1222 #define NEED(LEN, MSG) do \
1223 if (bytesleft < (LEN)) { \
1224 report(LOG_NOTICE, noroom, \
1225 hp->hostname->string, MSG); \
1229 dovend_rfc1048(bp, hp, bootsize)
1237 static const char noroom[] = "%s: No room for \"%s\" option";
1241 if (hp->flags.msg_size) {
1242 pktlen = hp->msg_size;
1245 * If the request was longer than the official length, build
1246 * a response of that same length where the additional length
1247 * is assumed to be part of the bp_vend (options) area.
1249 if (pktlen > sizeof(*bp)) {
1251 report(LOG_INFO, "request message length=%d", pktlen);
1254 * Check whether the request contains the option:
1255 * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1256 * and if so, override the response length with its value.
1257 * This request must lie within the first BP_VEND_LEN
1258 * bytes of the option space.
1266 ep = p + BP_VEND_LEN - 4;
1269 /* Check for tags with no data first. */
1274 /* Now scan the length byte. */
1279 bcopy(p, (char*)&msgsz, 2);
1280 msgsz = ntohs(msgsz);
1283 case TAG_SUBNET_MASK:
1284 /* XXX - Should preserve this if given... */
1290 if (msgsz > sizeof(*bp) + BP_MSG_OVERHEAD) {
1292 report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
1293 pktlen = msgsz - BP_MSG_OVERHEAD;
1298 if (pktlen < sizeof(*bp)) {
1299 report(LOG_ERR, "invalid response length=%d", pktlen);
1300 pktlen = sizeof(*bp);
1302 bytesleft = ((byte*)bp + pktlen) - vp;
1303 if (pktlen > sizeof(*bp)) {
1305 report(LOG_INFO, "extended reply, length=%d, options=%d",
1309 /* Copy in the magic cookie */
1310 bcopy(vm_rfc1048, vp, 4);
1314 if (hp->flags.subnet_mask) {
1315 /* always enough room here. */
1316 *vp++ = TAG_SUBNET_MASK;/* -1 byte */
1317 *vp++ = 4; /* -1 byte */
1318 insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
1319 bytesleft -= 6; /* Fix real count */
1320 if (hp->flags.gateway) {
1321 (void) insert_ip(TAG_GATEWAY,
1326 if (hp->flags.bootsize) {
1327 /* always enough room here */
1328 bootsize = (hp->flags.bootsize_auto) ?
1329 ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
1330 *vp++ = TAG_BOOT_SIZE;
1332 *vp++ = (byte) ((bootsize >> 8) & 0xFF);
1333 *vp++ = (byte) (bootsize & 0xFF);
1334 bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
1337 * This one is special: Remaining options go in the ext file.
1338 * Only the subnet_mask, bootsize, and gateway should precede.
1340 if (hp->flags.exten_file) {
1342 * Check for room for exten_file. Add 3 to account for
1343 * TAG_EXTEN_FILE, length, and TAG_END.
1345 len = strlen(hp->exten_file->string);
1346 NEED((len + 3), "ef");
1347 *vp++ = TAG_EXTEN_FILE;
1348 *vp++ = (byte) (len & 0xFF);
1349 bcopy(hp->exten_file->string, vp, len);
1352 bytesleft -= len + 3;
1353 return; /* no more options here. */
1356 * The remaining options are inserted by the following
1357 * function (which is shared with bootpef.c).
1358 * Keep back one byte for the TAG_END.
1360 len = dovend_rfc1497(hp, vp, bytesleft - 1);
1364 /* There should be at least one byte left. */
1369 /* Log message done by caller. */
1370 if (bytesleft > 0) {
1372 * Zero out any remaining part of the vendor area.
1374 bzero(vp, bytesleft);
1376 } /* dovend_rfc1048 */
1381 * Now in readfile.c:
1386 /* haddrtoa() - now in hwaddr.c */
1394 /* get_errmsg() - now in report.c */
1400 * c-argdecl-indent: 4
1401 * c-continued-statement-offset: 4
1402 * c-continued-brace-offset: -4
1403 * c-label-offset: -4