2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1990 The Regents of the University of California.
26 * All rights reserved.
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
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.
44 #include <sys/cdefs.h>
46 __unused
char copyright
[] =
47 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
48 All rights reserved.\n";
52 __unused
static char rcsid
[] =
53 "@(#) $Id: rarpd.c,v 1.3 2006/04/05 03:13:14 lindak Exp $";
58 * rarpd - Reverse ARP Daemon
60 * Usage: rarpd -a [ -d -f ]
61 * rarpd [ -d -f ] interface
69 #include <sys/types.h>
73 #include <sys/socket.h>
74 #include <sys/ioctl.h>
76 #include <net/if_dl.h>
77 #include <net/if_types.h>
78 #include <netinet/in.h>
79 #include <netinet/if_ether.h>
80 #include <sys/errno.h>
83 #include <arpa/inet.h>
86 #define FATAL 1 /* fatal error occurred */
87 #define NONFATAL 0 /* non fatal error occurred */
90 * The structure for each interface.
93 int ii_fd
; /* BPF file descriptor */
94 u_char ii_eaddr
[6]; /* Ethernet address of this interface */
95 in_addr_t ii_ipaddr
; /* IP address of this interface */
96 in_addr_t ii_netmask
; /* subnet or net mask */
97 struct if_info
*ii_next
;
100 * The list of all interfaces that are being listened to. rarp_loop()
101 * "selects" on the descriptors in this list.
103 struct if_info
*iflist
;
105 int rarp_open
__P((char *));
106 int rarp_bootable
__P((in_addr_t
));
107 void init_one
__P((char *));
108 void init_all
__P((void));
109 void rarp_loop
__P((void));
110 void lookup_eaddr
__P((char *, u_char
*));
111 void lookup_ipaddr
__P((char *, in_addr_t
*, in_addr_t
*));
112 void usage
__P((void));
113 void rarp_process
__P((struct if_info
*, u_char
*));
114 void rarp_reply
__P((struct if_info
*, struct ether_header
*, in_addr_t
));
115 void update_arptab
__P((u_char
*, in_addr_t
));
116 void err
__P((int, const char *,...));
117 void debug
__P((const char *,...));
118 in_addr_t ipaddrtonetmask
__P((in_addr_t
));
120 int aflag
= 0; /* listen on "all" interfaces */
121 int dflag
= 0; /* print debugging messages */
122 int fflag
= 0; /* don't fork */
129 int op
, pid
, devnull
, f
;
130 char *ifname
, *hostname
, *name
;
133 extern int optind
, opterr
;
135 if ((name
= strrchr(argv
[0], '/')) != NULL
)
142 /* All error reporting is done through syslogs. */
143 openlog(name
, LOG_PID
| LOG_CONS
, LOG_DAEMON
);
146 while ((op
= getopt(argc
, argv
, "adf")) != EOF
) {
165 ifname
= argv
[optind
++];
166 hostname
= ifname
? argv
[optind
] : 0;
167 if ((aflag
&& ifname
) || (!aflag
&& ifname
== 0))
175 if ((!fflag
) && (!dflag
)) {
178 /* Parent exits, leaving child in background. */
182 err(FATAL
, "cannot fork");
185 /* Fade into the background */
186 f
= open("/dev/tty", O_RDWR
);
188 if (ioctl(f
, TIOCNOTTY
, 0) < 0) {
189 err(FATAL
, "TIOCNOTTY: %s", strerror(errno
));
195 (void) setpgid(0, getpid());
196 devnull
= open("/dev/null", O_RDWR
);
198 (void) dup2(devnull
, 0);
199 (void) dup2(devnull
, 1);
200 (void) dup2(devnull
, 2);
202 (void) close(devnull
);
210 * Add 'ifname' to the interface list. Lookup its IP address and network
211 * mask and Ethernet address, and open a BPF file for it.
219 p
= (struct if_info
*)malloc(sizeof(*p
));
221 err(FATAL
, "malloc: %s", strerror(errno
));
227 p
->ii_fd
= rarp_open(ifname
);
228 lookup_eaddr(ifname
, p
->ii_eaddr
);
229 lookup_ipaddr(ifname
, &p
->ii_ipaddr
, &p
->ii_netmask
);
232 * Initialize all "candidate" interfaces that are in the system
233 * configuration list. A "candidate" is up, not loopback and not
245 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
246 err(FATAL
, "socket: %s", strerror(errno
));
250 ifc
.ifc_len
= sizeof(inbuf
);
252 if (ioctl(fd
, SIOCGIFCONF
, (caddr_t
)&ifc
) < 0 ||
253 ifc
.ifc_len
< sizeof(struct ifreq
)) {
254 err(FATAL
, "init_all: SIOCGIFCONF: %s", strerror(errno
));
258 for (i
= 0; i
< ifc
.ifc_len
;
259 i
+= len
, ifr
= (struct ifreq
*)((caddr_t
)ifr
+ len
)) {
260 len
= sizeof(ifr
->ifr_name
) + ifr
->ifr_addr
.sa_len
;
261 if (ioctl(fd
, SIOCGIFFLAGS
, (caddr_t
)ifr
) < 0) {
262 err(FATAL
, "init_all: SIOCGIFFLAGS: %s",
266 if ((ifr
->ifr_flags
&
267 (IFF_UP
| IFF_LOOPBACK
| IFF_POINTOPOINT
)) != IFF_UP
)
269 init_one(ifr
->ifr_name
);
277 (void) fprintf(stderr
, "usage: rarpd -a [ -d -f ]\n");
278 (void) fprintf(stderr
, " rarpd [ -d -f ] interface\n");
287 char device
[sizeof "/dev/bpf000"];
289 /* Go through all the minors and find one that isn't in use. */
291 (void) sprintf(device
, "/dev/bpf%d", n
++);
292 fd
= open(device
, O_RDWR
);
293 } while (fd
< 0 && errno
== EBUSY
);
296 err(FATAL
, "%s: %s", device
, strerror(errno
));
302 * Open a BPF file and attach it to the interface named 'device'.
303 * Set immediate mode, and set a filter that accepts only RARP requests.
314 static struct bpf_insn insns
[] = {
315 BPF_STMT(BPF_LD
| BPF_H
| BPF_ABS
, 12),
316 BPF_JUMP(BPF_JMP
| BPF_JEQ
| BPF_K
, ETHERTYPE_REVARP
, 0, 3),
317 BPF_STMT(BPF_LD
| BPF_H
| BPF_ABS
, 20),
318 BPF_JUMP(BPF_JMP
| BPF_JEQ
| BPF_K
, ARPOP_REVREQUEST
, 0, 1),
319 BPF_STMT(BPF_RET
| BPF_K
, sizeof(struct ether_arp
) +
320 sizeof(struct ether_header
)),
321 BPF_STMT(BPF_RET
| BPF_K
, 0),
323 static struct bpf_program filter
= {
324 sizeof insns
/ sizeof(insns
[0]),
330 /* Set immediate mode so packets are processed as they arrive. */
332 if (ioctl(fd
, BIOCIMMEDIATE
, &immediate
) < 0) {
333 err(FATAL
, "BIOCIMMEDIATE: %s", strerror(errno
));
336 (void) strncpy(ifr
.ifr_name
, device
, sizeof ifr
.ifr_name
);
337 if (ioctl(fd
, BIOCSETIF
, (caddr_t
) & ifr
) < 0) {
338 err(FATAL
, "BIOCSETIF: %s", strerror(errno
));
341 /* Check that the data link layer is an Ethernet; this code won't work
342 * with anything else. */
343 if (ioctl(fd
, BIOCGDLT
, (caddr_t
) & dlt
) < 0) {
344 err(FATAL
, "BIOCGDLT: %s", strerror(errno
));
347 if (dlt
!= DLT_EN10MB
) {
348 err(FATAL
, "%s is not an ethernet", device
);
351 /* Set filter program. */
352 if (ioctl(fd
, BIOCSETF
, (caddr_t
) & filter
) < 0) {
353 err(FATAL
, "BIOCSETF: %s", strerror(errno
));
359 * Perform various sanity checks on the RARP request packet. Return
360 * false on failure and log the reason.
367 struct ether_header
*ep
= (struct ether_header
*) p
;
368 struct ether_arp
*ap
= (struct ether_arp
*) (p
+ sizeof(*ep
));
370 (void) debug("got a packet");
372 if (len
< sizeof(*ep
) + sizeof(*ap
)) {
373 err(NONFATAL
, "truncated request");
376 /* XXX This test might be better off broken out... */
377 if (ntohs (ep
->ether_type
) != ETHERTYPE_REVARP
||
378 ntohs (ap
->arp_hrd
) != ARPHRD_ETHER
||
379 ntohs (ap
->arp_op
) != ARPOP_REVREQUEST
||
380 ntohs (ap
->arp_pro
) != ETHERTYPE_IP
||
381 ap
->arp_hln
!= 6 || ap
->arp_pln
!= 4) {
382 err(NONFATAL
, "request fails sanity check");
385 if (bcmp((char *) &ep
->ether_shost
, (char *) &ap
->arp_sha
, 6) != 0) {
386 err(NONFATAL
, "ether/arp sender address mismatch");
389 if (bcmp((char *) &ap
->arp_sha
, (char *) &ap
->arp_tha
, 6) != 0) {
390 err(NONFATAL
, "ether/arp target address mismatch");
397 * Loop indefinitely listening for RARP requests on the
398 * interfaces in 'iflist'.
403 u_char
*buf
, *bp
, *ep
;
405 fd_set fds
, listeners
;
406 int bufsize
, maxfd
= 0;
410 err(FATAL
, "no interfaces");
413 if (ioctl(iflist
->ii_fd
, BIOCGBLEN
, (caddr_t
) & bufsize
) < 0) {
414 err(FATAL
, "BIOCGBLEN: %s", strerror(errno
));
417 buf
= (u_char
*) malloc((unsigned) bufsize
);
419 err(FATAL
, "malloc: %s", strerror(errno
));
423 * Find the highest numbered file descriptor for select().
424 * Initialize the set of descriptors to listen to.
427 for (ii
= iflist
; ii
; ii
= ii
->ii_next
) {
428 FD_SET(ii
->ii_fd
, &fds
);
429 if (ii
->ii_fd
> maxfd
)
434 if (select(maxfd
+ 1, &listeners
, (struct fd_set
*) 0,
435 (struct fd_set
*) 0, (struct timeval
*) 0) < 0) {
436 err(FATAL
, "select: %s", strerror(errno
));
439 for (ii
= iflist
; ii
; ii
= ii
->ii_next
) {
441 if (!FD_ISSET(fd
, &listeners
))
444 cc
= read(fd
, (char *) buf
, bufsize
);
445 /* Don't choke when we get ptraced */
446 if (cc
< 0 && errno
== EINTR
)
448 /* Due to a SunOS bug, after 2^31 bytes, the file
449 * offset overflows and read fails with EINVAL. The
450 * lseek() to 0 will fix things. */
452 if (errno
== EINVAL
&&
453 (lseek(fd
, 0, SEEK_CUR
) + bufsize
) < 0) {
454 (void) lseek(fd
, 0, 0);
457 err(FATAL
, "read: %s", strerror(errno
));
460 /* Loop through the packet(s) */
461 #define bhp ((struct bpf_hdr *)bp)
465 register int caplen
, hdrlen
;
467 caplen
= bhp
->bh_caplen
;
468 hdrlen
= bhp
->bh_hdrlen
;
469 if (rarp_check(bp
+ hdrlen
, caplen
))
470 rarp_process(ii
, bp
+ hdrlen
);
471 bp
+= BPF_WORDALIGN(hdrlen
+ caplen
);
477 #define TFTP_DIR "/tftpboot"
481 * True if this server can boot the host whose IP address is 'addr'.
482 * This check is made by looking in the tftp directory for the
483 * configuration file.
489 register struct dirent
*dent
;
494 (void) sprintf(ipname
, "%08X", addr
);
495 /* If directory is already open, rewind it. Otherwise, open it. */
496 if ((d
= dd
) != NULL
)
499 if (chdir(TFTP_DIR
) == -1) {
500 err(FATAL
, "chdir: %s", strerror(errno
));
505 err(FATAL
, "opendir: %s", strerror(errno
));
510 while ((dent
= readdir(d
)) != NULL
)
511 if (strncmp(dent
->d_name
, ipname
, 8) == 0)
516 * Given a list of IP addresses, 'alist', return the first address that
517 * is on network 'net'; 'netmask' is a mask indicating the network portion
521 choose_ipaddr(alist
, net
, netmask
)
526 for (; *alist
; ++alist
) {
527 if ((**alist
& netmask
) == net
)
533 * Answer the RARP request in 'pkt', on the interface 'ii'. 'pkt' has
534 * already been checked for validity. The reply is overlaid on the request.
537 rarp_process(ii
, pkt
)
541 struct ether_header
*ep
;
543 in_addr_t target_ipaddr
;
547 ep
= (struct ether_header
*) pkt
;
549 if (ether_ntohost(ename
, (struct ether_addr
*)&ep
->ether_shost
) != 0 ||
550 (hp
= gethostbyname(ename
)) == 0)
553 /* Choose correct address from list. */
554 if (hp
->h_addrtype
!= AF_INET
) {
555 err(FATAL
, "cannot handle non IP addresses");
558 target_ipaddr
= choose_ipaddr((in_addr_t
**) hp
->h_addr_list
,
559 ii
->ii_ipaddr
& ii
->ii_netmask
, ii
->ii_netmask
);
561 if (target_ipaddr
== 0) {
562 in
.s_addr
= ii
->ii_ipaddr
& ii
->ii_netmask
;
563 err(NONFATAL
, "cannot find %s on net %s\n",
564 ename
, inet_ntoa(in
));
567 if (rarp_bootable(htonl(target_ipaddr
)))
568 rarp_reply(ii
, ep
, target_ipaddr
);
571 * Lookup the ethernet address of the interface attached to the BPF
572 * file descriptor 'fd'; return it in 'eaddr'.
575 lookup_eaddr(ifname
, eaddr
)
582 struct sockaddr_dl
*sdl
;
586 /* We cannot use SIOCGIFADDR on the BPF descriptor.
587 We must instead get all the interfaces with SIOCGIFCONF
588 and find the right one. */
590 /* Use datagram socket to get Ethernet address. */
591 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
592 err(FATAL
, "socket: %s", strerror(errno
));
596 ifc
.ifc_len
= sizeof(inbuf
);
598 if (ioctl(fd
, SIOCGIFCONF
, (caddr_t
)&ifc
) < 0 ||
599 ifc
.ifc_len
< sizeof(struct ifreq
)) {
600 err(FATAL
, "lookup_eaddr: SIOGIFCONF: %s", strerror(errno
));
604 for (i
= 0; i
< ifc
.ifc_len
;
605 i
+= len
, ifr
= (struct ifreq
*)((caddr_t
)ifr
+ len
)) {
606 len
= sizeof(ifr
->ifr_name
) + ifr
->ifr_addr
.sa_len
;
607 sdl
= (struct sockaddr_dl
*)&ifr
->ifr_addr
;
608 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_type
!= IFT_ETHER
||
611 if (!strncmp(ifr
->ifr_name
, ifname
, sizeof(ifr
->ifr_name
))) {
612 bcopy((caddr_t
)LLADDR(sdl
), (caddr_t
)eaddr
, 6);
614 fprintf(stderr
, "%s: %x:%x:%x:%x:%x:%x\n",
615 ifr
->ifr_name
, eaddr
[0], eaddr
[1],
616 eaddr
[2], eaddr
[3], eaddr
[4], eaddr
[5]);
621 err(FATAL
, "lookup_eaddr: Never saw interface `%s'!", ifname
);
624 * Lookup the IP address and network mask of the interface named 'ifname'.
627 lookup_ipaddr(ifname
, addrp
, netmaskp
)
635 /* Use datagram socket to get IP address. */
636 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
637 err(FATAL
, "socket: %s", strerror(errno
));
640 (void) strncpy(ifr
.ifr_name
, ifname
, sizeof ifr
.ifr_name
);
641 if (ioctl(fd
, SIOCGIFADDR
, (char *) &ifr
) < 0) {
642 err(FATAL
, "SIOCGIFADDR: %s", strerror(errno
));
645 *addrp
= ((struct sockaddr_in
*) & ifr
.ifr_addr
)->sin_addr
.s_addr
;
646 if (ioctl(fd
, SIOCGIFNETMASK
, (char *) &ifr
) < 0) {
647 perror("SIOCGIFNETMASK");
650 *netmaskp
= ((struct sockaddr_in
*) & ifr
.ifr_addr
)->sin_addr
.s_addr
;
651 /* If SIOCGIFNETMASK didn't work, figure out a mask from the IP
654 *netmaskp
= ipaddrtonetmask(*addrp
);
659 * Poke the kernel arp tables with the ethernet/ip address combinataion
660 * given. When processing a reply, we must do this so that the booting
661 * host (i.e. the guy running rarpd), won't try to ARP for the hardware
662 * address of the guy being booted (he cannot answer the ARP).
665 update_arptab(ep
, ipaddr
)
670 struct arpreq request
;
671 struct sockaddr_in
*sin
;
673 request
.arp_flags
= 0;
674 sin
= (struct sockaddr_in
*) & request
.arp_pa
;
675 sin
->sin_family
= AF_INET
;
676 sin
->sin_addr
.s_addr
= ipaddr
;
677 request
.arp_ha
.sa_family
= AF_UNSPEC
;
678 /* This is needed #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN,
679 because AF_UNSPEC is zero and the kernel assumes that a zero
680 sa_family means that the real sa_family value is in sa_len. */
681 request
.arp_ha
.sa_len
= 16; /* XXX */
682 bcopy((char *) ep
, (char *) request
.arp_ha
.sa_data
, 6);
685 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
686 if (ioctl(s
, SIOCSARP
, (caddr_t
) & request
) < 0) {
687 err(NONFATAL
, "SIOCSARP: %s", strerror(errno
));
693 * Build a reverse ARP packet and sent it out on the interface.
694 * 'ep' points to a valid ARPOP_REVREQUEST. The ARPOP_REVREPLY is built
695 * on top of the request, then written to the network.
697 * RFC 903 defines the ether_arp fields as follows. The following comments
698 * are taken (more or less) straight from this document.
702 * arp_sha is the hardware address of the sender of the packet.
703 * arp_spa is undefined.
704 * arp_tha is the 'target' hardware address.
705 * In the case where the sender wishes to determine his own
706 * protocol address, this, like arp_sha, will be the hardware
707 * address of the sender.
708 * arp_tpa is undefined.
712 * arp_sha is the hardware address of the responder (the sender of the
714 * arp_spa is the protocol address of the responder (see the note below).
715 * arp_tha is the hardware address of the target, and should be the same as
716 * that which was given in the request.
717 * arp_tpa is the protocol address of the target, that is, the desired address.
719 * Note that the requirement that arp_spa be filled in with the responder's
720 * protocol is purely for convenience. For instance, if a system were to use
721 * both ARP and RARP, then the inclusion of the valid protocol-hardware
722 * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent
726 rarp_reply(ii
, ep
, ipaddr
)
728 struct ether_header
*ep
;
732 struct ether_arp
*ap
= (struct ether_arp
*) (ep
+ 1);
735 update_arptab((u_char
*) & ap
->arp_sha
, ipaddr
);
737 /* Build the rarp reply by modifying the rarp request in place. */
738 ep
->ether_type
= htons(ETHERTYPE_REVARP
);
739 ap
->ea_hdr
.ar_hrd
= htons(ARPHRD_ETHER
);
740 ap
->ea_hdr
.ar_pro
= htons(ETHERTYPE_IP
);
741 ap
->arp_op
= htons(ARPOP_REVREPLY
);
743 bcopy((char *) &ap
->arp_sha
, (char *) &ep
->ether_dhost
, 6);
744 bcopy((char *) ii
->ii_eaddr
, (char *) &ep
->ether_shost
, 6);
745 bcopy((char *) ii
->ii_eaddr
, (char *) &ap
->arp_sha
, 6);
747 bcopy((char *) &ipaddr
, (char *) ap
->arp_tpa
, 4);
748 /* Target hardware is unchanged. */
749 bcopy((char *) &ii
->ii_ipaddr
, (char *) ap
->arp_spa
, 4);
751 len
= sizeof(*ep
) + sizeof(*ap
);
752 n
= write(ii
->ii_fd
, (char *) ep
, len
);
754 err(NONFATAL
, "write: only %d of %d bytes written", n
, len
);
758 * Get the netmask of an IP address. This routine is used if
759 * SIOCGIFNETMASK doesn't work.
762 ipaddrtonetmask(addr
)
766 return IN_CLASSA_NET
;
768 return IN_CLASSB_NET
;
770 return IN_CLASSC_NET
;
771 err(FATAL
, "unknown IP address class: %08X", addr
);
784 err(int fatal
, const char *fmt
,...)
800 (void) fprintf(stderr
, "rarpd: error: ");
802 (void) fprintf(stderr
, "rarpd: warning: ");
803 (void) vfprintf(stderr
, fmt
, ap
);
804 (void) fprintf(stderr
, "\n");
806 vsyslog(LOG_ERR
, fmt
, ap
);
815 debug(const char *fmt
,...)
830 (void) fprintf(stderr
, "rarpd: ");
831 (void) vfprintf(stderr
, fmt
, ap
);
833 (void) fprintf(stderr
, "\n");