rarpd.c revision 1.9
1/*	$NetBSD: rarpd.c,v 1.9 1995/11/17 09:54:49 thorpej Exp $	*/
2
3/*
4 * Copyright (c) 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that: (1) source code distributions
9 * retain the above copyright notice and this paragraph in its entirety, (2)
10 * distributions including binary code include the above copyright notice and
11 * this paragraph in its entirety in the documentation or other materials
12 * provided with the distribution, and (3) all advertising materials mentioning
13 * features or use of this software display the following acknowledgement:
14 * ``This product includes software developed by the University of California,
15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16 * the University nor the names of its contributors may be used to endorse
17 * or promote products derived from this software without specific prior
18 * written permission.
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 */
23#ifndef lint
24char    copyright[] =
25"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
26 All rights reserved.\n";
27#endif				/* not lint */
28
29#ifndef lint
30static char rcsid[] = "$NetBSD: rarpd.c,v 1.9 1995/11/17 09:54:49 thorpej Exp $";
31#endif
32
33
34/*
35 * rarpd - Reverse ARP Daemon
36 *
37 * Usage:	rarpd -a [ -d -f ]
38 *		rarpd [ -d -f ] interface
39 */
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <syslog.h>
44#include <string.h>
45#include <strings.h>
46#include <sys/types.h>
47#include <unistd.h>
48#include <sys/time.h>
49#include <net/bpf.h>
50#include <sys/socket.h>
51#include <sys/ioctl.h>
52#include <net/if.h>
53#include <net/if_dl.h>
54#include <net/if_types.h>
55#include <netinet/in.h>
56#include <netinet/if_ether.h>
57#include <sys/errno.h>
58#include <sys/file.h>
59#include <netdb.h>
60#include <arpa/inet.h>
61#include <dirent.h>
62
63#define FATAL		1	/* fatal error occurred */
64#define NONFATAL	0	/* non fatal error occurred */
65
66/*
67 * The structure for each interface.
68 */
69struct if_info {
70	int     ii_fd;		/* BPF file descriptor */
71	u_char  ii_eaddr[6];	/* Ethernet address of this interface */
72	u_long  ii_ipaddr;	/* IP address of this interface */
73	u_long  ii_netmask;	/* subnet or net mask */
74	struct if_info *ii_next;
75};
76/*
77 * The list of all interfaces that are being listened to.  rarp_loop()
78 * "selects" on the descriptors in this list.
79 */
80struct if_info *iflist;
81
82int    rarp_open     __P((char *));
83void   init_one      __P((char *));
84void   init_all      __P((void));
85void   rarp_loop     __P((void));
86void   lookup_eaddr  __P((char *, u_char *));
87void   lookup_ipaddr __P((char *, u_long *, u_long *));
88void   usage         __P((void));
89void   rarp_process  __P((struct if_info *, u_char *));
90void   rarp_reply    __P((struct if_info *, struct ether_header *, u_long));
91void   update_arptab __P((u_char *, u_long));
92void   err           __P((int, const char *,...));
93void   debug         __P((const char *,...));
94u_long ipaddrtonetmask __P((u_long));
95
96#ifdef REQUIRE_TFTPBOOT
97int    rarp_bootable __P((u_long));
98#endif
99
100int     aflag = 0;		/* listen on "all" interfaces  */
101int     dflag = 0;		/* print debugging messages */
102int     fflag = 0;		/* don't fork */
103
104void
105main(argc, argv)
106	int     argc;
107	char  **argv;
108{
109	int     op, pid, devnull, f;
110	char   *ifname, *hostname, *name;
111
112	extern char *optarg;
113	extern int optind, opterr;
114
115	if (name = strrchr(argv[0], '/'))
116		++name;
117	else
118		name = argv[0];
119	if (*name == '-')
120		++name;
121
122	/* All error reporting is done through syslogs. */
123	openlog(name, LOG_PID | LOG_CONS, LOG_DAEMON);
124
125	opterr = 0;
126	while ((op = getopt(argc, argv, "adf")) != EOF) {
127		switch (op) {
128		case 'a':
129			++aflag;
130			break;
131
132		case 'd':
133			++dflag;
134			break;
135
136		case 'f':
137			++fflag;
138			break;
139
140		default:
141			usage();
142			/* NOTREACHED */
143		}
144	}
145	ifname = argv[optind++];
146	hostname = ifname ? argv[optind] : 0;
147	if ((aflag && ifname) || (!aflag && ifname == 0))
148		usage();
149
150	if (aflag)
151		init_all();
152	else
153		init_one(ifname);
154
155	if ((!fflag) && (!dflag)) {
156		pid = fork();
157		if (pid > 0)
158			/* Parent exits, leaving child in background. */
159			exit(0);
160		else
161			if (pid == -1) {
162				err(FATAL, "cannot fork");
163				/* NOTREACHED */
164			}
165		/* Fade into the background */
166		f = open("/dev/tty", O_RDWR);
167		if (f >= 0) {
168			if (ioctl(f, TIOCNOTTY, 0) < 0) {
169				err(FATAL, "TIOCNOTTY: %s", strerror(errno));
170				/* NOTREACHED */
171			}
172			(void) close(f);
173		}
174		(void) chdir("/");
175		(void) setpgrp(0, getpid());
176		devnull = open("/dev/null", O_RDWR);
177		if (devnull >= 0) {
178			(void) dup2(devnull, 0);
179			(void) dup2(devnull, 1);
180			(void) dup2(devnull, 2);
181			if (devnull > 2)
182				(void) close(devnull);
183		}
184	}
185	rarp_loop();
186}
187/*
188 * Add 'ifname' to the interface list.  Lookup its IP address and network
189 * mask and Ethernet address, and open a BPF file for it.
190 */
191void
192init_one(ifname)
193	char   *ifname;
194{
195	struct if_info *p;
196
197	p = (struct if_info *)malloc(sizeof(*p));
198	if (p == 0) {
199		err(FATAL, "malloc: %s", strerror(errno));
200		/* NOTREACHED */
201	}
202	p->ii_next = iflist;
203	iflist = p;
204
205	p->ii_fd = rarp_open(ifname);
206	lookup_eaddr(ifname, p->ii_eaddr);
207	lookup_ipaddr(ifname, &p->ii_ipaddr, &p->ii_netmask);
208}
209/*
210 * Initialize all "candidate" interfaces that are in the system
211 * configuration list.  A "candidate" is up, not loopback and not
212 * point to point.
213 */
214void
215init_all()
216{
217	char inbuf[8192];
218	struct ifconf ifc;
219	struct ifreq *ifr;
220	int fd;
221	int i, len;
222
223	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
224		err(FATAL, "socket: %s", strerror(errno));
225		/* NOTREACHED */
226	}
227
228	ifc.ifc_len = sizeof(inbuf);
229	ifc.ifc_buf = inbuf;
230	if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
231	    ifc.ifc_len < sizeof(struct ifreq)) {
232		err(FATAL, "init_all: SIOCGIFCONF: %s", strerror(errno));
233		/* NOTREACHED */
234	}
235	ifr = ifc.ifc_req;
236	for (i = 0; i < ifc.ifc_len;
237	     i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
238		len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
239		if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
240			err(FATAL, "init_all: SIOCGIFFLAGS: %s",
241			    strerror(errno));
242			/* NOTREACHED */
243		}
244		if ((ifr->ifr_flags &
245		    (IFF_UP | IFF_LOOPBACK | IFF_POINTOPOINT)) != IFF_UP)
246			continue;
247		init_one(ifr->ifr_name);
248	}
249	(void) close(fd);
250}
251
252void
253usage()
254{
255	(void) fprintf(stderr, "usage: rarpd -a [ -d -f ]\n");
256	(void) fprintf(stderr, "       rarpd [ -d -f ] interface\n");
257	exit(1);
258}
259
260static int
261bpf_open()
262{
263	int     fd;
264	int     n = 0;
265	char    device[sizeof "/dev/bpf000"];
266
267	/* Go through all the minors and find one that isn't in use. */
268	do {
269		(void) sprintf(device, "/dev/bpf%d", n++);
270		fd = open(device, O_RDWR);
271	} while (fd < 0 && errno == EBUSY);
272
273	if (fd < 0) {
274		err(FATAL, "%s: %s", device, strerror(errno));
275		/* NOTREACHED */
276	}
277	return fd;
278}
279/*
280 * Open a BPF file and attach it to the interface named 'device'.
281 * Set immediate mode, and set a filter that accepts only RARP requests.
282 */
283int
284rarp_open(device)
285	char   *device;
286{
287	int     fd;
288	struct ifreq ifr;
289	u_int   dlt;
290	int     immediate;
291
292	static struct bpf_insn insns[] = {
293		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12),
294		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_REVARP, 0, 3),
295		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 20),
296		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ARPOP_REVREQUEST, 0, 1),
297		BPF_STMT(BPF_RET | BPF_K, sizeof(struct ether_arp) +
298		    sizeof(struct ether_header)),
299		BPF_STMT(BPF_RET | BPF_K, 0),
300	};
301	static struct bpf_program filter = {
302		sizeof insns / sizeof(insns[0]),
303		insns
304	};
305
306	fd = bpf_open();
307
308	/* Set immediate mode so packets are processed as they arrive. */
309	immediate = 1;
310	if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) {
311		err(FATAL, "BIOCIMMEDIATE: %s", strerror(errno));
312		/* NOTREACHED */
313	}
314	(void) strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
315	if (ioctl(fd, BIOCSETIF, (caddr_t) & ifr) < 0) {
316		err(FATAL, "BIOCSETIF: %s", strerror(errno));
317		/* NOTREACHED */
318	}
319	/* Check that the data link layer is an Ethernet; this code won't work
320	 * with anything else. */
321	if (ioctl(fd, BIOCGDLT, (caddr_t) & dlt) < 0) {
322		err(FATAL, "BIOCGDLT: %s", strerror(errno));
323		/* NOTREACHED */
324	}
325	if (dlt != DLT_EN10MB) {
326		err(FATAL, "%s is not an ethernet", device);
327		/* NOTREACHED */
328	}
329	/* Set filter program. */
330	if (ioctl(fd, BIOCSETF, (caddr_t) & filter) < 0) {
331		err(FATAL, "BIOCSETF: %s", strerror(errno));
332		/* NOTREACHED */
333	}
334	return fd;
335}
336/*
337 * Perform various sanity checks on the RARP request packet.  Return
338 * false on failure and log the reason.
339 */
340static int
341rarp_check(p, len)
342	u_char *p;
343	int     len;
344{
345	struct ether_header *ep = (struct ether_header *) p;
346	struct ether_arp *ap = (struct ether_arp *) (p + sizeof(*ep));
347
348	(void) debug("got a packet");
349
350	if (len < sizeof(*ep) + sizeof(*ap)) {
351		err(NONFATAL, "truncated request");
352		return 0;
353	}
354	/* XXX This test might be better off broken out... */
355	if (ntohs (ep->ether_type) != ETHERTYPE_REVARP ||
356	    ntohs (ap->arp_hrd) != ARPHRD_ETHER ||
357	    ntohs (ap->arp_op) != ARPOP_REVREQUEST ||
358	    ntohs (ap->arp_pro) != ETHERTYPE_IP ||
359	    ap->arp_hln != 6 || ap->arp_pln != 4) {
360		err(NONFATAL, "request fails sanity check");
361		return 0;
362	}
363	if (bcmp((char *) &ep->ether_shost, (char *) &ap->arp_sha, 6) != 0) {
364		err(NONFATAL, "ether/arp sender address mismatch");
365		return 0;
366	}
367	if (bcmp((char *) &ap->arp_sha, (char *) &ap->arp_tha, 6) != 0) {
368		err(NONFATAL, "ether/arp target address mismatch");
369		return 0;
370	}
371	return 1;
372}
373
374/*
375 * Loop indefinitely listening for RARP requests on the
376 * interfaces in 'iflist'.
377 */
378void
379rarp_loop()
380{
381	u_char *buf, *bp, *ep;
382	int     cc, fd;
383	fd_set  fds, listeners;
384	int     bufsize, maxfd = 0;
385	struct if_info *ii;
386
387	if (iflist == 0) {
388		err(FATAL, "no interfaces");
389		/* NOTREACHED */
390	}
391	if (ioctl(iflist->ii_fd, BIOCGBLEN, (caddr_t) & bufsize) < 0) {
392		err(FATAL, "BIOCGBLEN: %s", strerror(errno));
393		/* NOTREACHED */
394	}
395	buf = (u_char *) malloc((unsigned) bufsize);
396	if (buf == 0) {
397		err(FATAL, "malloc: %s", strerror(errno));
398		/* NOTREACHED */
399	}
400	/*
401         * Find the highest numbered file descriptor for select().
402         * Initialize the set of descriptors to listen to.
403         */
404	FD_ZERO(&fds);
405	for (ii = iflist; ii; ii = ii->ii_next) {
406		FD_SET(ii->ii_fd, &fds);
407		if (ii->ii_fd > maxfd)
408			maxfd = ii->ii_fd;
409	}
410	while (1) {
411		listeners = fds;
412		if (select(maxfd + 1, &listeners, (struct fd_set *) 0,
413			(struct fd_set *) 0, (struct timeval *) 0) < 0) {
414			err(FATAL, "select: %s", strerror(errno));
415			/* NOTREACHED */
416		}
417		for (ii = iflist; ii; ii = ii->ii_next) {
418			fd = ii->ii_fd;
419			if (!FD_ISSET(fd, &listeners))
420				continue;
421	again:
422			cc = read(fd, (char *) buf, bufsize);
423			/* Don't choke when we get ptraced */
424			if (cc < 0 && errno == EINTR)
425				goto again;
426			/* Due to a SunOS bug, after 2^31 bytes, the file
427			 * offset overflows and read fails with EINVAL.  The
428			 * lseek() to 0 will fix things. */
429			if (cc < 0) {
430				if (errno == EINVAL &&
431				    (lseek(fd, 0, SEEK_CUR) + bufsize) < 0) {
432					(void) lseek(fd, 0, 0);
433					goto again;
434				}
435				err(FATAL, "read: %s", strerror(errno));
436				/* NOTREACHED */
437			}
438			/* Loop through the packet(s) */
439#define bhp ((struct bpf_hdr *)bp)
440			bp = buf;
441			ep = bp + cc;
442			while (bp < ep) {
443				register int caplen, hdrlen;
444
445				caplen = bhp->bh_caplen;
446				hdrlen = bhp->bh_hdrlen;
447				if (rarp_check(bp + hdrlen, caplen))
448					rarp_process(ii, bp + hdrlen);
449				bp += BPF_WORDALIGN(hdrlen + caplen);
450			}
451		}
452	}
453}
454
455#ifdef REQUIRE_TFTPBOOT
456
457#ifndef TFTP_DIR
458#define TFTP_DIR "/tftpboot"
459#endif
460
461/*
462 * True if this server can boot the host whose IP address is 'addr'.
463 * This check is made by looking in the tftp directory for the
464 * configuration file.
465 */
466int
467rarp_bootable(addr)
468	u_long  addr;
469{
470	register struct dirent *dent;
471	register DIR *d;
472	char    ipname[9];
473	static DIR *dd = 0;
474
475	(void) sprintf(ipname, "%08X", addr);
476	/* If directory is already open, rewind it.  Otherwise, open it. */
477	if (d = dd)
478		rewinddir(d);
479	else {
480		if (chdir(TFTP_DIR) == -1) {
481			err(FATAL, "chdir: %s", strerror(errno));
482			/* NOTREACHED */
483		}
484		d = opendir(".");
485		if (d == 0) {
486			err(FATAL, "opendir: %s", strerror(errno));
487			/* NOTREACHED */
488		}
489		dd = d;
490	}
491	while (dent = readdir(d))
492		if (strncmp(dent->d_name, ipname, 8) == 0)
493			return 1;
494	return 0;
495}
496#endif /* REQUIRE_TFTPBOOT */
497
498/*
499 * Given a list of IP addresses, 'alist', return the first address that
500 * is on network 'net'; 'netmask' is a mask indicating the network portion
501 * of the address.
502 */
503u_long
504choose_ipaddr(alist, net, netmask)
505	u_long **alist;
506	u_long  net;
507	u_long  netmask;
508{
509	for (; *alist; ++alist) {
510		if ((**alist & netmask) == net)
511			return **alist;
512	}
513	return 0;
514}
515/*
516 * Answer the RARP request in 'pkt', on the interface 'ii'.  'pkt' has
517 * already been checked for validity.  The reply is overlaid on the request.
518 */
519void
520rarp_process(ii, pkt)
521	struct if_info *ii;
522	u_char *pkt;
523{
524	struct ether_header *ep;
525	struct hostent *hp;
526	u_long  target_ipaddr;
527	char    ename[256];
528	struct	in_addr in;
529
530	ep = (struct ether_header *) pkt;
531
532	if (ether_ntohost(ename, &ep->ether_shost) != 0 ||
533	    (hp = gethostbyname(ename)) == 0)
534		return;
535
536	/* Choose correct address from list. */
537	if (hp->h_addrtype != AF_INET) {
538		err(FATAL, "cannot handle non IP addresses");
539		/* NOTREACHED */
540	}
541	target_ipaddr = choose_ipaddr((u_long **) hp->h_addr_list,
542	    ii->ii_ipaddr & ii->ii_netmask, ii->ii_netmask);
543
544	if (target_ipaddr == 0) {
545		in.s_addr = ii->ii_ipaddr & ii->ii_netmask;
546		err(NONFATAL, "cannot find %s on net %s\n",
547		    ename, inet_ntoa(in));
548		return;
549	}
550#ifdef REQUIRE_TFTPBOOT
551	if (rarp_bootable(htonl(target_ipaddr)))
552#endif
553		rarp_reply(ii, ep, target_ipaddr);
554}
555/*
556 * Lookup the ethernet address of the interface attached to the BPF
557 * file descriptor 'fd'; return it in 'eaddr'.
558 */
559void
560lookup_eaddr(ifname, eaddr)
561	char *ifname;
562	u_char *eaddr;
563{
564	char inbuf[8192];
565	struct ifconf ifc;
566	struct ifreq *ifr;
567	struct sockaddr_dl *sdl;
568	int fd;
569	int i, len;
570
571	/* We cannot use SIOCGIFADDR on the BPF descriptor.
572	   We must instead get all the interfaces with SIOCGIFCONF
573	   and find the right one.  */
574
575	/* Use datagram socket to get Ethernet address. */
576	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
577		err(FATAL, "socket: %s", strerror(errno));
578		/* NOTREACHED */
579	}
580
581	ifc.ifc_len = sizeof(inbuf);
582	ifc.ifc_buf = inbuf;
583	if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
584	    ifc.ifc_len < sizeof(struct ifreq)) {
585		err(FATAL, "lookup_eaddr: SIOGIFCONF: %s", strerror(errno));
586		/* NOTREACHED */
587	}
588	ifr = ifc.ifc_req;
589	for (i = 0; i < ifc.ifc_len;
590	     i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
591		len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
592		sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
593		if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER ||
594		    sdl->sdl_alen != 6)
595			continue;
596		if (!strncmp(ifr->ifr_name, ifname, sizeof(ifr->ifr_name))) {
597			bcopy((caddr_t)LLADDR(sdl), (caddr_t)eaddr, 6);
598			if (dflag)
599				fprintf(stderr, "%s: %x:%x:%x:%x:%x:%x\n",
600				    ifr->ifr_name, eaddr[0], eaddr[1],
601				    eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
602			return;
603		}
604	}
605
606	err(FATAL, "lookup_eaddr: Never saw interface `%s'!", ifname);
607}
608/*
609 * Lookup the IP address and network mask of the interface named 'ifname'.
610 */
611void
612lookup_ipaddr(ifname, addrp, netmaskp)
613	char   *ifname;
614	u_long *addrp;
615	u_long *netmaskp;
616{
617	int     fd;
618	struct ifreq ifr;
619
620	/* Use datagram socket to get IP address. */
621	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
622		err(FATAL, "socket: %s", strerror(errno));
623		/* NOTREACHED */
624	}
625	(void) strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
626	if (ioctl(fd, SIOCGIFADDR, (char *) &ifr) < 0) {
627		err(FATAL, "SIOCGIFADDR: %s", strerror(errno));
628		/* NOTREACHED */
629	}
630	*addrp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr;
631	if (ioctl(fd, SIOCGIFNETMASK, (char *) &ifr) < 0) {
632		perror("SIOCGIFNETMASK");
633		exit(1);
634	}
635	*netmaskp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr;
636	/* If SIOCGIFNETMASK didn't work, figure out a mask from the IP
637	 * address class. */
638	if (*netmaskp == 0)
639		*netmaskp = ipaddrtonetmask(*addrp);
640
641	(void) close(fd);
642}
643/*
644 * Poke the kernel arp tables with the ethernet/ip address combinataion
645 * given.  When processing a reply, we must do this so that the booting
646 * host (i.e. the guy running rarpd), won't try to ARP for the hardware
647 * address of the guy being booted (he cannot answer the ARP).
648 */
649void
650update_arptab(ep, ipaddr)
651	u_char *ep;
652	u_long  ipaddr;
653{
654	int     s;
655	struct arpreq request;
656	struct sockaddr_in *sin;
657
658	request.arp_flags = 0;
659	sin = (struct sockaddr_in *) & request.arp_pa;
660	sin->sin_family = AF_INET;
661	sin->sin_addr.s_addr = ipaddr;
662	request.arp_ha.sa_family = AF_UNSPEC;
663	/* This is needed #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN,
664	   because AF_UNSPEC is zero and the kernel assumes that a zero
665	   sa_family means that the real sa_family value is in sa_len.  */
666	request.arp_ha.sa_len = 16; /* XXX */
667	bcopy((char *) ep, (char *) request.arp_ha.sa_data, 6);
668
669#if 0
670	s = socket(AF_INET, SOCK_DGRAM, 0);
671	if (ioctl(s, SIOCSARP, (caddr_t) & request) < 0) {
672		err(NONFATAL, "SIOCSARP: %s", strerror(errno));
673	}
674	(void) close(s);
675#endif
676}
677/*
678 * Build a reverse ARP packet and sent it out on the interface.
679 * 'ep' points to a valid ARPOP_REVREQUEST.  The ARPOP_REVREPLY is built
680 * on top of the request, then written to the network.
681 *
682 * RFC 903 defines the ether_arp fields as follows.  The following comments
683 * are taken (more or less) straight from this document.
684 *
685 * ARPOP_REVREQUEST
686 *
687 * arp_sha is the hardware address of the sender of the packet.
688 * arp_spa is undefined.
689 * arp_tha is the 'target' hardware address.
690 *   In the case where the sender wishes to determine his own
691 *   protocol address, this, like arp_sha, will be the hardware
692 *   address of the sender.
693 * arp_tpa is undefined.
694 *
695 * ARPOP_REVREPLY
696 *
697 * arp_sha is the hardware address of the responder (the sender of the
698 *   reply packet).
699 * arp_spa is the protocol address of the responder (see the note below).
700 * arp_tha is the hardware address of the target, and should be the same as
701 *   that which was given in the request.
702 * arp_tpa is the protocol address of the target, that is, the desired address.
703 *
704 * Note that the requirement that arp_spa be filled in with the responder's
705 * protocol is purely for convenience.  For instance, if a system were to use
706 * both ARP and RARP, then the inclusion of the valid protocol-hardware
707 * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent
708 * ARP request.
709 */
710void
711rarp_reply(ii, ep, ipaddr)
712	struct if_info *ii;
713	struct ether_header *ep;
714	u_long  ipaddr;
715{
716	int     n;
717	struct ether_arp *ap = (struct ether_arp *) (ep + 1);
718	int     len;
719
720	update_arptab((u_char *) & ap->arp_sha, ipaddr);
721
722	/* Build the rarp reply by modifying the rarp request in place. */
723	ep->ether_type = htons(ETHERTYPE_REVARP);
724	ap->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
725	ap->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
726	ap->arp_op = htons(ARPOP_REVREPLY);
727
728	bcopy((char *) &ap->arp_sha, (char *) &ep->ether_dhost, 6);
729	bcopy((char *) ii->ii_eaddr, (char *) &ep->ether_shost, 6);
730	bcopy((char *) ii->ii_eaddr, (char *) &ap->arp_sha, 6);
731
732	bcopy((char *) &ipaddr, (char *) ap->arp_tpa, 4);
733	/* Target hardware is unchanged. */
734	bcopy((char *) &ii->ii_ipaddr, (char *) ap->arp_spa, 4);
735
736	len = sizeof(*ep) + sizeof(*ap);
737	n = write(ii->ii_fd, (char *) ep, len);
738	if (n != len) {
739		err(NONFATAL, "write: only %d of %d bytes written", n, len);
740	}
741}
742/*
743 * Get the netmask of an IP address.  This routine is used if
744 * SIOCGIFNETMASK doesn't work.
745 */
746u_long
747ipaddrtonetmask(addr)
748	u_long  addr;
749{
750	if (IN_CLASSA(addr))
751		return IN_CLASSA_NET;
752	if (IN_CLASSB(addr))
753		return IN_CLASSB_NET;
754	if (IN_CLASSC(addr))
755		return IN_CLASSC_NET;
756	err(FATAL, "unknown IP address class: %08X", addr);
757	/* NOTREACHED */
758}
759
760#if __STDC__
761#include <stdarg.h>
762#else
763#include <varargs.h>
764#endif
765
766void
767#if __STDC__
768err(int fatal, const char *fmt,...)
769#else
770err(fmt, va_alist)
771	int     fatal;
772	char   *fmt;
773va_dcl
774#endif
775{
776	va_list ap;
777#if __STDC__
778	va_start(ap, fmt);
779#else
780	va_start(ap);
781#endif
782	if (dflag) {
783		if (fatal)
784			(void) fprintf(stderr, "rarpd: error: ");
785		else
786			(void) fprintf(stderr, "rarpd: warning: ");
787		(void) vfprintf(stderr, fmt, ap);
788		(void) fprintf(stderr, "\n");
789	}
790	vsyslog(LOG_ERR, fmt, ap);
791	va_end(ap);
792	if (fatal)
793		exit(1);
794	/* NOTREACHED */
795}
796
797void
798#if __STDC__
799debug(const char *fmt,...)
800#else
801debug(fmt, va_alist)
802	char   *fmt;
803va_dcl
804#endif
805{
806	va_list ap;
807
808	if (dflag) {
809#if __STDC__
810		va_start(ap, fmt);
811#else
812		va_start(ap);
813#endif
814		(void) fprintf(stderr, "rarpd: ");
815		(void) vfprintf(stderr, fmt, ap);
816		va_end(ap);
817		(void) fprintf(stderr, "\n");
818	}
819}
820