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