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