rarpd.c revision 1.10
1/* $NetBSD: rarpd.c,v 1.10 1996/01/31 20:25:31 hpeyerl 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.10 1996/01/31 20:25:31 hpeyerl 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 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 ifreq.ifr_name[0] = '\0'; 237 for (i = 0; i < ifc.ifc_len; 238 i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) { 239 len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len; 240 if (!strncmp(ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name))) 241 continue; 242 ifreq = *ifr; 243 if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) { 244 err(FATAL, "init_all: SIOCGIFFLAGS: %s", 245 strerror(errno)); 246 /* NOTREACHED */ 247 } 248 if ((ifr->ifr_flags & 249 (IFF_UP | IFF_LOOPBACK | IFF_POINTOPOINT)) != IFF_UP) 250 continue; 251 init_one(ifr->ifr_name); 252 } 253 (void) close(fd); 254} 255 256void 257usage() 258{ 259 (void) fprintf(stderr, "usage: rarpd -a [ -d -f ]\n"); 260 (void) fprintf(stderr, " rarpd [ -d -f ] interface\n"); 261 exit(1); 262} 263 264static int 265bpf_open() 266{ 267 int fd; 268 int n = 0; 269 char device[sizeof "/dev/bpf000"]; 270 271 /* Go through all the minors and find one that isn't in use. */ 272 do { 273 (void) sprintf(device, "/dev/bpf%d", n++); 274 fd = open(device, O_RDWR); 275 } while (fd < 0 && errno == EBUSY); 276 277 if (fd < 0) { 278 err(FATAL, "%s: %s", device, strerror(errno)); 279 /* NOTREACHED */ 280 } 281 return fd; 282} 283/* 284 * Open a BPF file and attach it to the interface named 'device'. 285 * Set immediate mode, and set a filter that accepts only RARP requests. 286 */ 287int 288rarp_open(device) 289 char *device; 290{ 291 int fd; 292 struct ifreq ifr; 293 u_int dlt; 294 int immediate; 295 296 static struct bpf_insn insns[] = { 297 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12), 298 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_REVARP, 0, 3), 299 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 20), 300 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ARPOP_REVREQUEST, 0, 1), 301 BPF_STMT(BPF_RET | BPF_K, sizeof(struct ether_arp) + 302 sizeof(struct ether_header)), 303 BPF_STMT(BPF_RET | BPF_K, 0), 304 }; 305 static struct bpf_program filter = { 306 sizeof insns / sizeof(insns[0]), 307 insns 308 }; 309 310 fd = bpf_open(); 311 312 /* Set immediate mode so packets are processed as they arrive. */ 313 immediate = 1; 314 if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) { 315 err(FATAL, "BIOCIMMEDIATE: %s", strerror(errno)); 316 /* NOTREACHED */ 317 } 318 (void) strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name); 319 if (ioctl(fd, BIOCSETIF, (caddr_t) & ifr) < 0) { 320 err(FATAL, "BIOCSETIF: %s", strerror(errno)); 321 /* NOTREACHED */ 322 } 323 /* Check that the data link layer is an Ethernet; this code won't work 324 * with anything else. */ 325 if (ioctl(fd, BIOCGDLT, (caddr_t) & dlt) < 0) { 326 err(FATAL, "BIOCGDLT: %s", strerror(errno)); 327 /* NOTREACHED */ 328 } 329 if (dlt != DLT_EN10MB) { 330 err(FATAL, "%s is not an ethernet", device); 331 /* NOTREACHED */ 332 } 333 /* Set filter program. */ 334 if (ioctl(fd, BIOCSETF, (caddr_t) & filter) < 0) { 335 err(FATAL, "BIOCSETF: %s", strerror(errno)); 336 /* NOTREACHED */ 337 } 338 return fd; 339} 340/* 341 * Perform various sanity checks on the RARP request packet. Return 342 * false on failure and log the reason. 343 */ 344static int 345rarp_check(p, len) 346 u_char *p; 347 int len; 348{ 349 struct ether_header *ep = (struct ether_header *) p; 350 struct ether_arp *ap = (struct ether_arp *) (p + sizeof(*ep)); 351 352 (void) debug("got a packet"); 353 354 if (len < sizeof(*ep) + sizeof(*ap)) { 355 err(NONFATAL, "truncated request"); 356 return 0; 357 } 358 /* XXX This test might be better off broken out... */ 359 if (ntohs (ep->ether_type) != ETHERTYPE_REVARP || 360 ntohs (ap->arp_hrd) != ARPHRD_ETHER || 361 ntohs (ap->arp_op) != ARPOP_REVREQUEST || 362 ntohs (ap->arp_pro) != ETHERTYPE_IP || 363 ap->arp_hln != 6 || ap->arp_pln != 4) { 364 err(NONFATAL, "request fails sanity check"); 365 return 0; 366 } 367 if (bcmp((char *) &ep->ether_shost, (char *) &ap->arp_sha, 6) != 0) { 368 err(NONFATAL, "ether/arp sender address mismatch"); 369 return 0; 370 } 371 if (bcmp((char *) &ap->arp_sha, (char *) &ap->arp_tha, 6) != 0) { 372 err(NONFATAL, "ether/arp target address mismatch"); 373 return 0; 374 } 375 return 1; 376} 377 378/* 379 * Loop indefinitely listening for RARP requests on the 380 * interfaces in 'iflist'. 381 */ 382void 383rarp_loop() 384{ 385 u_char *buf, *bp, *ep; 386 int cc, fd; 387 fd_set fds, listeners; 388 int bufsize, maxfd = 0; 389 struct if_info *ii; 390 391 if (iflist == 0) { 392 err(FATAL, "no interfaces"); 393 /* NOTREACHED */ 394 } 395 if (ioctl(iflist->ii_fd, BIOCGBLEN, (caddr_t) & bufsize) < 0) { 396 err(FATAL, "BIOCGBLEN: %s", strerror(errno)); 397 /* NOTREACHED */ 398 } 399 buf = (u_char *) malloc((unsigned) bufsize); 400 if (buf == 0) { 401 err(FATAL, "malloc: %s", strerror(errno)); 402 /* NOTREACHED */ 403 } 404 /* 405 * Find the highest numbered file descriptor for select(). 406 * Initialize the set of descriptors to listen to. 407 */ 408 FD_ZERO(&fds); 409 for (ii = iflist; ii; ii = ii->ii_next) { 410 FD_SET(ii->ii_fd, &fds); 411 if (ii->ii_fd > maxfd) 412 maxfd = ii->ii_fd; 413 } 414 while (1) { 415 listeners = fds; 416 if (select(maxfd + 1, &listeners, (struct fd_set *) 0, 417 (struct fd_set *) 0, (struct timeval *) 0) < 0) { 418 err(FATAL, "select: %s", strerror(errno)); 419 /* NOTREACHED */ 420 } 421 for (ii = iflist; ii; ii = ii->ii_next) { 422 fd = ii->ii_fd; 423 if (!FD_ISSET(fd, &listeners)) 424 continue; 425 again: 426 cc = read(fd, (char *) buf, bufsize); 427 /* Don't choke when we get ptraced */ 428 if (cc < 0 && errno == EINTR) 429 goto again; 430 /* Due to a SunOS bug, after 2^31 bytes, the file 431 * offset overflows and read fails with EINVAL. The 432 * lseek() to 0 will fix things. */ 433 if (cc < 0) { 434 if (errno == EINVAL && 435 (lseek(fd, 0, SEEK_CUR) + bufsize) < 0) { 436 (void) lseek(fd, 0, 0); 437 goto again; 438 } 439 err(FATAL, "read: %s", strerror(errno)); 440 /* NOTREACHED */ 441 } 442 /* Loop through the packet(s) */ 443#define bhp ((struct bpf_hdr *)bp) 444 bp = buf; 445 ep = bp + cc; 446 while (bp < ep) { 447 register int caplen, hdrlen; 448 449 caplen = bhp->bh_caplen; 450 hdrlen = bhp->bh_hdrlen; 451 if (rarp_check(bp + hdrlen, caplen)) 452 rarp_process(ii, bp + hdrlen); 453 bp += BPF_WORDALIGN(hdrlen + caplen); 454 } 455 } 456 } 457} 458 459#ifdef REQUIRE_TFTPBOOT 460 461#ifndef TFTP_DIR 462#define TFTP_DIR "/tftpboot" 463#endif 464 465/* 466 * True if this server can boot the host whose IP address is 'addr'. 467 * This check is made by looking in the tftp directory for the 468 * configuration file. 469 */ 470int 471rarp_bootable(addr) 472 u_long addr; 473{ 474 register struct dirent *dent; 475 register DIR *d; 476 char ipname[9]; 477 static DIR *dd = 0; 478 479 (void) sprintf(ipname, "%08X", addr); 480 /* If directory is already open, rewind it. Otherwise, open it. */ 481 if (d = dd) 482 rewinddir(d); 483 else { 484 if (chdir(TFTP_DIR) == -1) { 485 err(FATAL, "chdir: %s", strerror(errno)); 486 /* NOTREACHED */ 487 } 488 d = opendir("."); 489 if (d == 0) { 490 err(FATAL, "opendir: %s", strerror(errno)); 491 /* NOTREACHED */ 492 } 493 dd = d; 494 } 495 while (dent = readdir(d)) 496 if (strncmp(dent->d_name, ipname, 8) == 0) 497 return 1; 498 return 0; 499} 500#endif /* REQUIRE_TFTPBOOT */ 501 502/* 503 * Given a list of IP addresses, 'alist', return the first address that 504 * is on network 'net'; 'netmask' is a mask indicating the network portion 505 * of the address. 506 */ 507u_long 508choose_ipaddr(alist, net, netmask) 509 u_long **alist; 510 u_long net; 511 u_long netmask; 512{ 513 for (; *alist; ++alist) { 514 if ((**alist & netmask) == net) 515 return **alist; 516 } 517 return 0; 518} 519/* 520 * Answer the RARP request in 'pkt', on the interface 'ii'. 'pkt' has 521 * already been checked for validity. The reply is overlaid on the request. 522 */ 523void 524rarp_process(ii, pkt) 525 struct if_info *ii; 526 u_char *pkt; 527{ 528 struct ether_header *ep; 529 struct hostent *hp; 530 u_long target_ipaddr; 531 char ename[256]; 532 struct in_addr in; 533 534 ep = (struct ether_header *) pkt; 535 536 if (ether_ntohost(ename, &ep->ether_shost) != 0 || 537 (hp = gethostbyname(ename)) == 0) 538 return; 539 540 /* Choose correct address from list. */ 541 if (hp->h_addrtype != AF_INET) { 542 err(FATAL, "cannot handle non IP addresses"); 543 /* NOTREACHED */ 544 } 545 target_ipaddr = choose_ipaddr((u_long **) hp->h_addr_list, 546 ii->ii_ipaddr & ii->ii_netmask, ii->ii_netmask); 547 548 if (target_ipaddr == 0) { 549 in.s_addr = ii->ii_ipaddr & ii->ii_netmask; 550 err(NONFATAL, "cannot find %s on net %s\n", 551 ename, inet_ntoa(in)); 552 return; 553 } 554#ifdef REQUIRE_TFTPBOOT 555 if (rarp_bootable(htonl(target_ipaddr))) 556#endif 557 rarp_reply(ii, ep, target_ipaddr); 558} 559/* 560 * Lookup the ethernet address of the interface attached to the BPF 561 * file descriptor 'fd'; return it in 'eaddr'. 562 */ 563void 564lookup_eaddr(ifname, eaddr) 565 char *ifname; 566 u_char *eaddr; 567{ 568 char inbuf[8192]; 569 struct ifconf ifc; 570 struct ifreq *ifr; 571 struct sockaddr_dl *sdl; 572 int fd; 573 int i, len; 574 575 /* We cannot use SIOCGIFADDR on the BPF descriptor. 576 We must instead get all the interfaces with SIOCGIFCONF 577 and find the right one. */ 578 579 /* Use datagram socket to get Ethernet address. */ 580 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 581 err(FATAL, "socket: %s", strerror(errno)); 582 /* NOTREACHED */ 583 } 584 585 ifc.ifc_len = sizeof(inbuf); 586 ifc.ifc_buf = inbuf; 587 if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 || 588 ifc.ifc_len < sizeof(struct ifreq)) { 589 err(FATAL, "lookup_eaddr: SIOGIFCONF: %s", strerror(errno)); 590 /* NOTREACHED */ 591 } 592 ifr = ifc.ifc_req; 593 for (i = 0; i < ifc.ifc_len; 594 i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) { 595 len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len; 596 sdl = (struct sockaddr_dl *)&ifr->ifr_addr; 597 if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER || 598 sdl->sdl_alen != 6) 599 continue; 600 if (!strncmp(ifr->ifr_name, ifname, sizeof(ifr->ifr_name))) { 601 bcopy((caddr_t)LLADDR(sdl), (caddr_t)eaddr, 6); 602 if (dflag) 603 fprintf(stderr, "%s: %x:%x:%x:%x:%x:%x\n", 604 ifr->ifr_name, eaddr[0], eaddr[1], 605 eaddr[2], eaddr[3], eaddr[4], eaddr[5]); 606 return; 607 } 608 } 609 610 err(FATAL, "lookup_eaddr: Never saw interface `%s'!", ifname); 611} 612/* 613 * Lookup the IP address and network mask of the interface named 'ifname'. 614 */ 615void 616lookup_ipaddr(ifname, addrp, netmaskp) 617 char *ifname; 618 u_long *addrp; 619 u_long *netmaskp; 620{ 621 int fd; 622 struct ifreq ifr; 623 624 /* Use datagram socket to get IP address. */ 625 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 626 err(FATAL, "socket: %s", strerror(errno)); 627 /* NOTREACHED */ 628 } 629 (void) strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); 630 if (ioctl(fd, SIOCGIFADDR, (char *) &ifr) < 0) { 631 err(FATAL, "SIOCGIFADDR: %s", strerror(errno)); 632 /* NOTREACHED */ 633 } 634 *addrp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr; 635 if (ioctl(fd, SIOCGIFNETMASK, (char *) &ifr) < 0) { 636 perror("SIOCGIFNETMASK"); 637 exit(1); 638 } 639 *netmaskp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr; 640 /* If SIOCGIFNETMASK didn't work, figure out a mask from the IP 641 * address class. */ 642 if (*netmaskp == 0) 643 *netmaskp = ipaddrtonetmask(*addrp); 644 645 (void) close(fd); 646} 647/* 648 * Poke the kernel arp tables with the ethernet/ip address combinataion 649 * given. When processing a reply, we must do this so that the booting 650 * host (i.e. the guy running rarpd), won't try to ARP for the hardware 651 * address of the guy being booted (he cannot answer the ARP). 652 */ 653void 654update_arptab(ep, ipaddr) 655 u_char *ep; 656 u_long ipaddr; 657{ 658 int s; 659 struct arpreq request; 660 struct sockaddr_in *sin; 661 662 request.arp_flags = 0; 663 sin = (struct sockaddr_in *) & request.arp_pa; 664 sin->sin_family = AF_INET; 665 sin->sin_addr.s_addr = ipaddr; 666 request.arp_ha.sa_family = AF_UNSPEC; 667 /* This is needed #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN, 668 because AF_UNSPEC is zero and the kernel assumes that a zero 669 sa_family means that the real sa_family value is in sa_len. */ 670 request.arp_ha.sa_len = 16; /* XXX */ 671 bcopy((char *) ep, (char *) request.arp_ha.sa_data, 6); 672 673#if 0 674 s = socket(AF_INET, SOCK_DGRAM, 0); 675 if (ioctl(s, SIOCSARP, (caddr_t) & request) < 0) { 676 err(NONFATAL, "SIOCSARP: %s", strerror(errno)); 677 } 678 (void) close(s); 679#endif 680} 681/* 682 * Build a reverse ARP packet and sent it out on the interface. 683 * 'ep' points to a valid ARPOP_REVREQUEST. The ARPOP_REVREPLY is built 684 * on top of the request, then written to the network. 685 * 686 * RFC 903 defines the ether_arp fields as follows. The following comments 687 * are taken (more or less) straight from this document. 688 * 689 * ARPOP_REVREQUEST 690 * 691 * arp_sha is the hardware address of the sender of the packet. 692 * arp_spa is undefined. 693 * arp_tha is the 'target' hardware address. 694 * In the case where the sender wishes to determine his own 695 * protocol address, this, like arp_sha, will be the hardware 696 * address of the sender. 697 * arp_tpa is undefined. 698 * 699 * ARPOP_REVREPLY 700 * 701 * arp_sha is the hardware address of the responder (the sender of the 702 * reply packet). 703 * arp_spa is the protocol address of the responder (see the note below). 704 * arp_tha is the hardware address of the target, and should be the same as 705 * that which was given in the request. 706 * arp_tpa is the protocol address of the target, that is, the desired address. 707 * 708 * Note that the requirement that arp_spa be filled in with the responder's 709 * protocol is purely for convenience. For instance, if a system were to use 710 * both ARP and RARP, then the inclusion of the valid protocol-hardware 711 * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent 712 * ARP request. 713 */ 714void 715rarp_reply(ii, ep, ipaddr) 716 struct if_info *ii; 717 struct ether_header *ep; 718 u_long ipaddr; 719{ 720 int n; 721 struct ether_arp *ap = (struct ether_arp *) (ep + 1); 722 int len; 723 724 update_arptab((u_char *) & ap->arp_sha, ipaddr); 725 726 /* Build the rarp reply by modifying the rarp request in place. */ 727 ep->ether_type = htons(ETHERTYPE_REVARP); 728 ap->ea_hdr.ar_hrd = htons(ARPHRD_ETHER); 729 ap->ea_hdr.ar_pro = htons(ETHERTYPE_IP); 730 ap->arp_op = htons(ARPOP_REVREPLY); 731 732 bcopy((char *) &ap->arp_sha, (char *) &ep->ether_dhost, 6); 733 bcopy((char *) ii->ii_eaddr, (char *) &ep->ether_shost, 6); 734 bcopy((char *) ii->ii_eaddr, (char *) &ap->arp_sha, 6); 735 736 bcopy((char *) &ipaddr, (char *) ap->arp_tpa, 4); 737 /* Target hardware is unchanged. */ 738 bcopy((char *) &ii->ii_ipaddr, (char *) ap->arp_spa, 4); 739 740 len = sizeof(*ep) + sizeof(*ap); 741 n = write(ii->ii_fd, (char *) ep, len); 742 if (n != len) { 743 err(NONFATAL, "write: only %d of %d bytes written", n, len); 744 } 745} 746/* 747 * Get the netmask of an IP address. This routine is used if 748 * SIOCGIFNETMASK doesn't work. 749 */ 750u_long 751ipaddrtonetmask(addr) 752 u_long addr; 753{ 754 if (IN_CLASSA(addr)) 755 return IN_CLASSA_NET; 756 if (IN_CLASSB(addr)) 757 return IN_CLASSB_NET; 758 if (IN_CLASSC(addr)) 759 return IN_CLASSC_NET; 760 err(FATAL, "unknown IP address class: %08X", addr); 761 /* NOTREACHED */ 762} 763 764#if __STDC__ 765#include <stdarg.h> 766#else 767#include <varargs.h> 768#endif 769 770void 771#if __STDC__ 772err(int fatal, const char *fmt,...) 773#else 774err(fmt, va_alist) 775 int fatal; 776 char *fmt; 777va_dcl 778#endif 779{ 780 va_list ap; 781#if __STDC__ 782 va_start(ap, fmt); 783#else 784 va_start(ap); 785#endif 786 if (dflag) { 787 if (fatal) 788 (void) fprintf(stderr, "rarpd: error: "); 789 else 790 (void) fprintf(stderr, "rarpd: warning: "); 791 (void) vfprintf(stderr, fmt, ap); 792 (void) fprintf(stderr, "\n"); 793 } 794 vsyslog(LOG_ERR, fmt, ap); 795 va_end(ap); 796 if (fatal) 797 exit(1); 798 /* NOTREACHED */ 799} 800 801void 802#if __STDC__ 803debug(const char *fmt,...) 804#else 805debug(fmt, va_alist) 806 char *fmt; 807va_dcl 808#endif 809{ 810 va_list ap; 811 812 if (dflag) { 813#if __STDC__ 814 va_start(ap, fmt); 815#else 816 va_start(ap); 817#endif 818 (void) fprintf(stderr, "rarpd: "); 819 (void) vfprintf(stderr, fmt, ap); 820 va_end(ap); 821 (void) fprintf(stderr, "\n"); 822 } 823} 824