]>
git.saurik.com Git - apple/network_cmds.git/blob - rarpd.tproj/rarpd.c
890be78148a6451c6b58a2cc922ce7ee6eb10674
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.
46 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
47 All rights reserved.\n";
52 "@(#) $Id: rarpd.c,v 1.1.1.1 1999/05/02 03:57:59 wsanchez Exp $";
57 * rarpd - Reverse ARP Daemon
59 * Usage: rarpd -a [ -d -f ]
60 * rarpd [ -d -f ] interface
68 #include <sys/types.h>
72 #include <sys/socket.h>
73 #include <sys/ioctl.h>
75 #include <net/if_dl.h>
76 #include <net/if_types.h>
77 #include <netinet/in.h>
78 #include <netinet/if_ether.h>
79 #include <sys/errno.h>
82 #include <arpa/inet.h>
85 #define FATAL 1 /* fatal error occurred */
86 #define NONFATAL 0 /* non fatal error occurred */
89 * The structure for each interface.
92 int ii_fd
; /* BPF file descriptor */
93 u_char ii_eaddr
[6]; /* Ethernet address of this interface */
94 u_long ii_ipaddr
; /* IP address of this interface */
95 u_long ii_netmask
; /* subnet or net mask */
96 struct if_info
*ii_next
;
99 * The list of all interfaces that are being listened to. rarp_loop()
100 * "selects" on the descriptors in this list.
102 struct if_info
*iflist
;
104 int rarp_open
__P((char *));
105 int rarp_bootable
__P((u_long
));
106 void init_one
__P((char *));
107 void init_all
__P((void));
108 void rarp_loop
__P((void));
109 void lookup_eaddr
__P((char *, u_char
*));
110 void lookup_ipaddr
__P((char *, u_long
*, u_long
*));
111 void usage
__P((void));
112 void rarp_process
__P((struct if_info
*, u_char
*));
113 void rarp_reply
__P((struct if_info
*, struct ether_header
*, u_long
));
114 void update_arptab
__P((u_char
*, u_long
));
115 void err
__P((int, const char *,...));
116 void debug
__P((const char *,...));
117 u_long ipaddrtonetmask
__P((u_long
));
119 int aflag
= 0; /* listen on "all" interfaces */
120 int dflag
= 0; /* print debugging messages */
121 int fflag
= 0; /* don't fork */
128 int op
, pid
, devnull
, f
;
129 char *ifname
, *hostname
, *name
;
132 extern int optind
, opterr
;
134 if (name
= strrchr(argv
[0], '/'))
141 /* All error reporting is done through syslogs. */
142 openlog(name
, LOG_PID
| LOG_CONS
, LOG_DAEMON
);
145 while ((op
= getopt(argc
, argv
, "adf")) != EOF
) {
164 ifname
= argv
[optind
++];
165 hostname
= ifname
? argv
[optind
] : 0;
166 if ((aflag
&& ifname
) || (!aflag
&& ifname
== 0))
174 if ((!fflag
) && (!dflag
)) {
177 /* Parent exits, leaving child in background. */
181 err(FATAL
, "cannot fork");
184 /* Fade into the background */
185 f
= open("/dev/tty", O_RDWR
);
187 if (ioctl(f
, TIOCNOTTY
, 0) < 0) {
188 err(FATAL
, "TIOCNOTTY: %s", strerror(errno
));
194 (void) setpgrp(0, getpid());
195 devnull
= open("/dev/null", O_RDWR
);
197 (void) dup2(devnull
, 0);
198 (void) dup2(devnull
, 1);
199 (void) dup2(devnull
, 2);
201 (void) close(devnull
);
207 * Add 'ifname' to the interface list. Lookup its IP address and network
208 * mask and Ethernet address, and open a BPF file for it.
216 p
= (struct if_info
*)malloc(sizeof(*p
));
218 err(FATAL
, "malloc: %s", strerror(errno
));
224 p
->ii_fd
= rarp_open(ifname
);
225 lookup_eaddr(ifname
, p
->ii_eaddr
);
226 lookup_ipaddr(ifname
, &p
->ii_ipaddr
, &p
->ii_netmask
);
229 * Initialize all "candidate" interfaces that are in the system
230 * configuration list. A "candidate" is up, not loopback and not
242 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
243 err(FATAL
, "socket: %s", strerror(errno
));
247 ifc
.ifc_len
= sizeof(inbuf
);
249 if (ioctl(fd
, SIOCGIFCONF
, (caddr_t
)&ifc
) < 0 ||
250 ifc
.ifc_len
< sizeof(struct ifreq
)) {
251 err(FATAL
, "init_all: SIOCGIFCONF: %s", strerror(errno
));
255 for (i
= 0; i
< ifc
.ifc_len
;
256 i
+= len
, ifr
= (struct ifreq
*)((caddr_t
)ifr
+ len
)) {
257 len
= sizeof(ifr
->ifr_name
) + ifr
->ifr_addr
.sa_len
;
258 if (ioctl(fd
, SIOCGIFFLAGS
, (caddr_t
)ifr
) < 0) {
259 err(FATAL
, "init_all: SIOCGIFFLAGS: %s",
263 if ((ifr
->ifr_flags
&
264 (IFF_UP
| IFF_LOOPBACK
| IFF_POINTOPOINT
)) != IFF_UP
)
266 init_one(ifr
->ifr_name
);
274 (void) fprintf(stderr
, "usage: rarpd -a [ -d -f ]\n");
275 (void) fprintf(stderr
, " rarpd [ -d -f ] interface\n");
284 char device
[sizeof "/dev/bpf000"];
286 /* Go through all the minors and find one that isn't in use. */
288 (void) sprintf(device
, "/dev/bpf%d", n
++);
289 fd
= open(device
, O_RDWR
);
290 } while (fd
< 0 && errno
== EBUSY
);
293 err(FATAL
, "%s: %s", device
, strerror(errno
));
299 * Open a BPF file and attach it to the interface named 'device'.
300 * Set immediate mode, and set a filter that accepts only RARP requests.
311 static struct bpf_insn insns
[] = {
312 BPF_STMT(BPF_LD
| BPF_H
| BPF_ABS
, 12),
313 BPF_JUMP(BPF_JMP
| BPF_JEQ
| BPF_K
, ETHERTYPE_REVARP
, 0, 3),
314 BPF_STMT(BPF_LD
| BPF_H
| BPF_ABS
, 20),
315 BPF_JUMP(BPF_JMP
| BPF_JEQ
| BPF_K
, ARPOP_REVREQUEST
, 0, 1),
316 BPF_STMT(BPF_RET
| BPF_K
, sizeof(struct ether_arp
) +
317 sizeof(struct ether_header
)),
318 BPF_STMT(BPF_RET
| BPF_K
, 0),
320 static struct bpf_program filter
= {
321 sizeof insns
/ sizeof(insns
[0]),
327 /* Set immediate mode so packets are processed as they arrive. */
329 if (ioctl(fd
, BIOCIMMEDIATE
, &immediate
) < 0) {
330 err(FATAL
, "BIOCIMMEDIATE: %s", strerror(errno
));
333 (void) strncpy(ifr
.ifr_name
, device
, sizeof ifr
.ifr_name
);
334 if (ioctl(fd
, BIOCSETIF
, (caddr_t
) & ifr
) < 0) {
335 err(FATAL
, "BIOCSETIF: %s", strerror(errno
));
338 /* Check that the data link layer is an Ethernet; this code won't work
339 * with anything else. */
340 if (ioctl(fd
, BIOCGDLT
, (caddr_t
) & dlt
) < 0) {
341 err(FATAL
, "BIOCGDLT: %s", strerror(errno
));
344 if (dlt
!= DLT_EN10MB
) {
345 err(FATAL
, "%s is not an ethernet", device
);
348 /* Set filter program. */
349 if (ioctl(fd
, BIOCSETF
, (caddr_t
) & filter
) < 0) {
350 err(FATAL
, "BIOCSETF: %s", strerror(errno
));
356 * Perform various sanity checks on the RARP request packet. Return
357 * false on failure and log the reason.
364 struct ether_header
*ep
= (struct ether_header
*) p
;
365 struct ether_arp
*ap
= (struct ether_arp
*) (p
+ sizeof(*ep
));
367 (void) debug("got a packet");
369 if (len
< sizeof(*ep
) + sizeof(*ap
)) {
370 err(NONFATAL
, "truncated request");
373 /* XXX This test might be better off broken out... */
374 if (ntohs (ep
->ether_type
) != ETHERTYPE_REVARP
||
375 ntohs (ap
->arp_hrd
) != ARPHRD_ETHER
||
376 ntohs (ap
->arp_op
) != ARPOP_REVREQUEST
||
377 ntohs (ap
->arp_pro
) != ETHERTYPE_IP
||
378 ap
->arp_hln
!= 6 || ap
->arp_pln
!= 4) {
379 err(NONFATAL
, "request fails sanity check");
382 if (bcmp((char *) &ep
->ether_shost
, (char *) &ap
->arp_sha
, 6) != 0) {
383 err(NONFATAL
, "ether/arp sender address mismatch");
386 if (bcmp((char *) &ap
->arp_sha
, (char *) &ap
->arp_tha
, 6) != 0) {
387 err(NONFATAL
, "ether/arp target address mismatch");
394 * Loop indefinitely listening for RARP requests on the
395 * interfaces in 'iflist'.
400 u_char
*buf
, *bp
, *ep
;
402 fd_set fds
, listeners
;
403 int bufsize
, maxfd
= 0;
407 err(FATAL
, "no interfaces");
410 if (ioctl(iflist
->ii_fd
, BIOCGBLEN
, (caddr_t
) & bufsize
) < 0) {
411 err(FATAL
, "BIOCGBLEN: %s", strerror(errno
));
414 buf
= (u_char
*) malloc((unsigned) bufsize
);
416 err(FATAL
, "malloc: %s", strerror(errno
));
420 * Find the highest numbered file descriptor for select().
421 * Initialize the set of descriptors to listen to.
424 for (ii
= iflist
; ii
; ii
= ii
->ii_next
) {
425 FD_SET(ii
->ii_fd
, &fds
);
426 if (ii
->ii_fd
> maxfd
)
431 if (select(maxfd
+ 1, &listeners
, (struct fd_set
*) 0,
432 (struct fd_set
*) 0, (struct timeval
*) 0) < 0) {
433 err(FATAL
, "select: %s", strerror(errno
));
436 for (ii
= iflist
; ii
; ii
= ii
->ii_next
) {
438 if (!FD_ISSET(fd
, &listeners
))
441 cc
= read(fd
, (char *) buf
, bufsize
);
442 /* Don't choke when we get ptraced */
443 if (cc
< 0 && errno
== EINTR
)
445 /* Due to a SunOS bug, after 2^31 bytes, the file
446 * offset overflows and read fails with EINVAL. The
447 * lseek() to 0 will fix things. */
449 if (errno
== EINVAL
&&
450 (lseek(fd
, 0, SEEK_CUR
) + bufsize
) < 0) {
451 (void) lseek(fd
, 0, 0);
454 err(FATAL
, "read: %s", strerror(errno
));
457 /* Loop through the packet(s) */
458 #define bhp ((struct bpf_hdr *)bp)
462 register int caplen
, hdrlen
;
464 caplen
= bhp
->bh_caplen
;
465 hdrlen
= bhp
->bh_hdrlen
;
466 if (rarp_check(bp
+ hdrlen
, caplen
))
467 rarp_process(ii
, bp
+ hdrlen
);
468 bp
+= BPF_WORDALIGN(hdrlen
+ caplen
);
474 #define TFTP_DIR "/tftpboot"
478 * True if this server can boot the host whose IP address is 'addr'.
479 * This check is made by looking in the tftp directory for the
480 * configuration file.
486 register struct dirent
*dent
;
491 (void) sprintf(ipname
, "%08X", addr
);
492 /* If directory is already open, rewind it. Otherwise, open it. */
496 if (chdir(TFTP_DIR
) == -1) {
497 err(FATAL
, "chdir: %s", strerror(errno
));
502 err(FATAL
, "opendir: %s", strerror(errno
));
507 while (dent
= readdir(d
))
508 if (strncmp(dent
->d_name
, ipname
, 8) == 0)
513 * Given a list of IP addresses, 'alist', return the first address that
514 * is on network 'net'; 'netmask' is a mask indicating the network portion
518 choose_ipaddr(alist
, net
, netmask
)
523 for (; *alist
; ++alist
) {
524 if ((**alist
& netmask
) == net
)
530 * Answer the RARP request in 'pkt', on the interface 'ii'. 'pkt' has
531 * already been checked for validity. The reply is overlaid on the request.
534 rarp_process(ii
, pkt
)
538 struct ether_header
*ep
;
540 u_long target_ipaddr
;
544 ep
= (struct ether_header
*) pkt
;
546 if (ether_ntohost(ename
, &ep
->ether_shost
) != 0 ||
547 (hp
= gethostbyname(ename
)) == 0)
550 /* Choose correct address from list. */
551 if (hp
->h_addrtype
!= AF_INET
) {
552 err(FATAL
, "cannot handle non IP addresses");
555 target_ipaddr
= choose_ipaddr((u_long
**) hp
->h_addr_list
,
556 ii
->ii_ipaddr
& ii
->ii_netmask
, ii
->ii_netmask
);
558 if (target_ipaddr
== 0) {
559 in
.s_addr
= ii
->ii_ipaddr
& ii
->ii_netmask
;
560 err(NONFATAL
, "cannot find %s on net %s\n",
561 ename
, inet_ntoa(in
));
564 if (rarp_bootable(htonl(target_ipaddr
)))
565 rarp_reply(ii
, ep
, target_ipaddr
);
568 * Lookup the ethernet address of the interface attached to the BPF
569 * file descriptor 'fd'; return it in 'eaddr'.
572 lookup_eaddr(ifname
, eaddr
)
579 struct sockaddr_dl
*sdl
;
583 /* We cannot use SIOCGIFADDR on the BPF descriptor.
584 We must instead get all the interfaces with SIOCGIFCONF
585 and find the right one. */
587 /* Use datagram socket to get Ethernet address. */
588 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
589 err(FATAL
, "socket: %s", strerror(errno
));
593 ifc
.ifc_len
= sizeof(inbuf
);
595 if (ioctl(fd
, SIOCGIFCONF
, (caddr_t
)&ifc
) < 0 ||
596 ifc
.ifc_len
< sizeof(struct ifreq
)) {
597 err(FATAL
, "lookup_eaddr: SIOGIFCONF: %s", strerror(errno
));
601 for (i
= 0; i
< ifc
.ifc_len
;
602 i
+= len
, ifr
= (struct ifreq
*)((caddr_t
)ifr
+ len
)) {
603 len
= sizeof(ifr
->ifr_name
) + ifr
->ifr_addr
.sa_len
;
604 sdl
= (struct sockaddr_dl
*)&ifr
->ifr_addr
;
605 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_type
!= IFT_ETHER
||
608 if (!strncmp(ifr
->ifr_name
, ifname
, sizeof(ifr
->ifr_name
))) {
609 bcopy((caddr_t
)LLADDR(sdl
), (caddr_t
)eaddr
, 6);
611 fprintf(stderr
, "%s: %x:%x:%x:%x:%x:%x\n",
612 ifr
->ifr_name
, eaddr
[0], eaddr
[1],
613 eaddr
[2], eaddr
[3], eaddr
[4], eaddr
[5]);
618 err(FATAL
, "lookup_eaddr: Never saw interface `%s'!", ifname
);
621 * Lookup the IP address and network mask of the interface named 'ifname'.
624 lookup_ipaddr(ifname
, addrp
, netmaskp
)
632 /* Use datagram socket to get IP address. */
633 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
634 err(FATAL
, "socket: %s", strerror(errno
));
637 (void) strncpy(ifr
.ifr_name
, ifname
, sizeof ifr
.ifr_name
);
638 if (ioctl(fd
, SIOCGIFADDR
, (char *) &ifr
) < 0) {
639 err(FATAL
, "SIOCGIFADDR: %s", strerror(errno
));
642 *addrp
= ((struct sockaddr_in
*) & ifr
.ifr_addr
)->sin_addr
.s_addr
;
643 if (ioctl(fd
, SIOCGIFNETMASK
, (char *) &ifr
) < 0) {
644 perror("SIOCGIFNETMASK");
647 *netmaskp
= ((struct sockaddr_in
*) & ifr
.ifr_addr
)->sin_addr
.s_addr
;
648 /* If SIOCGIFNETMASK didn't work, figure out a mask from the IP
651 *netmaskp
= ipaddrtonetmask(*addrp
);
656 * Poke the kernel arp tables with the ethernet/ip address combinataion
657 * given. When processing a reply, we must do this so that the booting
658 * host (i.e. the guy running rarpd), won't try to ARP for the hardware
659 * address of the guy being booted (he cannot answer the ARP).
662 update_arptab(ep
, ipaddr
)
667 struct arpreq request
;
668 struct sockaddr_in
*sin
;
670 request
.arp_flags
= 0;
671 sin
= (struct sockaddr_in
*) & request
.arp_pa
;
672 sin
->sin_family
= AF_INET
;
673 sin
->sin_addr
.s_addr
= ipaddr
;
674 request
.arp_ha
.sa_family
= AF_UNSPEC
;
675 /* This is needed #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN,
676 because AF_UNSPEC is zero and the kernel assumes that a zero
677 sa_family means that the real sa_family value is in sa_len. */
678 request
.arp_ha
.sa_len
= 16; /* XXX */
679 bcopy((char *) ep
, (char *) request
.arp_ha
.sa_data
, 6);
682 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
683 if (ioctl(s
, SIOCSARP
, (caddr_t
) & request
) < 0) {
684 err(NONFATAL
, "SIOCSARP: %s", strerror(errno
));
690 * Build a reverse ARP packet and sent it out on the interface.
691 * 'ep' points to a valid ARPOP_REVREQUEST. The ARPOP_REVREPLY is built
692 * on top of the request, then written to the network.
694 * RFC 903 defines the ether_arp fields as follows. The following comments
695 * are taken (more or less) straight from this document.
699 * arp_sha is the hardware address of the sender of the packet.
700 * arp_spa is undefined.
701 * arp_tha is the 'target' hardware address.
702 * In the case where the sender wishes to determine his own
703 * protocol address, this, like arp_sha, will be the hardware
704 * address of the sender.
705 * arp_tpa is undefined.
709 * arp_sha is the hardware address of the responder (the sender of the
711 * arp_spa is the protocol address of the responder (see the note below).
712 * arp_tha is the hardware address of the target, and should be the same as
713 * that which was given in the request.
714 * arp_tpa is the protocol address of the target, that is, the desired address.
716 * Note that the requirement that arp_spa be filled in with the responder's
717 * protocol is purely for convenience. For instance, if a system were to use
718 * both ARP and RARP, then the inclusion of the valid protocol-hardware
719 * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent
723 rarp_reply(ii
, ep
, ipaddr
)
725 struct ether_header
*ep
;
729 struct ether_arp
*ap
= (struct ether_arp
*) (ep
+ 1);
732 update_arptab((u_char
*) & ap
->arp_sha
, ipaddr
);
734 /* Build the rarp reply by modifying the rarp request in place. */
735 ep
->ether_type
= htons(ETHERTYPE_REVARP
);
736 ap
->ea_hdr
.ar_hrd
= htons(ARPHRD_ETHER
);
737 ap
->ea_hdr
.ar_pro
= htons(ETHERTYPE_IP
);
738 ap
->arp_op
= htons(ARPOP_REVREPLY
);
740 bcopy((char *) &ap
->arp_sha
, (char *) &ep
->ether_dhost
, 6);
741 bcopy((char *) ii
->ii_eaddr
, (char *) &ep
->ether_shost
, 6);
742 bcopy((char *) ii
->ii_eaddr
, (char *) &ap
->arp_sha
, 6);
744 bcopy((char *) &ipaddr
, (char *) ap
->arp_tpa
, 4);
745 /* Target hardware is unchanged. */
746 bcopy((char *) &ii
->ii_ipaddr
, (char *) ap
->arp_spa
, 4);
748 len
= sizeof(*ep
) + sizeof(*ap
);
749 n
= write(ii
->ii_fd
, (char *) ep
, len
);
751 err(NONFATAL
, "write: only %d of %d bytes written", n
, len
);
755 * Get the netmask of an IP address. This routine is used if
756 * SIOCGIFNETMASK doesn't work.
759 ipaddrtonetmask(addr
)
763 return IN_CLASSA_NET
;
765 return IN_CLASSB_NET
;
767 return IN_CLASSC_NET
;
768 err(FATAL
, "unknown IP address class: %08X", addr
);
780 err(int fatal
, const char *fmt
,...)
796 (void) fprintf(stderr
, "rarpd: error: ");
798 (void) fprintf(stderr
, "rarpd: warning: ");
799 (void) vfprintf(stderr
, fmt
, ap
);
800 (void) fprintf(stderr
, "\n");
802 vsyslog(LOG_ERR
, fmt
, ap
);
811 debug(const char *fmt
,...)
826 (void) fprintf(stderr
, "rarpd: ");
827 (void) vfprintf(stderr
, fmt
, ap
);
829 (void) fprintf(stderr
, "\n");