113572Spst/* 213572Spst * bootpgw.c - BOOTP GateWay 313572Spst * This program forwards BOOTP Request packets to a BOOTP server. 413572Spst */ 513572Spst 613572Spst/************************************************************************ 713572Spst Copyright 1988, 1991 by Carnegie Mellon University 813572Spst 913572Spst All Rights Reserved 1013572Spst 1113572SpstPermission to use, copy, modify, and distribute this software and its 1213572Spstdocumentation for any purpose and without fee is hereby granted, provided 1313572Spstthat the above copyright notice appear in all copies and that both that 1413572Spstcopyright notice and this permission notice appear in supporting 1513572Spstdocumentation, and that the name of Carnegie Mellon University not be used 1613572Spstin advertising or publicity pertaining to distribution of the software 1713572Spstwithout specific, written prior permission. 1813572Spst 1913572SpstCARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 2013572SpstSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 2113572SpstIN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 2213572SpstDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 2313572SpstPROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 2413572SpstACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2513572SpstSOFTWARE. 2613572Spst************************************************************************/ 2713572Spst 2813572Spst/* 2913572Spst * BOOTPGW is typically used to forward BOOTP client requests from 3013572Spst * one subnet to a BOOTP server on a different subnet. 3113572Spst */ 3213572Spst 33110395Scharnier#include <sys/cdefs.h> 34110395Scharnier__FBSDID("$FreeBSD: releng/10.2/libexec/bootpd/bootpgw/bootpgw.c 229780 2012-01-07 16:09:54Z uqs $"); 35110395Scharnier 3613572Spst#include <sys/types.h> 3713572Spst#include <sys/param.h> 3813572Spst#include <sys/socket.h> 3913572Spst#include <sys/ioctl.h> 4013572Spst#include <sys/file.h> 4113572Spst#include <sys/time.h> 4213572Spst#include <sys/stat.h> 4313572Spst#include <sys/utsname.h> 4413572Spst 4513572Spst#include <net/if.h> 4613572Spst#include <netinet/in.h> 4713572Spst#include <arpa/inet.h> /* inet_ntoa */ 4813572Spst 4913572Spst#ifndef NO_UNISTD 5013572Spst#include <unistd.h> 5113572Spst#endif 5213572Spst 53110395Scharnier#include <err.h> 5413572Spst#include <stdlib.h> 5513572Spst#include <signal.h> 5613572Spst#include <stdio.h> 5713572Spst#include <string.h> 5813572Spst#include <errno.h> 5913572Spst#include <ctype.h> 6013572Spst#include <netdb.h> 6169793Sobrien#include <paths.h> 6213572Spst#include <syslog.h> 6313572Spst#include <assert.h> 6413572Spst 6513572Spst#ifdef NO_SETSID 6613572Spst# include <fcntl.h> /* for O_RDONLY, etc */ 6713572Spst#endif 6813572Spst 6913572Spst#ifndef USE_BFUNCS 7013572Spst# include <memory.h> 7113572Spst/* Yes, memcpy is OK here (no overlapped copies). */ 7213572Spst# define bcopy(a,b,c) memcpy(b,a,c) 7313572Spst# define bzero(p,l) memset(p,0,l) 7413572Spst# define bcmp(a,b,c) memcmp(a,b,c) 7513572Spst#endif 7613572Spst 7713572Spst#include "bootp.h" 7813572Spst#include "getif.h" 7913572Spst#include "hwaddr.h" 8013572Spst#include "report.h" 8113572Spst#include "patchlevel.h" 8213572Spst 8313572Spst/* Local definitions: */ 8413572Spst#define MAX_MSG_SIZE (3*512) /* Maximum packet size */ 8513572Spst#define TRUE 1 8613572Spst#define FALSE 0 8713572Spst#define get_network_errmsg get_errmsg 8813572Spst 8913572Spst 9013572Spst 9113572Spst/* 9213572Spst * Externals, forward declarations, and global variables 9313572Spst */ 9413572Spst 9597418Salfredstatic void usage(void); 9697418Salfredstatic void handle_reply(void); 9797418Salfredstatic void handle_request(void); 9813572Spst 9913572Spst/* 10013572Spst * IP port numbers for client and server obtained from /etc/services 10113572Spst */ 10213572Spst 10313572Spstu_short bootps_port, bootpc_port; 10413572Spst 10513572Spst 10613572Spst/* 10713572Spst * Internet socket and interface config structures 10813572Spst */ 10913572Spst 11013572Spststruct sockaddr_in bind_addr; /* Listening */ 11113572Spststruct sockaddr_in recv_addr; /* Packet source */ 11213572Spststruct sockaddr_in send_addr; /* destination */ 11313572Spst 11413572Spst 11513572Spst/* 11613572Spst * option defaults 11713572Spst */ 11813572Spstint debug = 0; /* Debugging flag (level) */ 11913572Spststruct timeval actualtimeout = 12013572Spst{ /* fifteen minutes */ 12113572Spst 15 * 60L, /* tv_sec */ 12213572Spst 0 /* tv_usec */ 12313572Spst}; 12422413Sjkhu_char maxhops = 4; /* Number of hops allowed for requests. */ 12513572Spstu_int minwait = 3; /* Number of seconds client must wait before 12613572Spst its bootrequest packets are forwarded. */ 12713572Spst 12813572Spst/* 12913572Spst * General 13013572Spst */ 13113572Spst 13213572Spstint s; /* Socket file descriptor */ 13313572Spstchar *pktbuf; /* Receive packet buffer */ 13413572Spstint pktlen; 13513572Spstchar *progname; 13613572Spstchar *servername; 13713572Spstint32 server_ipa; /* Real server IP address, network order. */ 13813572Spst 13913572Spststruct in_addr my_ip_addr; 14013572Spst 14113572Spststruct utsname my_uname; 14213572Spstchar *hostname; 14313572Spst 14413572Spst 14513572Spst 14613572Spst 14713572Spst 14813572Spst/* 14913572Spst * Initialization such as command-line processing is done and then the 15013572Spst * main server loop is started. 15113572Spst */ 15213572Spst 15346078Simpint 15413572Spstmain(argc, argv) 15513572Spst int argc; 15613572Spst char **argv; 15713572Spst{ 15813572Spst struct timeval *timeout; 15913572Spst struct bootp *bp; 16013572Spst struct servent *servp; 16113572Spst struct hostent *hep; 16213572Spst char *stmp; 16313572Spst int n, ba_len, ra_len; 16413572Spst int nfound, readfds; 16513572Spst int standalone; 16613572Spst 16713572Spst progname = strrchr(argv[0], '/'); 16813572Spst if (progname) progname++; 16913572Spst else progname = argv[0]; 17013572Spst 17113572Spst /* 17213572Spst * Initialize logging. 17313572Spst */ 17413572Spst report_init(0); /* uses progname */ 17513572Spst 17613572Spst /* 17713572Spst * Log startup 17813572Spst */ 17913572Spst report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL); 18013572Spst 18113572Spst /* Debugging for compilers with struct padding. */ 18213572Spst assert(sizeof(struct bootp) == BP_MINPKTSZ); 18313572Spst 18413572Spst /* Get space for receiving packets and composing replies. */ 18513572Spst pktbuf = malloc(MAX_MSG_SIZE); 18613572Spst if (!pktbuf) { 18713572Spst report(LOG_ERR, "malloc failed"); 18813572Spst exit(1); 18913572Spst } 19013572Spst bp = (struct bootp *) pktbuf; 19113572Spst 19213572Spst /* 19313572Spst * Check to see if a socket was passed to us from inetd. 19413572Spst * 19513572Spst * Use getsockname() to determine if descriptor 0 is indeed a socket 19613572Spst * (and thus we are probably a child of inetd) or if it is instead 19713572Spst * something else and we are running standalone. 19813572Spst */ 19913572Spst s = 0; 20013572Spst ba_len = sizeof(bind_addr); 20113572Spst bzero((char *) &bind_addr, ba_len); 20213572Spst errno = 0; 20313572Spst standalone = TRUE; 20413572Spst if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) { 20513572Spst /* 20613572Spst * Descriptor 0 is a socket. Assume we are a child of inetd. 20713572Spst */ 20813572Spst if (bind_addr.sin_family == AF_INET) { 20913572Spst standalone = FALSE; 21013572Spst bootps_port = ntohs(bind_addr.sin_port); 21113572Spst } else { 21213572Spst /* Some other type of socket? */ 21313572Spst report(LOG_INFO, "getsockname: not an INET socket"); 21413572Spst } 21513572Spst } 21613572Spst /* 21713572Spst * Set defaults that might be changed by option switches. 21813572Spst */ 21913572Spst stmp = NULL; 22013572Spst timeout = &actualtimeout; 22113572Spst 222110395Scharnier if (uname(&my_uname) < 0) 223110395Scharnier errx(1, "can't get hostname"); 22413572Spst hostname = my_uname.nodename; 22513572Spst 22613572Spst hep = gethostbyname(hostname); 22713572Spst if (!hep) { 22813572Spst printf("Can not get my IP address\n"); 22913572Spst exit(1); 23013572Spst } 23113572Spst bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr)); 23213572Spst 23313572Spst /* 23413572Spst * Read switches. 23513572Spst */ 23613572Spst for (argc--, argv++; argc > 0; argc--, argv++) { 23713572Spst if (argv[0][0] != '-') 23813572Spst break; 23913572Spst switch (argv[0][1]) { 24013572Spst 24113572Spst case 'd': /* debug level */ 24213572Spst if (argv[0][2]) { 24313572Spst stmp = &(argv[0][2]); 24413572Spst } else if (argv[1] && argv[1][0] == '-') { 24513572Spst /* 24613572Spst * Backwards-compatible behavior: 24713572Spst * no parameter, so just increment the debug flag. 24813572Spst */ 24913572Spst debug++; 25013572Spst break; 25113572Spst } else { 25213572Spst argc--; 25313572Spst argv++; 25413572Spst stmp = argv[0]; 25513572Spst } 25613572Spst if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) { 257110395Scharnier warnx("invalid debug level"); 25813572Spst break; 25913572Spst } 26013572Spst debug = n; 26113572Spst break; 26213572Spst 26313572Spst case 'h': /* hop count limit */ 26413572Spst if (argv[0][2]) { 26513572Spst stmp = &(argv[0][2]); 26613572Spst } else { 26713572Spst argc--; 26813572Spst argv++; 26913572Spst stmp = argv[0]; 27013572Spst } 27113572Spst if (!stmp || (sscanf(stmp, "%d", &n) != 1) || 27213572Spst (n < 0) || (n > 16)) 27313572Spst { 274110395Scharnier warnx("invalid hop count limit"); 27513572Spst break; 27613572Spst } 27722413Sjkh maxhops = (u_char)n; 27813572Spst break; 27913572Spst 28013572Spst case 'i': /* inetd mode */ 28113572Spst standalone = FALSE; 28213572Spst break; 28313572Spst 28413572Spst case 's': /* standalone mode */ 28513572Spst standalone = TRUE; 28613572Spst break; 28713572Spst 28813572Spst case 't': /* timeout */ 28913572Spst if (argv[0][2]) { 29013572Spst stmp = &(argv[0][2]); 29113572Spst } else { 29213572Spst argc--; 29313572Spst argv++; 29413572Spst stmp = argv[0]; 29513572Spst } 29613572Spst if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) { 297110395Scharnier warnx("invalid timeout specification"); 29813572Spst break; 29913572Spst } 30013572Spst actualtimeout.tv_sec = (int32) (60 * n); 30113572Spst /* 30213572Spst * If the actual timeout is zero, pass a NULL pointer 30313572Spst * to select so it blocks indefinitely, otherwise, 30413572Spst * point to the actual timeout value. 30513572Spst */ 30613572Spst timeout = (n > 0) ? &actualtimeout : NULL; 30713572Spst break; 30813572Spst 30913572Spst case 'w': /* wait time */ 31013572Spst if (argv[0][2]) { 31113572Spst stmp = &(argv[0][2]); 31213572Spst } else { 31313572Spst argc--; 31413572Spst argv++; 31513572Spst stmp = argv[0]; 31613572Spst } 31713572Spst if (!stmp || (sscanf(stmp, "%d", &n) != 1) || 31813572Spst (n < 0) || (n > 60)) 31913572Spst { 320110395Scharnier warnx("invalid wait time"); 32113572Spst break; 32213572Spst } 32313572Spst minwait = (u_int)n; 32413572Spst break; 32513572Spst 32613572Spst default: 327110395Scharnier warnx("unknown switch: -%c", argv[0][1]); 32813572Spst usage(); 32913572Spst break; 33013572Spst 33113572Spst } /* switch */ 33213572Spst } /* for args */ 33313572Spst 33413572Spst /* Make sure server name argument is suplied. */ 33513572Spst servername = argv[0]; 33613572Spst if (!servername) { 337110395Scharnier warnx("missing server name"); 33813572Spst usage(); 33913572Spst } 34013572Spst /* 34113572Spst * Get address of real bootp server. 34213572Spst */ 34313572Spst if (isdigit(servername[0])) 34413572Spst server_ipa = inet_addr(servername); 34513572Spst else { 34613572Spst hep = gethostbyname(servername); 347110395Scharnier if (!hep) 348110395Scharnier errx(1, "can't get addr for %s", servername); 34913572Spst bcopy(hep->h_addr, (char *)&server_ipa, sizeof(server_ipa)); 35013572Spst } 35113572Spst 35213572Spst if (standalone) { 35313572Spst /* 35413572Spst * Go into background and disassociate from controlling terminal. 35513572Spst * XXX - This is not the POSIX way (Should use setsid). -gwr 35613572Spst */ 35713572Spst if (debug < 3) { 35813572Spst if (fork()) 35913572Spst exit(0); 36013572Spst#ifdef NO_SETSID 36113572Spst setpgrp(0,0); 36213572Spst#ifdef TIOCNOTTY 36369793Sobrien n = open(_PATH_TTY, O_RDWR); 36413572Spst if (n >= 0) { 36513572Spst ioctl(n, TIOCNOTTY, (char *) 0); 36613572Spst (void) close(n); 36713572Spst } 36813572Spst#endif /* TIOCNOTTY */ 36913572Spst#else /* SETSID */ 37013572Spst if (setsid() < 0) 37113572Spst perror("setsid"); 37213572Spst#endif /* SETSID */ 37313572Spst } /* if debug < 3 */ 37413572Spst /* 37513572Spst * Nuke any timeout value 37613572Spst */ 37713572Spst timeout = NULL; 37813572Spst 37913572Spst /* 38013572Spst * Here, bootpd would do: 38113572Spst * chdir 38213572Spst * tzone_init 38313572Spst * rdtab_init 38413572Spst * readtab 38513572Spst */ 38613572Spst 38713572Spst /* 38813572Spst * Create a socket. 38913572Spst */ 39013572Spst if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 39113572Spst report(LOG_ERR, "socket: %s", get_network_errmsg()); 39213572Spst exit(1); 39313572Spst } 39413572Spst /* 39513572Spst * Get server's listening port number 39613572Spst */ 39713572Spst servp = getservbyname("bootps", "udp"); 39813572Spst if (servp) { 39913572Spst bootps_port = ntohs((u_short) servp->s_port); 40013572Spst } else { 40113572Spst bootps_port = (u_short) IPPORT_BOOTPS; 40213572Spst report(LOG_ERR, 403110395Scharnier "bootps/udp: unknown service -- using port %d", 40413572Spst bootps_port); 40513572Spst } 40613572Spst 40713572Spst /* 40813572Spst * Bind socket to BOOTPS port. 40913572Spst */ 41013572Spst bind_addr.sin_family = AF_INET; 41113572Spst bind_addr.sin_port = htons(bootps_port); 41213572Spst bind_addr.sin_addr.s_addr = INADDR_ANY; 41313572Spst if (bind(s, (struct sockaddr *) &bind_addr, 41413572Spst sizeof(bind_addr)) < 0) 41513572Spst { 41613572Spst report(LOG_ERR, "bind: %s", get_network_errmsg()); 41713572Spst exit(1); 41813572Spst } 41913572Spst } /* if standalone */ 42013572Spst /* 42113572Spst * Get destination port number so we can reply to client 42213572Spst */ 42313572Spst servp = getservbyname("bootpc", "udp"); 42413572Spst if (servp) { 42513572Spst bootpc_port = ntohs(servp->s_port); 42613572Spst } else { 42713572Spst report(LOG_ERR, 428110395Scharnier "bootpc/udp: unknown service -- using port %d", 42913572Spst IPPORT_BOOTPC); 43013572Spst bootpc_port = (u_short) IPPORT_BOOTPC; 43113572Spst } 43213572Spst 43313572Spst /* no signal catchers */ 43413572Spst 43513572Spst /* 43613572Spst * Process incoming requests. 43713572Spst */ 43813572Spst for (;;) { 43913572Spst struct timeval tv; 44013572Spst 44113572Spst readfds = 1 << s; 44213572Spst if (timeout) 44313572Spst tv = *timeout; 44413572Spst 44513572Spst nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, 44613572Spst (timeout) ? &tv : NULL); 44713572Spst if (nfound < 0) { 44813572Spst if (errno != EINTR) { 44913572Spst report(LOG_ERR, "select: %s", get_errmsg()); 45013572Spst } 45113572Spst continue; 45213572Spst } 45313572Spst if (!(readfds & (1 << s))) { 45413572Spst report(LOG_INFO, "exiting after %ld minutes of inactivity", 455228581Sdim (long)(actualtimeout.tv_sec / 60)); 45613572Spst exit(0); 45713572Spst } 45813572Spst ra_len = sizeof(recv_addr); 45913572Spst n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0, 46013572Spst (struct sockaddr *) &recv_addr, &ra_len); 46113572Spst if (n <= 0) { 46213572Spst continue; 46313572Spst } 46413572Spst if (debug > 3) { 46513572Spst report(LOG_INFO, "recvd pkt from IP addr %s", 46613572Spst inet_ntoa(recv_addr.sin_addr)); 46713572Spst } 46813572Spst if (n < sizeof(struct bootp)) { 46913572Spst if (debug) { 47013572Spst report(LOG_INFO, "received short packet"); 47113572Spst } 47213572Spst continue; 47313572Spst } 47413572Spst pktlen = n; 47513572Spst 47613572Spst switch (bp->bp_op) { 47713572Spst case BOOTREQUEST: 47813572Spst handle_request(); 47913572Spst break; 48013572Spst case BOOTREPLY: 48113572Spst handle_reply(); 48213572Spst break; 48313572Spst } 48413572Spst } 48546078Simp return 0; 48613572Spst} 48713572Spst 48813572Spst 48913572Spst 49013572Spst 49113572Spst/* 49213572Spst * Print "usage" message and exit 49313572Spst */ 49413572Spst 49513572Spststatic void 49613572Spstusage() 49713572Spst{ 49813572Spst fprintf(stderr, 49913572Spst "usage: bootpgw [-d level] [-i] [-s] [-t timeout] server\n"); 50013572Spst fprintf(stderr, "\t -d n\tset debug level\n"); 50113572Spst fprintf(stderr, "\t -h n\tset max hop count\n"); 50213572Spst fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n"); 50313572Spst fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n"); 50413572Spst fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n"); 50513572Spst fprintf(stderr, "\t -w n\tset min wait time (secs)\n"); 50613572Spst exit(1); 50713572Spst} 50813572Spst 50913572Spst 51013572Spst 51113572Spst/* 51213572Spst * Process BOOTREQUEST packet. 51313572Spst * 51413572Spst * Note, this just forwards the request to a real server. 51513572Spst */ 51613572Spststatic void 51713572Spsthandle_request() 51813572Spst{ 51913572Spst struct bootp *bp = (struct bootp *) pktbuf; 52022413Sjkh u_short secs; 52122413Sjkh u_char hops; 52213572Spst 52313572Spst /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */ 52413572Spst 52513572Spst if (debug) { 52613572Spst report(LOG_INFO, "request from %s", 52713572Spst inet_ntoa(recv_addr.sin_addr)); 52813572Spst } 52913572Spst /* Has the client been waiting long enough? */ 53013572Spst secs = ntohs(bp->bp_secs); 53113572Spst if (secs < minwait) 53213572Spst return; 53313572Spst 53413572Spst /* Has this packet hopped too many times? */ 53522413Sjkh hops = bp->bp_hops; 53613572Spst if (++hops > maxhops) { 537229780Suqs report(LOG_NOTICE, "request from %s reached hop limit", 53813572Spst inet_ntoa(recv_addr.sin_addr)); 53913572Spst return; 54013572Spst } 54122413Sjkh bp->bp_hops = hops; 54213572Spst 54313572Spst /* 54413572Spst * Here one might discard a request from the same subnet as the 54513572Spst * real server, but we can assume that the real server will send 54613572Spst * a reply to the client before it waits for minwait seconds. 54713572Spst */ 54813572Spst 54913572Spst /* If gateway address is not set, put in local interface addr. */ 55013572Spst if (bp->bp_giaddr.s_addr == 0) { 55113572Spst#if 0 /* BUG */ 55213572Spst struct sockaddr_in *sip; 55313572Spst struct ifreq *ifr; 55413572Spst /* 55513572Spst * XXX - This picks the wrong interface when the receive addr 55613572Spst * is the broadcast address. There is no portable way to 55713572Spst * find out which interface a broadcast was received on. -gwr 55813572Spst * (Thanks to <walker@zk3.dec.com> for finding this bug!) 55913572Spst */ 56013572Spst ifr = getif(s, &recv_addr.sin_addr); 56113572Spst if (!ifr) { 56213572Spst report(LOG_NOTICE, "no interface for request from %s", 56313572Spst inet_ntoa(recv_addr.sin_addr)); 56413572Spst return; 56513572Spst } 56613572Spst sip = (struct sockaddr_in *) &(ifr->ifr_addr); 56713572Spst bp->bp_giaddr = sip->sin_addr; 56813572Spst#else /* BUG */ 56913572Spst /* 57013572Spst * XXX - Just set "giaddr" to our "official" IP address. 57113572Spst * RFC 1532 says giaddr MUST be set to the address of the 57213572Spst * interface on which the request was received. Setting 57313572Spst * it to our "default" IP address is not strictly correct, 57413572Spst * but is good enough to allow the real BOOTP server to 57513572Spst * get the reply back here. Then, before we forward the 57613572Spst * reply to the client, the giaddr field is corrected. 57713572Spst * (In case the client uses giaddr, which it should not.) 57813572Spst * See handle_reply() 57913572Spst */ 58013572Spst bp->bp_giaddr = my_ip_addr; 58113572Spst#endif /* BUG */ 58213572Spst 58313572Spst /* 58413572Spst * XXX - DHCP says to insert a subnet mask option into the 58513572Spst * options area of the request (if vendor magic == std). 58613572Spst */ 58713572Spst } 58813572Spst /* Set up socket address for send. */ 58913572Spst send_addr.sin_family = AF_INET; 59013572Spst send_addr.sin_port = htons(bootps_port); 59113572Spst send_addr.sin_addr.s_addr = server_ipa; 59213572Spst 59313572Spst /* Send reply with same size packet as request used. */ 59413572Spst if (sendto(s, pktbuf, pktlen, 0, 59513572Spst (struct sockaddr *) &send_addr, 59613572Spst sizeof(send_addr)) < 0) 59713572Spst { 59813572Spst report(LOG_ERR, "sendto: %s", get_network_errmsg()); 59913572Spst } 60013572Spst} 60113572Spst 60213572Spst 60313572Spst 60413572Spst/* 60513572Spst * Process BOOTREPLY packet. 60613572Spst */ 60713572Spststatic void 60813572Spsthandle_reply() 60913572Spst{ 61013572Spst struct bootp *bp = (struct bootp *) pktbuf; 61113572Spst struct ifreq *ifr; 61213572Spst struct sockaddr_in *sip; 61313572Spst unsigned char *ha; 61413572Spst int len, haf; 61513572Spst 61613572Spst if (debug) { 61713572Spst report(LOG_INFO, " reply for %s", 61813572Spst inet_ntoa(bp->bp_yiaddr)); 61913572Spst } 62013572Spst /* Make sure client is directly accessible. */ 62113572Spst ifr = getif(s, &(bp->bp_yiaddr)); 62213572Spst if (!ifr) { 62313572Spst report(LOG_NOTICE, "no interface for reply to %s", 62413572Spst inet_ntoa(bp->bp_yiaddr)); 62513572Spst return; 62613572Spst } 62713572Spst#if 1 /* Experimental (see BUG above) */ 62813572Spst/* #ifdef CATER_TO_OLD_CLIENTS ? */ 62913572Spst /* 63013572Spst * The giaddr field has been set to our "default" IP address 63113572Spst * which might not be on the same interface as the client. 63213572Spst * In case the client looks at giaddr, (which it should not) 63313572Spst * giaddr is now set to the address of the correct interface. 63413572Spst */ 63513572Spst sip = (struct sockaddr_in *) &(ifr->ifr_addr); 63613572Spst bp->bp_giaddr = sip->sin_addr; 63713572Spst#endif 63813572Spst 63913572Spst /* Set up socket address for send to client. */ 64013572Spst send_addr.sin_family = AF_INET; 64113572Spst send_addr.sin_addr = bp->bp_yiaddr; 64213572Spst send_addr.sin_port = htons(bootpc_port); 64313572Spst 64413572Spst /* Create an ARP cache entry for the client. */ 64513572Spst ha = bp->bp_chaddr; 64613572Spst len = bp->bp_hlen; 64713572Spst if (len > MAXHADDRLEN) 64813572Spst len = MAXHADDRLEN; 64913572Spst haf = (int) bp->bp_htype; 65013572Spst if (haf == 0) 65113572Spst haf = HTYPE_ETHERNET; 65213572Spst 65313572Spst if (debug > 1) 65413572Spst report(LOG_INFO, "setarp %s - %s", 65513572Spst inet_ntoa(bp->bp_yiaddr), haddrtoa(ha, len)); 65613572Spst setarp(s, &bp->bp_yiaddr, haf, ha, len); 65713572Spst 65813572Spst /* Send reply with same size packet as request used. */ 65913572Spst if (sendto(s, pktbuf, pktlen, 0, 66013572Spst (struct sockaddr *) &send_addr, 66113572Spst sizeof(send_addr)) < 0) 66213572Spst { 66313572Spst report(LOG_ERR, "sendto: %s", get_network_errmsg()); 66413572Spst } 66513572Spst} 66613572Spst 66713572Spst/* 66813572Spst * Local Variables: 66913572Spst * tab-width: 4 67013572Spst * c-indent-level: 4 67113572Spst * c-argdecl-indent: 4 67213572Spst * c-continued-statement-offset: 4 67313572Spst * c-continued-brace-offset: -4 67413572Spst * c-label-offset: -4 67513572Spst * c-brace-offset: 0 67613572Spst * End: 67713572Spst */ 678