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