1 /* 2 * arpd.c ARP helper 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 <malloc.h> 15 #include <string.h> 16 #include <unistd.h> 17 #include <stdlib.h> 18 #include <netdb.h> 19 #include <db_185.h> 20 #include <sys/ioctl.h> 21 #include <sys/poll.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <sys/uio.h> 25 #include <sys/socket.h> 26 #include <sys/time.h> 27 #include <time.h> 28 #include <signal.h> 29 #include <linux/if.h> 30 #include <linux/if_ether.h> 31 #include <linux/if_arp.h> 32 #include <netinet/in.h> 33 #include <arpa/inet.h> 34 #include <linux/if_packet.h> 35 #include <linux/filter.h> 36 37 #include "libnetlink.h" 38 #include "utils.h" 39 40 int resolve_hosts; 41 42 DB *dbase; 43 char *dbname = "/var/lib/arpd/arpd.db"; 44 45 int ifnum; 46 int *ifvec; 47 char **ifnames; 48 49 struct dbkey 50 { 51 __u32 iface; 52 __u32 addr; 53 }; 54 55 #define IS_NEG(x) (((__u8*)(x))[0] == 0xFF) 56 #define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5]) 57 #define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8*)x)) 58 #define NEG_VALID(x) (NEG_AGE(x) < negative_timeout) 59 #define NEG_CNT(x) (((__u8*)(x))[1]) 60 61 struct rtnl_handle rth; 62 63 struct pollfd pset[2]; 64 int udp_sock = -1; 65 66 volatile int do_exit; 67 volatile int do_sync; 68 volatile int do_stats; 69 70 struct { 71 unsigned long arp_new; 72 unsigned long arp_change; 73 74 unsigned long app_recv; 75 unsigned long app_success; 76 unsigned long app_bad; 77 unsigned long app_neg; 78 unsigned long app_suppressed; 79 80 unsigned long kern_neg; 81 unsigned long kern_new; 82 unsigned long kern_change; 83 84 unsigned long probes_sent; 85 unsigned long probes_suppressed; 86 } stats; 87 88 int active_probing; 89 int negative_timeout = 60; 90 int no_kernel_broadcasts; 91 int broadcast_rate = 1000; 92 int broadcast_burst = 3000; 93 int poll_timeout = 30000; 94 95 void usage(void) 96 { 97 fprintf(stderr, 98 "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ]" 99 " [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n"); 100 exit(1); 101 } 102 103 int handle_if(int ifindex) 104 { 105 int i; 106 107 if (ifnum == 0) 108 return 1; 109 110 for (i=0; i<ifnum; i++) 111 if (ifvec[i] == ifindex) 112 return 1; 113 return 0; 114 } 115 116 int sysctl_adjusted; 117 118 void do_sysctl_adjustments(void) 119 { 120 int i; 121 122 if (!ifnum) 123 return; 124 125 for (i=0; i<ifnum; i++) { 126 char buf[128]; 127 FILE *fp; 128 129 if (active_probing) { 130 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]); 131 if ((fp = fopen(buf, "w")) != NULL) { 132 if (no_kernel_broadcasts) 133 strcpy(buf, "0\n"); 134 else 135 sprintf(buf, "%d\n", active_probing>=2 ? 1 : 3-active_probing); 136 fputs(buf, fp); 137 fclose(fp); 138 } 139 } 140 141 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]); 142 if ((fp = fopen(buf, "w")) != NULL) { 143 sprintf(buf, "%d\n", active_probing<=1 ? 1 : active_probing); 144 fputs(buf, fp); 145 fclose(fp); 146 } 147 } 148 sysctl_adjusted = 1; 149 } 150 151 void undo_sysctl_adjustments(void) 152 { 153 int i; 154 155 if (!sysctl_adjusted) 156 return; 157 158 for (i=0; i<ifnum; i++) { 159 char buf[128]; 160 FILE *fp; 161 162 if (active_probing) { 163 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]); 164 if ((fp = fopen(buf, "w")) != NULL) { 165 strcpy(buf, "3\n"); 166 fputs(buf, fp); 167 fclose(fp); 168 } 169 } 170 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]); 171 if ((fp = fopen(buf, "w")) != NULL) { 172 strcpy(buf, "0\n"); 173 fputs(buf, fp); 174 fclose(fp); 175 } 176 } 177 sysctl_adjusted = 0; 178 } 179 180 181 int send_probe(int ifindex, __u32 addr) 182 { 183 struct ifreq ifr; 184 struct sockaddr_in dst; 185 socklen_t len; 186 unsigned char buf[256]; 187 struct arphdr *ah = (struct arphdr*)buf; 188 unsigned char *p = (unsigned char *)(ah+1); 189 struct sockaddr_ll sll; 190 191 memset(&ifr, 0, sizeof(ifr)); 192 ifr.ifr_ifindex = ifindex; 193 if (ioctl(udp_sock, SIOCGIFNAME, &ifr)) 194 return -1; 195 if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr)) 196 return -1; 197 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) 198 return -1; 199 if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0) 200 return -1; 201 202 dst.sin_family = AF_INET; 203 dst.sin_port = htons(1025); 204 dst.sin_addr.s_addr = addr; 205 if (connect(udp_sock, (struct sockaddr*)&dst, sizeof(dst)) < 0) 206 return -1; 207 len = sizeof(dst); 208 if (getsockname(udp_sock, (struct sockaddr*)&dst, &len) < 0) 209 return -1; 210 211 ah->ar_hrd = htons(ifr.ifr_hwaddr.sa_family); 212 ah->ar_pro = htons(ETH_P_IP); 213 ah->ar_hln = 6; 214 ah->ar_pln = 4; 215 ah->ar_op = htons(ARPOP_REQUEST); 216 217 memcpy(p, ifr.ifr_hwaddr.sa_data, ah->ar_hln); 218 p += ah->ar_hln; 219 220 memcpy(p, &dst.sin_addr, 4); 221 p+=4; 222 223 sll.sll_family = AF_PACKET; 224 memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr)); 225 sll.sll_ifindex = ifindex; 226 sll.sll_protocol = htons(ETH_P_ARP); 227 memcpy(p, &sll.sll_addr, ah->ar_hln); 228 p+=ah->ar_hln; 229 230 memcpy(p, &addr, 4); 231 p+=4; 232 233 if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr*)&sll, sizeof(sll)) < 0) 234 return -1; 235 stats.probes_sent++; 236 return 0; 237 } 238 239 /* Be very tough on sending probes: 1 per second with burst of 3. */ 240 241 int queue_active_probe(int ifindex, __u32 addr) 242 { 243 static struct timeval prev; 244 static int buckets; 245 struct timeval now; 246 247 gettimeofday(&now, NULL); 248 if (prev.tv_sec) { 249 int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000; 250 buckets += diff; 251 } else { 252 buckets = broadcast_burst; 253 } 254 if (buckets > broadcast_burst) 255 buckets = broadcast_burst; 256 if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) { 257 buckets -= broadcast_rate; 258 prev = now; 259 return 0; 260 } 261 stats.probes_suppressed++; 262 return -1; 263 } 264 265 int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen) 266 { 267 struct { 268 struct nlmsghdr n; 269 struct ndmsg ndm; 270 char buf[256]; 271 } req; 272 273 memset(&req.n, 0, sizeof(req.n)); 274 memset(&req.ndm, 0, sizeof(req.ndm)); 275 276 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); 277 req.n.nlmsg_flags = NLM_F_REQUEST; 278 req.n.nlmsg_type = RTM_NEWNEIGH; 279 req.ndm.ndm_family = AF_INET; 280 req.ndm.ndm_state = NUD_STALE; 281 req.ndm.ndm_ifindex = ifindex; 282 req.ndm.ndm_type = RTN_UNICAST; 283 284 addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); 285 addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); 286 return rtnl_send(&rth, &req, req.n.nlmsg_len) <= 0; 287 } 288 289 void prepare_neg_entry(__u8 *ndata, __u32 stamp) 290 { 291 ndata[0] = 0xFF; 292 ndata[1] = 0; 293 ndata[2] = stamp>>24; 294 ndata[3] = stamp>>16; 295 ndata[4] = stamp>>8; 296 ndata[5] = stamp; 297 } 298 299 300 int do_one_request(struct nlmsghdr *n) 301 { 302 struct ndmsg *ndm = NLMSG_DATA(n); 303 int len = n->nlmsg_len; 304 struct rtattr * tb[NDA_MAX+1]; 305 struct dbkey key; 306 DBT dbkey, dbdat; 307 int do_acct = 0; 308 309 if (n->nlmsg_type == NLMSG_DONE) { 310 dbase->sync(dbase, 0); 311 312 /* Now we have at least mirror of kernel db, so that 313 * may start real resolution. 314 */ 315 do_sysctl_adjustments(); 316 return 0; 317 } 318 319 if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH) 320 return 0; 321 322 len -= NLMSG_LENGTH(sizeof(*ndm)); 323 if (len < 0) 324 return -1; 325 326 if (ndm->ndm_family != AF_INET || 327 (ifnum && !handle_if(ndm->ndm_ifindex)) || 328 ndm->ndm_flags || 329 ndm->ndm_type != RTN_UNICAST || 330 !(ndm->ndm_state&~NUD_NOARP)) 331 return 0; 332 333 parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len); 334 335 if (!tb[NDA_DST]) 336 return 0; 337 338 key.iface = ndm->ndm_ifindex; 339 memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4); 340 dbkey.data = &key; 341 dbkey.size = sizeof(key); 342 343 if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) { 344 dbdat.data = 0; 345 dbdat.size = 0; 346 } 347 348 if (n->nlmsg_type == RTM_GETNEIGH) { 349 if (!(n->nlmsg_flags&NLM_F_REQUEST)) 350 return 0; 351 352 if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) { 353 stats.app_bad++; 354 return 0; 355 } 356 357 if (ndm->ndm_state&NUD_PROBE) { 358 /* If we get this, kernel still has some valid 359 * address, but unicast probing failed and host 360 * is either dead or changed its mac address. 361 * Kernel is going to initiate broadcast resolution. 362 * OK, we invalidate our information as well. 363 */ 364 if (dbdat.data && !IS_NEG(dbdat.data)) 365 stats.app_neg++; 366 367 dbase->del(dbase, &dbkey, 0); 368 } else { 369 /* If we get this kernel does not have any information. 370 * If we have something tell this to kernel. */ 371 stats.app_recv++; 372 if (dbdat.data && !IS_NEG(dbdat.data)) { 373 stats.app_success++; 374 respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size); 375 return 0; 376 } 377 378 /* Sheeit! We have nothing to tell. */ 379 /* If we have recent negative entry, be silent. */ 380 if (dbdat.data && NEG_VALID(dbdat.data)) { 381 if (NEG_CNT(dbdat.data) >= active_probing) { 382 stats.app_suppressed++; 383 return 0; 384 } 385 do_acct = 1; 386 } 387 } 388 389 if (active_probing && 390 queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 && 391 do_acct) { 392 NEG_CNT(dbdat.data)++; 393 dbase->put(dbase, &dbkey, &dbdat, 0); 394 } 395 } else if (n->nlmsg_type == RTM_NEWNEIGH) { 396 if (n->nlmsg_flags&NLM_F_REQUEST) 397 return 0; 398 399 if (ndm->ndm_state&NUD_FAILED) { 400 /* Kernel was not able to resolve. Host is dead. 401 * Create negative entry if it is not present 402 * or renew it if it is too old. */ 403 if (!dbdat.data || 404 !IS_NEG(dbdat.data) || 405 !NEG_VALID(dbdat.data)) { 406 __u8 ndata[6]; 407 stats.kern_neg++; 408 prepare_neg_entry(ndata, time(NULL)); 409 dbdat.data = ndata; 410 dbdat.size = sizeof(ndata); 411 dbase->put(dbase, &dbkey, &dbdat, 0); 412 } 413 } else if (tb[NDA_LLADDR]) { 414 if (dbdat.data && !IS_NEG(dbdat.data)) { 415 if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0) 416 return 0; 417 stats.kern_change++; 418 } else { 419 stats.kern_new++; 420 } 421 dbdat.data = RTA_DATA(tb[NDA_LLADDR]); 422 dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]); 423 dbase->put(dbase, &dbkey, &dbdat, 0); 424 } 425 } 426 return 0; 427 } 428 429 void load_initial_table(void) 430 { 431 rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH); 432 } 433 434 void get_kern_msg(void) 435 { 436 int status; 437 struct nlmsghdr *h; 438 struct sockaddr_nl nladdr; 439 struct iovec iov; 440 char buf[8192]; 441 struct msghdr msg = { 442 (void*)&nladdr, sizeof(nladdr), 443 &iov, 1, 444 NULL, 0, 445 0 446 }; 447 448 memset(&nladdr, 0, sizeof(nladdr)); 449 450 iov.iov_base = buf; 451 iov.iov_len = sizeof(buf); 452 453 status = recvmsg(rth.fd, &msg, MSG_DONTWAIT); 454 455 if (status <= 0) 456 return; 457 458 if (msg.msg_namelen != sizeof(nladdr)) 459 return; 460 461 if (nladdr.nl_pid) 462 return; 463 464 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { 465 int len = h->nlmsg_len; 466 int l = len - sizeof(*h); 467 468 if (l < 0 || len > status) 469 return; 470 471 if (do_one_request(h) < 0) 472 return; 473 474 status -= NLMSG_ALIGN(len); 475 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 476 } 477 } 478 479 /* Receive gratuitous ARP messages and store them, that's all. */ 480 void get_arp_pkt(void) 481 { 482 unsigned char buf[1024]; 483 struct sockaddr_ll sll; 484 socklen_t sll_len = sizeof(sll); 485 struct arphdr *a = (struct arphdr*)buf; 486 struct dbkey key; 487 DBT dbkey, dbdat; 488 int n; 489 490 n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT, 491 (struct sockaddr*)&sll, &sll_len); 492 if (n < 0) { 493 if (errno != EINTR && errno != EAGAIN) 494 syslog(LOG_ERR, "recvfrom: %m"); 495 return; 496 } 497 498 if (ifnum && !handle_if(sll.sll_ifindex)) 499 return; 500 501 /* Sanity checks */ 502 503 if (n < sizeof(*a) || 504 (a->ar_op != htons(ARPOP_REQUEST) && 505 a->ar_op != htons(ARPOP_REPLY)) || 506 a->ar_pln != 4 || 507 a->ar_pro != htons(ETH_P_IP) || 508 a->ar_hln != sll.sll_halen || 509 sizeof(*a) + 2*4 + 2*a->ar_hln > n) 510 return; 511 512 key.iface = sll.sll_ifindex; 513 memcpy(&key.addr, (char*)(a+1) + a->ar_hln, 4); 514 515 /* DAD message, ignore. */ 516 if (key.addr == 0) 517 return; 518 519 dbkey.data = &key; 520 dbkey.size = sizeof(key); 521 522 if (dbase->get(dbase, &dbkey, &dbdat, 0) == 0 && !IS_NEG(dbdat.data)) { 523 if (memcmp(dbdat.data, a+1, dbdat.size) == 0) 524 return; 525 stats.arp_change++; 526 } else { 527 stats.arp_new++; 528 } 529 530 dbdat.data = a+1; 531 dbdat.size = a->ar_hln; 532 dbase->put(dbase, &dbkey, &dbdat, 0); 533 } 534 535 void catch_signal(int sig, void (*handler)(int)) 536 { 537 struct sigaction sa; 538 539 memset(&sa, 0, sizeof(sa)); 540 sa.sa_handler = handler; 541 #ifdef SA_INTERRUPT 542 sa.sa_flags = SA_INTERRUPT; 543 #endif 544 sigaction(sig, &sa, NULL); 545 } 546 547 #include <setjmp.h> 548 sigjmp_buf env; 549 volatile int in_poll; 550 551 void sig_exit(int signo) 552 { 553 do_exit = 1; 554 if (in_poll) 555 siglongjmp(env, 1); 556 } 557 558 void sig_sync(int signo) 559 { 560 do_sync = 1; 561 if (in_poll) 562 siglongjmp(env, 1); 563 } 564 565 void sig_stats(int signo) 566 { 567 do_sync = 1; 568 do_stats = 1; 569 if (in_poll) 570 siglongjmp(env, 1); 571 } 572 573 void send_stats(void) 574 { 575 syslog(LOG_INFO, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu", 576 stats.arp_new, stats.arp_change, 577 578 stats.app_recv, stats.app_success, 579 stats.app_bad, stats.app_neg, stats.app_suppressed 580 ); 581 syslog(LOG_INFO, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu", 582 stats.kern_new, stats.kern_change, stats.kern_neg, 583 584 stats.probes_sent, stats.probes_suppressed 585 ); 586 do_stats = 0; 587 } 588 589 590 int main(int argc, char **argv) 591 { 592 int opt; 593 int do_list = 0; 594 char *do_load = NULL; 595 596 while ((opt = getopt(argc, argv, "h?b:lf:a:n:p:kR:B:")) != EOF) { 597 switch (opt) { 598 case 'b': 599 dbname = optarg; 600 break; 601 case 'f': 602 if (do_load) { 603 fprintf(stderr, "Duplicate option -f\n"); 604 usage(); 605 } 606 do_load = optarg; 607 break; 608 case 'l': 609 do_list = 1; 610 break; 611 case 'a': 612 active_probing = atoi(optarg); 613 break; 614 case 'n': 615 negative_timeout = atoi(optarg); 616 break; 617 case 'k': 618 no_kernel_broadcasts = 1; 619 break; 620 case 'p': 621 if ((poll_timeout = 1000 * strtod(optarg, NULL)) < 100) { 622 fprintf(stderr,"Invalid poll timeout\n"); 623 exit(-1); 624 } 625 break; 626 case 'R': 627 if ((broadcast_rate = atoi(optarg)) <= 0 || 628 (broadcast_rate = 1000/broadcast_rate) <= 0) { 629 fprintf(stderr, "Invalid ARP rate\n"); 630 exit(-1); 631 } 632 break; 633 case 'B': 634 if ((broadcast_burst = atoi(optarg)) <= 0 || 635 (broadcast_burst = 1000*broadcast_burst) <= 0) { 636 fprintf(stderr, "Invalid ARP burst\n"); 637 exit(-1); 638 } 639 break; 640 case 'h': 641 case '?': 642 default: 643 usage(); 644 } 645 } 646 argc -= optind; 647 argv += optind; 648 649 if (argc > 0) { 650 ifnum = argc; 651 ifnames = argv; 652 ifvec = malloc(argc*sizeof(int)); 653 if (!ifvec) { 654 perror("malloc"); 655 exit(-1); 656 } 657 } 658 659 if ((udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 660 perror("socket"); 661 exit(-1); 662 } 663 664 if (ifnum) { 665 int i; 666 struct ifreq ifr; 667 memset(&ifr, 0, sizeof(ifr)); 668 for (i=0; i<ifnum; i++) { 669 strncpy(ifr.ifr_name, ifnames[i], IFNAMSIZ); 670 if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) { 671 perror("ioctl(SIOCGIFINDEX)"); 672 exit(-1);; 673 } 674 ifvec[i] = ifr.ifr_ifindex; 675 } 676 } 677 678 dbase = dbopen(dbname, O_CREAT|O_RDWR, 0644, DB_HASH, NULL); 679 if (dbase == NULL) { 680 perror("db_open"); 681 exit(-1); 682 } 683 684 if (do_load) { 685 char buf[128]; 686 FILE *fp; 687 struct dbkey k; 688 DBT dbkey, dbdat; 689 690 dbkey.data = &k; 691 dbkey.size = sizeof(k); 692 693 if (strcmp(do_load, "-") == 0 || strcmp(do_load, "--") == 0) { 694 fp = stdin; 695 } else if ((fp = fopen(do_load, "r")) == NULL) { 696 perror("fopen"); 697 goto do_abort; 698 } 699 700 buf[sizeof(buf)-1] = 0; 701 while (fgets(buf, sizeof(buf)-1, fp)) { 702 __u8 b1[6]; 703 char ipbuf[128]; 704 char macbuf[128]; 705 706 if (buf[0] == '#') 707 continue; 708 709 if (sscanf(buf, "%u%s%s", &k.iface, ipbuf, macbuf) != 3) { 710 fprintf(stderr, "Wrong format of input file \"%s\"\n", do_load); 711 goto do_abort; 712 } 713 if (strncmp(macbuf, "FAILED:", 7) == 0) 714 continue; 715 if (!inet_aton(ipbuf, (struct in_addr*)&k.addr)) { 716 fprintf(stderr, "Invalid IP address: \"%s\"\n", ipbuf); 717 goto do_abort; 718 } 719 720 dbdat.data = hexstring_a2n(macbuf, b1, 6); 721 if (dbdat.data == NULL) 722 goto do_abort; 723 dbdat.size = 6; 724 725 if (dbase->put(dbase, &dbkey, &dbdat, 0)) { 726 perror("hash->put"); 727 goto do_abort; 728 } 729 } 730 dbase->sync(dbase, 0); 731 if (fp != stdin) 732 fclose(fp); 733 } 734 735 if (do_list) { 736 DBT dbkey, dbdat; 737 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC"); 738 while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) { 739 struct dbkey *key = dbkey.data; 740 if (handle_if(key->iface)) { 741 if (!IS_NEG(dbdat.data)) { 742 char b1[18]; 743 printf("%-8d %-15s %s\n", 744 key->iface, 745 inet_ntoa(*(struct in_addr*)&key->addr), 746 hexstring_n2a(dbdat.data, 6, b1, 18)); 747 } else { 748 printf("%-8d %-15s FAILED: %dsec ago\n", 749 key->iface, 750 inet_ntoa(*(struct in_addr*)&key->addr), 751 NEG_AGE(dbdat.data)); 752 } 753 } 754 } 755 } 756 757 if (do_load || do_list) 758 goto out; 759 760 pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0); 761 if (pset[0].fd < 0) { 762 perror("socket"); 763 exit(-1); 764 } 765 766 if (1) { 767 struct sockaddr_ll sll; 768 memset(&sll, 0, sizeof(sll)); 769 sll.sll_family = AF_PACKET; 770 sll.sll_protocol = htons(ETH_P_ARP); 771 sll.sll_ifindex = (ifnum == 1 ? ifvec[0] : 0); 772 if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) { 773 perror("bind"); 774 goto do_abort; 775 } 776 } 777 778 if (rtnl_open(&rth, RTMGRP_NEIGH) < 0) { 779 perror("rtnl_open"); 780 goto do_abort; 781 } 782 pset[1].fd = rth.fd; 783 784 load_initial_table(); 785 786 if (daemon(0, 0)) { 787 perror("arpd: daemon"); 788 goto do_abort; 789 } 790 791 openlog("arpd", LOG_PID | LOG_CONS, LOG_DAEMON); 792 catch_signal(SIGINT, sig_exit); 793 catch_signal(SIGTERM, sig_exit); 794 catch_signal(SIGHUP, sig_sync); 795 catch_signal(SIGUSR1, sig_stats); 796 797 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP) 798 pset[0].events = EVENTS; 799 pset[0].revents = 0; 800 pset[1].events = EVENTS; 801 pset[1].revents = 0; 802 803 sigsetjmp(env, 1); 804 805 for (;;) { 806 in_poll = 1; 807 808 if (do_exit) 809 break; 810 if (do_sync) { 811 in_poll = 0; 812 dbase->sync(dbase, 0); 813 do_sync = 0; 814 in_poll = 1; 815 } 816 if (do_stats) 817 send_stats(); 818 if (poll(pset, 2, poll_timeout) > 0) { 819 in_poll = 0; 820 if (pset[0].revents&EVENTS) 821 get_arp_pkt(); 822 if (pset[1].revents&EVENTS) 823 get_kern_msg(); 824 } else { 825 do_sync = 1; 826 } 827 } 828 829 undo_sysctl_adjustments(); 830 out: 831 dbase->close(dbase); 832 exit(0); 833 834 do_abort: 835 dbase->close(dbase); 836 exit(-1); 837 } 838