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