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