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