1 /* 2 * rarpd.c RARP daemon. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet (at) ms2.inr.ac.ru> 10 */ 11 12 #include <stdio.h> 13 #include <syslog.h> 14 #include <dirent.h> 15 #include <malloc.h> 16 #include <string.h> 17 #include <unistd.h> 18 #include <stdlib.h> 19 #include <netdb.h> 20 #include <arpa/inet.h> 21 #include <sys/ioctl.h> 22 #include <sys/poll.h> 23 #include <sys/errno.h> 24 #include <sys/fcntl.h> 25 #include <sys/socket.h> 26 #include <sys/signal.h> 27 #include <linux/if.h> 28 #include <linux/if_arp.h> 29 #include <netinet/in.h> 30 #include <linux/if_packet.h> 31 #include <linux/filter.h> 32 33 int do_reload = 1; 34 35 int debug; 36 int verbose; 37 int ifidx; 38 int allow_offlink; 39 int only_ethers; 40 int all_ifaces; 41 int listen_arp; 42 char *ifname; 43 char *tftp_dir = "/etc/tftpboot"; 44 45 extern int ether_ntohost(char *name, unsigned char *ea); 46 void usage(void) __attribute__((noreturn)); 47 48 struct iflink 49 { 50 struct iflink *next; 51 int index; 52 int hatype; 53 unsigned char lladdr[16]; 54 char name[IFNAMSIZ]; 55 struct ifaddr *ifa_list; 56 } *ifl_list; 57 58 struct ifaddr 59 { 60 struct ifaddr *next; 61 __u32 prefix; 62 __u32 mask; 63 __u32 local; 64 }; 65 66 struct rarp_map 67 { 68 struct rarp_map *next; 69 70 int ifindex; 71 int arp_type; 72 int lladdr_len; 73 unsigned char lladdr[16]; 74 __u32 ipaddr; 75 } *rarp_db; 76 77 void usage() 78 { 79 fprintf(stderr, "Usage: rarpd [ -dveaA ] [ -b tftpdir ] [ interface]\n"); 80 exit(1); 81 } 82 83 void load_db(void) 84 { 85 } 86 87 void load_if(void) 88 { 89 int fd; 90 struct ifreq *ifrp, *ifend; 91 struct iflink *ifl; 92 struct ifaddr *ifa; 93 struct ifconf ifc; 94 struct ifreq ibuf[256]; 95 96 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 97 syslog(LOG_ERR, "socket: %m"); 98 return; 99 } 100 101 ifc.ifc_len = sizeof ibuf; 102 ifc.ifc_buf = (caddr_t)ibuf; 103 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || 104 ifc.ifc_len < (int)sizeof(struct ifreq)) { 105 syslog(LOG_ERR, "SIOCGIFCONF: %m"); 106 close(fd); 107 return; 108 } 109 110 while ((ifl = ifl_list) != NULL) { 111 while ((ifa = ifl->ifa_list) != NULL) { 112 ifl->ifa_list = ifa->next; 113 free(ifa); 114 } 115 ifl_list = ifl->next; 116 free(ifl); 117 } 118 119 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); 120 for (ifrp = ibuf; ifrp < ifend; ifrp++) { 121 __u32 addr; 122 __u32 mask; 123 __u32 prefix; 124 125 if (ifrp->ifr_addr.sa_family != AF_INET) 126 continue; 127 addr = ((struct sockaddr_in*)&ifrp->ifr_addr)->sin_addr.s_addr; 128 if (addr == 0) 129 continue; 130 if (ioctl(fd, SIOCGIFINDEX, ifrp)) { 131 syslog(LOG_ERR, "ioctl(SIOCGIFNAME): %m"); 132 continue; 133 } 134 if (ifidx && ifrp->ifr_ifindex != ifidx) 135 continue; 136 for (ifl = ifl_list; ifl; ifl = ifl->next) 137 if (ifl->index == ifrp->ifr_ifindex) 138 break; 139 if (ifl == NULL) { 140 char *p; 141 int index = ifrp->ifr_ifindex; 142 143 if (ioctl(fd, SIOCGIFHWADDR, ifrp)) { 144 syslog(LOG_ERR, "ioctl(SIOCGIFHWADDR): %m"); 145 continue; 146 } 147 148 ifl = (struct iflink*)malloc(sizeof(*ifl)); 149 if (ifl == NULL) 150 continue; 151 memset(ifl, 0, sizeof(*ifl)); 152 ifl->next = ifl_list; 153 ifl_list = ifl; 154 ifl->index = index; 155 ifl->hatype = ifrp->ifr_hwaddr.sa_family; 156 memcpy(ifl->lladdr, ifrp->ifr_hwaddr.sa_data, 14); 157 strncpy(ifl->name, ifrp->ifr_name, IFNAMSIZ); 158 p = strchr(ifl->name, ':'); 159 if (p) 160 *p = 0; 161 if (verbose) 162 syslog(LOG_INFO, "link %s", ifl->name); 163 } 164 if (ioctl(fd, SIOCGIFNETMASK, ifrp)) { 165 syslog(LOG_ERR, "ioctl(SIOCGIFMASK): %m"); 166 continue; 167 } 168 mask = ((struct sockaddr_in*)&ifrp->ifr_netmask)->sin_addr.s_addr; 169 if (ioctl(fd, SIOCGIFDSTADDR, ifrp)) { 170 syslog(LOG_ERR, "ioctl(SIOCGIFDSTADDR): %m"); 171 continue; 172 } 173 prefix = ((struct sockaddr_in*)&ifrp->ifr_dstaddr)->sin_addr.s_addr; 174 for (ifa = ifl->ifa_list; ifa; ifa = ifa->next) { 175 if (ifa->local == addr && 176 ifa->prefix == prefix && 177 ifa->mask == mask) 178 break; 179 } 180 if (ifa == NULL) { 181 if (mask == 0 || prefix == 0) 182 continue; 183 ifa = (struct ifaddr*)malloc(sizeof(*ifa)); 184 memset(ifa, 0, sizeof(*ifa)); 185 ifa->local = addr; 186 ifa->prefix = prefix; 187 ifa->mask = mask; 188 ifa->next = ifl->ifa_list; 189 ifl->ifa_list = ifa; 190 191 if (verbose) { 192 int i; 193 __u32 m = ~0U; 194 for (i=32; i>=0; i--) { 195 if (htonl(m) == mask) 196 break; 197 m <<= 1; 198 } 199 if (addr == prefix) { 200 syslog(LOG_INFO, " addr %s/%d on %s\n", 201 inet_ntoa(*(struct in_addr*)&addr), i, ifl->name); 202 } else { 203 char tmpa[64]; 204 sprintf(tmpa, "%s", inet_ntoa(*(struct in_addr*)&addr)); 205 syslog(LOG_INFO, " addr %s %s/%d on %s\n", tmpa, 206 inet_ntoa(*(struct in_addr*)&prefix), i, ifl->name); 207 } 208 } 209 } 210 } 211 } 212 213 void configure(void) 214 { 215 load_if(); 216 load_db(); 217 } 218 219 int bootable(__u32 addr) 220 { 221 struct dirent *dent; 222 DIR *d; 223 char name[9]; 224 225 sprintf(name, "%08X", (__u32)ntohl(addr)); 226 d = opendir(tftp_dir); 227 if (d == NULL) { 228 syslog(LOG_ERR, "opendir: %m"); 229 return 0; 230 } 231 while ((dent = readdir(d)) != NULL) { 232 if (strncmp(dent->d_name, name, 8) == 0) 233 break; 234 } 235 closedir(d); 236 return dent != NULL; 237 } 238 239 struct ifaddr *select_ipaddr(int ifindex, __u32 *sel_addr, __u32 **alist) 240 { 241 struct iflink *ifl; 242 struct ifaddr *ifa; 243 int retry = 0; 244 int i; 245 246 retry: 247 for (ifl=ifl_list; ifl; ifl=ifl->next) 248 if (ifl->index == ifindex) 249 break; 250 if (ifl == NULL && !retry) { 251 retry++; 252 load_if(); 253 goto retry; 254 } 255 if (ifl == NULL) 256 return NULL; 257 258 for (i=0; alist[i]; i++) { 259 __u32 addr = *(alist[i]); 260 for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) { 261 if (!((ifa->prefix^addr)&ifa->mask)) { 262 *sel_addr = addr; 263 return ifa; 264 } 265 } 266 if (ifa == NULL && retry==0) { 267 retry++; 268 load_if(); 269 goto retry; 270 } 271 } 272 if (i==1 && allow_offlink) { 273 *sel_addr = *(alist[0]); 274 return ifl->ifa_list; 275 } 276 syslog(LOG_ERR, "Off-link request on %s", ifl->name); 277 return NULL; 278 } 279 280 struct rarp_map *rarp_lookup(int ifindex, int hatype, 281 int halen, unsigned char *lladdr) 282 { 283 struct rarp_map *r; 284 285 for (r=rarp_db; r; r=r->next) { 286 if (r->arp_type != hatype && r->arp_type != -1) 287 continue; 288 if (r->lladdr_len != halen) 289 continue; 290 if (r->ifindex != ifindex && r->ifindex != 0) 291 continue; 292 if (memcmp(r->lladdr, lladdr, halen) == 0) 293 break; 294 } 295 296 if (r == NULL) { 297 if (hatype == ARPHRD_ETHER && halen == 6) { 298 struct ifaddr *ifa; 299 struct hostent *hp; 300 char ename[256]; 301 static struct rarp_map emap = { 302 NULL, 303 0, 304 ARPHRD_ETHER, 305 6, 306 }; 307 308 if (ether_ntohost(ename, lladdr) != 0 || 309 (hp = gethostbyname(ename)) == NULL) { 310 if (verbose) 311 syslog(LOG_INFO, "not found in /etc/ethers"); 312 return NULL; 313 } 314 if (hp->h_addrtype != AF_INET) { 315 syslog(LOG_ERR, "no IP address"); 316 return NULL; 317 } 318 ifa = select_ipaddr(ifindex, &emap.ipaddr, (__u32 **)hp->h_addr_list); 319 if (ifa) { 320 memcpy(emap.lladdr, lladdr, 6); 321 if (only_ethers || bootable(emap.ipaddr)) 322 return &emap; 323 if (verbose) 324 syslog(LOG_INFO, "not bootable"); 325 } 326 } 327 } 328 return r; 329 } 330 331 static int load_arp_bpflet(int fd) 332 { 333 static struct sock_filter insns[] = { 334 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), 335 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ARPOP_RREQUEST, 0, 1), 336 BPF_STMT(BPF_RET|BPF_K, 1024), 337 BPF_STMT(BPF_RET|BPF_K, 0), 338 }; 339 static struct sock_fprog filter = { 340 sizeof insns / sizeof(insns[0]), 341 insns 342 }; 343 344 return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); 345 } 346 347 int put_mylladdr(unsigned char **ptr_p, int ifindex, int alen) 348 { 349 struct iflink *ifl; 350 351 for (ifl=ifl_list; ifl; ifl = ifl->next) 352 if (ifl->index == ifindex) 353 break; 354 355 if (ifl==NULL) 356 return -1; 357 358 memcpy(*ptr_p, ifl->lladdr, alen); 359 *ptr_p += alen; 360 return 0; 361 } 362 363 int put_myipaddr(unsigned char **ptr_p, int ifindex, __u32 hisipaddr) 364 { 365 __u32 laddr = 0; 366 struct iflink *ifl; 367 struct ifaddr *ifa; 368 369 for (ifl=ifl_list; ifl; ifl = ifl->next) 370 if (ifl->index == ifindex) 371 break; 372 373 if (ifl==NULL) 374 return -1; 375 376 for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) { 377 if (!((ifa->prefix^hisipaddr)&ifa->mask)) { 378 laddr = ifa->local; 379 break; 380 } 381 } 382 memcpy(*ptr_p, &laddr, 4); 383 *ptr_p += 4; 384 return 0; 385 } 386 387 void arp_advise(int ifindex, unsigned char *lladdr, int lllen, __u32 ipaddr) 388 { 389 int fd; 390 struct arpreq req; 391 struct sockaddr_in *sin; 392 struct iflink *ifl; 393 394 for (ifl=ifl_list; ifl; ifl = ifl->next) 395 if (ifl->index == ifindex) 396 break; 397 398 if (ifl == NULL) 399 return; 400 401 fd = socket(AF_INET, SOCK_DGRAM, 0); 402 memset(&req, 0, sizeof(req)); 403 req.arp_flags = ATF_COM; 404 sin = (struct sockaddr_in *)&req.arp_pa; 405 sin->sin_family = AF_INET; 406 sin->sin_addr.s_addr = ipaddr; 407 req.arp_ha.sa_family = ifl->hatype; 408 memcpy(req.arp_ha.sa_data, lladdr, lllen); 409 memcpy(req.arp_dev, ifl->name, IFNAMSIZ); 410 411 if (ioctl(fd, SIOCSARP, &req)) 412 syslog(LOG_ERR, "SIOCSARP: %m"); 413 close(fd); 414 } 415 416 void serve_it(int fd) 417 { 418 unsigned char buf[1024]; 419 struct sockaddr_ll sll; 420 socklen_t sll_len = sizeof(sll); 421 struct arphdr *a = (struct arphdr*)buf; 422 struct rarp_map *rmap; 423 unsigned char *ptr; 424 int n; 425 426 n = recvfrom(fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sll, &sll_len); 427 if (n<0) { 428 if (errno != EINTR && errno != EAGAIN) 429 syslog(LOG_ERR, "recvfrom: %m"); 430 return; 431 } 432 433 /* Do not accept packets for other hosts and our own ones */ 434 if (sll.sll_pkttype != PACKET_BROADCAST && 435 sll.sll_pkttype != PACKET_MULTICAST && 436 sll.sll_pkttype != PACKET_HOST) 437 return; 438 439 if (ifidx && sll.sll_ifindex != ifidx) 440 return; 441 442 if (n<sizeof(*a)) { 443 syslog(LOG_ERR, "truncated arp packet; len=%d", n); 444 return; 445 } 446 447 /* Accept only RARP requests */ 448 if (a->ar_op != htons(ARPOP_RREQUEST)) 449 return; 450 451 if (verbose) { 452 int i; 453 char tmpbuf[16*3]; 454 char *ptr = tmpbuf; 455 for (i=0; i<sll.sll_halen; i++) { 456 if (i) { 457 sprintf(ptr, ":%02x", sll.sll_addr[i]); 458 ptr++; 459 } else 460 sprintf(ptr, "%02x", sll.sll_addr[i]); 461 ptr += 2; 462 } 463 syslog(LOG_INFO, "RARP request from %s on if%d", tmpbuf, sll.sll_ifindex); 464 } 465 466 /* Sanity checks */ 467 468 /* 1. IP only -> pln==4 */ 469 if (a->ar_pln != 4) { 470 syslog(LOG_ERR, "interesting rarp_req plen=%d", a->ar_pln); 471 return; 472 } 473 /* 2. ARP protocol must be IP */ 474 if (a->ar_pro != htons(ETH_P_IP)) { 475 syslog(LOG_ERR, "rarp protocol is not IP %04x", ntohs(a->ar_pro)); 476 return; 477 } 478 /* 3. ARP types must match */ 479 if (htons(sll.sll_hatype) != a->ar_hrd) { 480 switch (sll.sll_hatype) { 481 case ARPHRD_FDDI: 482 if (a->ar_hrd == htons(ARPHRD_ETHER) || 483 a->ar_hrd == htons(ARPHRD_IEEE802)) 484 break; 485 default: 486 syslog(LOG_ERR, "rarp htype mismatch"); 487 return; 488 } 489 } 490 /* 3. LL address lengths must be equal */ 491 if (a->ar_hln != sll.sll_halen) { 492 syslog(LOG_ERR, "rarp hlen mismatch"); 493 return; 494 } 495 /* 4. Check packet length */ 496 if (sizeof(*a) + 2*4 + 2*a->ar_hln > n) { 497 syslog(LOG_ERR, "truncated rarp request; len=%d", n); 498 return; 499 } 500 /* 5. Silly check: if this guy set different source 501 addresses in MAC header and in ARP, he is insane 502 */ 503 if (memcmp(sll.sll_addr, a+1, sll.sll_halen)) { 504 syslog(LOG_ERR, "this guy set different his lladdrs in arp and header"); 505 return; 506 } 507 /* End of sanity checks */ 508 509 /* Lookup requested target in our database */ 510 rmap = rarp_lookup(sll.sll_ifindex, sll.sll_hatype, 511 sll.sll_halen, (unsigned char*)(a+1) + sll.sll_halen + 4); 512 if (rmap == NULL) 513 return; 514 515 /* Prepare reply. It is almost ready, we only 516 replace ARP packet type, put our lladdr and 517 IP address to source fileds, 518 and fill target IP address. 519 */ 520 a->ar_op = htons(ARPOP_RREPLY); 521 ptr = (unsigned char*)(a+1); 522 if (put_mylladdr(&ptr, sll.sll_ifindex, rmap->lladdr_len)) 523 return; 524 if (put_myipaddr(&ptr, sll.sll_ifindex, rmap->ipaddr)) 525 return; 526 /* It is already filled */ 527 ptr += rmap->lladdr_len; 528 memcpy(ptr, &rmap->ipaddr, 4); 529 ptr += 4; 530 531 /* Update our ARP cache. Probably, this guy 532 will not able to make ARP (if it is broken) 533 */ 534 arp_advise(sll.sll_ifindex, rmap->lladdr, rmap->lladdr_len, rmap->ipaddr); 535 536 /* Sendto is blocking, but with 5sec timeout */ 537 alarm(5); 538 sendto(fd, buf, ptr - buf, 0, (struct sockaddr*)&sll, sizeof(sll)); 539 alarm(0); 540 } 541 542 void catch_signal(int sig, void (*handler)(int)) 543 { 544 struct sigaction sa; 545 546 memset(&sa, 0, sizeof(sa)); 547 sa.sa_handler = handler; 548 #ifdef SA_INTERRUPT 549 sa.sa_flags = SA_INTERRUPT; 550 #endif 551 sigaction(sig, &sa, NULL); 552 } 553 554 void sig_alarm(int signo) 555 { 556 } 557 558 void sig_hup(int signo) 559 { 560 do_reload = 1; 561 } 562 563 int main(int argc, char **argv) 564 { 565 struct pollfd pset[2]; 566 int psize; 567 int opt; 568 569 570 opterr = 0; 571 while ((opt = getopt(argc, argv, "aAb:dvoe")) != EOF) { 572 switch (opt) { 573 case 'a': 574 ++all_ifaces; 575 break; 576 577 case 'A': 578 ++listen_arp; 579 break; 580 581 case 'd': 582 ++debug; 583 break; 584 585 case 'v': 586 ++verbose; 587 break; 588 589 case 'o': 590 ++allow_offlink; 591 break; 592 593 case 'e': 594 ++only_ethers; 595 break; 596 597 case 'b': 598 tftp_dir = optarg; 599 break; 600 601 default: 602 usage(); 603 } 604 } 605 if (argc > optind) { 606 if (argc > optind+1) 607 usage(); 608 ifname = argv[optind]; 609 } 610 611 psize = 1; 612 pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0); 613 614 if (ifname) { 615 struct ifreq ifr; 616 memset(&ifr, 0, sizeof(ifr)); 617 strncpy(ifr.ifr_name, ifname, IFNAMSIZ); 618 if (ioctl(pset[0].fd, SIOCGIFINDEX, &ifr)) { 619 perror("ioctl(SIOCGIFINDEX)"); 620 usage(); 621 } 622 ifidx = ifr.ifr_ifindex; 623 } 624 625 pset[1].fd = -1; 626 if (listen_arp) { 627 pset[1].fd = socket(PF_PACKET, SOCK_DGRAM, 0); 628 if (pset[1].fd >= 0) { 629 load_arp_bpflet(pset[1].fd); 630 psize = 1; 631 } 632 } 633 634 if (pset[1].fd >= 0) { 635 struct sockaddr_ll sll; 636 memset(&sll, 0, sizeof(sll)); 637 sll.sll_family = AF_PACKET; 638 sll.sll_protocol = htons(ETH_P_ARP); 639 sll.sll_ifindex = all_ifaces ? 0 : ifidx; 640 if (bind(pset[1].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) { 641 close(pset[1].fd); 642 pset[1].fd = -1; 643 psize = 1; 644 } 645 } 646 if (pset[0].fd >= 0) { 647 struct sockaddr_ll sll; 648 memset(&sll, 0, sizeof(sll)); 649 sll.sll_family = AF_PACKET; 650 sll.sll_protocol = htons(ETH_P_RARP); 651 sll.sll_ifindex = all_ifaces ? 0 : ifidx; 652 if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) { 653 close(pset[0].fd); 654 pset[0].fd = -1; 655 } 656 } 657 if (pset[0].fd < 0) { 658 pset[0] = pset[1]; 659 psize--; 660 } 661 if (psize == 0) { 662 fprintf(stderr, "failed to bind any socket. Aborting.\n"); 663 exit(1); 664 } 665 666 if (!debug) { 667 int fd; 668 pid_t pid = fork(); 669 670 if (pid > 0) 671 exit(0); 672 else if (pid == -1) { 673 perror("rarpd: fork"); 674 exit(1); 675 } 676 677 if (chdir("/") < 0) { 678 perror("rarpd: chdir"); 679 exit(1); 680 } 681 682 fd = open("/dev/null", O_RDWR); 683 if (fd >= 0) { 684 dup2(fd, 0); 685 dup2(fd, 1); 686 dup2(fd, 2); 687 if (fd > 2) 688 close(fd); 689 } 690 setsid(); 691 } 692 693 openlog("rarpd", LOG_PID | LOG_CONS, LOG_DAEMON); 694 catch_signal(SIGALRM, sig_alarm); 695 catch_signal(SIGHUP, sig_hup); 696 697 for (;;) { 698 int i; 699 700 if (do_reload) { 701 configure(); 702 do_reload = 0; 703 } 704 705 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP) 706 pset[0].events = EVENTS; 707 pset[0].revents = 0; 708 pset[1].events = EVENTS; 709 pset[1].revents = 0; 710 711 i = poll(pset, psize, -1); 712 if (i <= 0) { 713 if (errno != EINTR && i<0) { 714 syslog(LOG_ERR, "poll returned some crap: %m\n"); 715 sleep(10); 716 } 717 continue; 718 } 719 for (i=0; i<psize; i++) { 720 if (pset[i].revents&EVENTS) 721 serve_it(pset[i].fd); 722 } 723 } 724 } 725