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