iproute2/misc/arpd.c
<<
>>
Prefs
   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
  41DB      *dbase;
  42char    *dbname = "/var/lib/arpd/arpd.db";
  43
  44int     ifnum;
  45int     *ifvec;
  46char    **ifnames;
  47
  48struct dbkey {
  49        __u32   iface;
  50        __u32   addr;
  51};
  52
  53#define IS_NEG(x)       (((__u8 *)(x))[0] == 0xFF)
  54#define NEG_TIME(x)     (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
  55#define NEG_AGE(x)      ((__u32)time(NULL) - NEG_TIME((__u8 *)x))
  56#define NEG_VALID(x)    (NEG_AGE(x) < negative_timeout)
  57#define NEG_CNT(x)      (((__u8 *)(x))[1])
  58
  59struct rtnl_handle rth;
  60
  61struct pollfd pset[2];
  62int udp_sock = -1;
  63
  64volatile int do_exit;
  65volatile int do_sync;
  66volatile int do_stats;
  67
  68struct {
  69        unsigned long arp_new;
  70        unsigned long arp_change;
  71
  72        unsigned long app_recv;
  73        unsigned long app_success;
  74        unsigned long app_bad;
  75        unsigned long app_neg;
  76        unsigned long app_suppressed;
  77
  78        unsigned long kern_neg;
  79        unsigned long kern_new;
  80        unsigned long kern_change;
  81
  82        unsigned long probes_sent;
  83        unsigned long probes_suppressed;
  84} stats;
  85
  86int active_probing;
  87int negative_timeout = 60;
  88int no_kernel_broadcasts;
  89int broadcast_rate = 1000;
  90int broadcast_burst = 3000;
  91int poll_timeout = 30000;
  92
  93static void usage(void)
  94{
  95        fprintf(stderr,
  96                "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ] [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n");
  97        exit(1);
  98}
  99
 100static int handle_if(int ifindex)
 101{
 102        int i;
 103
 104        if (ifnum == 0)
 105                return 1;
 106
 107        for (i = 0; i < ifnum; i++)
 108                if (ifvec[i] == ifindex)
 109                        return 1;
 110        return 0;
 111}
 112
 113int sysctl_adjusted;
 114
 115static void do_sysctl_adjustments(void)
 116{
 117        int i;
 118
 119        if (!ifnum)
 120                return;
 121
 122        for (i = 0; i < ifnum; i++) {
 123                char buf[128];
 124                FILE *fp;
 125
 126                if (active_probing) {
 127                        sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
 128                        if ((fp = fopen(buf, "w")) != NULL) {
 129                                if (no_kernel_broadcasts)
 130                                        strcpy(buf, "0\n");
 131                                else
 132                                        sprintf(buf, "%d\n", active_probing >= 2 ? 1 : 3-active_probing);
 133                                fputs(buf, fp);
 134                                fclose(fp);
 135                        }
 136                }
 137
 138                sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
 139                if ((fp = fopen(buf, "w")) != NULL) {
 140                        sprintf(buf, "%d\n", active_probing <= 1 ? 1 : active_probing);
 141                        fputs(buf, fp);
 142                        fclose(fp);
 143                }
 144        }
 145        sysctl_adjusted = 1;
 146}
 147
 148static void undo_sysctl_adjustments(void)
 149{
 150        int i;
 151
 152        if (!sysctl_adjusted)
 153                return;
 154
 155        for (i = 0; i < ifnum; i++) {
 156                char buf[128];
 157                FILE *fp;
 158
 159                if (active_probing) {
 160                        sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
 161                        if ((fp = fopen(buf, "w")) != NULL) {
 162                                strcpy(buf, "3\n");
 163                                fputs(buf, fp);
 164                                fclose(fp);
 165                        }
 166                }
 167                sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
 168                if ((fp = fopen(buf, "w")) != NULL) {
 169                        strcpy(buf, "0\n");
 170                        fputs(buf, fp);
 171                        fclose(fp);
 172                }
 173        }
 174        sysctl_adjusted = 0;
 175}
 176
 177
 178static int send_probe(int ifindex, __u32 addr)
 179{
 180        struct ifreq ifr = { .ifr_ifindex = ifindex };
 181        struct sockaddr_in dst = {
 182                .sin_family = AF_INET,
 183                .sin_port = htons(1025),
 184                .sin_addr.s_addr = addr,
 185        };
 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                .sll_family = AF_PACKET,
 192                .sll_ifindex = ifindex,
 193                .sll_protocol = htons(ETH_P_ARP),
 194        };
 195
 196        if (ioctl(udp_sock, SIOCGIFNAME, &ifr))
 197                return -1;
 198        if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr))
 199                return -1;
 200        if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
 201                return -1;
 202        if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0)
 203                return -1;
 204
 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        memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr));
 224        memcpy(p, &sll.sll_addr, ah->ar_hln);
 225        p += ah->ar_hln;
 226
 227        memcpy(p, &addr, 4);
 228        p += 4;
 229
 230        if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr *)&sll, sizeof(sll)) < 0)
 231                return -1;
 232        stats.probes_sent++;
 233        return 0;
 234}
 235
 236/* Be very tough on sending probes: 1 per second with burst of 3. */
 237
 238static int queue_active_probe(int ifindex, __u32 addr)
 239{
 240        static struct timeval prev;
 241        static int buckets;
 242        struct timeval now;
 243
 244        gettimeofday(&now, NULL);
 245        if (prev.tv_sec) {
 246                int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000;
 247
 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
 263static 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                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
 271                .n.nlmsg_flags = NLM_F_REQUEST,
 272                .n.nlmsg_type = RTM_NEWNEIGH,
 273                .ndm.ndm_family = AF_INET,
 274                .ndm.ndm_state = NUD_STALE,
 275                .ndm.ndm_ifindex = ifindex,
 276                .ndm.ndm_type = RTN_UNICAST,
 277        };
 278
 279        addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
 280        addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
 281        return rtnl_send(&rth, &req, req.n.nlmsg_len) <= 0;
 282}
 283
 284static void prepare_neg_entry(__u8 *ndata, __u32 stamp)
 285{
 286        ndata[0] = 0xFF;
 287        ndata[1] = 0;
 288        ndata[2] = stamp>>24;
 289        ndata[3] = stamp>>16;
 290        ndata[4] = stamp>>8;
 291        ndata[5] = stamp;
 292}
 293
 294
 295static int do_one_request(struct nlmsghdr *n)
 296{
 297        struct ndmsg *ndm = NLMSG_DATA(n);
 298        int len = n->nlmsg_len;
 299        struct rtattr *tb[NDA_MAX+1];
 300        struct dbkey key;
 301        DBT dbkey, dbdat;
 302        int do_acct = 0;
 303
 304        if (n->nlmsg_type == NLMSG_DONE) {
 305                dbase->sync(dbase, 0);
 306
 307                /* Now we have at least mirror of kernel db, so that
 308                 * may start real resolution.
 309                 */
 310                do_sysctl_adjustments();
 311                return 0;
 312        }
 313
 314        if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH)
 315                return 0;
 316
 317        len -= NLMSG_LENGTH(sizeof(*ndm));
 318        if (len < 0)
 319                return -1;
 320
 321        if (ndm->ndm_family != AF_INET ||
 322            (ifnum && !handle_if(ndm->ndm_ifindex)) ||
 323            ndm->ndm_flags ||
 324            ndm->ndm_type != RTN_UNICAST ||
 325            !(ndm->ndm_state&~NUD_NOARP))
 326                return 0;
 327
 328        parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
 329
 330        if (!tb[NDA_DST])
 331                return 0;
 332
 333        key.iface = ndm->ndm_ifindex;
 334        memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4);
 335        dbkey.data = &key;
 336        dbkey.size = sizeof(key);
 337
 338        if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) {
 339                dbdat.data = 0;
 340                dbdat.size = 0;
 341        }
 342
 343        if (n->nlmsg_type == RTM_GETNEIGH) {
 344                if (!(n->nlmsg_flags&NLM_F_REQUEST))
 345                        return 0;
 346
 347                if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) {
 348                        stats.app_bad++;
 349                        return 0;
 350                }
 351
 352                if (ndm->ndm_state&NUD_PROBE) {
 353                        /* If we get this, kernel still has some valid
 354                         * address, but unicast probing failed and host
 355                         * is either dead or changed its mac address.
 356                         * Kernel is going to initiate broadcast resolution.
 357                         * OK, we invalidate our information as well.
 358                         */
 359                        if (dbdat.data && !IS_NEG(dbdat.data))
 360                                stats.app_neg++;
 361
 362                        dbase->del(dbase, &dbkey, 0);
 363                } else {
 364                        /* If we get this kernel does not have any information.
 365                         * If we have something tell this to kernel. */
 366                        stats.app_recv++;
 367                        if (dbdat.data && !IS_NEG(dbdat.data)) {
 368                                stats.app_success++;
 369                                respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size);
 370                                return 0;
 371                        }
 372
 373                        /* Sheeit! We have nothing to tell. */
 374                        /* If we have recent negative entry, be silent. */
 375                        if (dbdat.data && NEG_VALID(dbdat.data)) {
 376                                if (NEG_CNT(dbdat.data) >= active_probing) {
 377                                        stats.app_suppressed++;
 378                                        return 0;
 379                                }
 380                                do_acct = 1;
 381                        }
 382                }
 383
 384                if (active_probing &&
 385                    queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 &&
 386                    do_acct) {
 387                        NEG_CNT(dbdat.data)++;
 388                        dbase->put(dbase, &dbkey, &dbdat, 0);
 389                }
 390        } else if (n->nlmsg_type == RTM_NEWNEIGH) {
 391                if (n->nlmsg_flags&NLM_F_REQUEST)
 392                        return 0;
 393
 394                if (ndm->ndm_state&NUD_FAILED) {
 395                        /* Kernel was not able to resolve. Host is dead.
 396                         * Create negative entry if it is not present
 397                         * or renew it if it is too old. */
 398                        if (!dbdat.data ||
 399                            !IS_NEG(dbdat.data) ||
 400                            !NEG_VALID(dbdat.data)) {
 401                                __u8 ndata[6];
 402
 403                                stats.kern_neg++;
 404                                prepare_neg_entry(ndata, time(NULL));
 405                                dbdat.data = ndata;
 406                                dbdat.size = sizeof(ndata);
 407                                dbase->put(dbase, &dbkey, &dbdat, 0);
 408                        }
 409                } else if (tb[NDA_LLADDR]) {
 410                        if (dbdat.data && !IS_NEG(dbdat.data)) {
 411                                if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0)
 412                                        return 0;
 413                                stats.kern_change++;
 414                        } else {
 415                                stats.kern_new++;
 416                        }
 417                        dbdat.data = RTA_DATA(tb[NDA_LLADDR]);
 418                        dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]);
 419                        dbase->put(dbase, &dbkey, &dbdat, 0);
 420                }
 421        }
 422        return 0;
 423}
 424
 425static void load_initial_table(void)
 426{
 427        if (rtnl_neighdump_req(&rth, AF_INET, NULL) < 0) {
 428                perror("dump request failed");
 429                exit(1);
 430        }
 431
 432}
 433
 434static 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        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. */
 478static 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
 533static void catch_signal(int sig, void (*handler)(int))
 534{
 535        struct sigaction sa = { .sa_handler = handler };
 536
 537#ifdef SA_INTERRUPT
 538        sa.sa_flags = SA_INTERRUPT;
 539#endif
 540        sigaction(sig, &sa, NULL);
 541}
 542
 543#include <setjmp.h>
 544sigjmp_buf env;
 545volatile int in_poll;
 546
 547static void sig_exit(int signo)
 548{
 549        do_exit = 1;
 550        if (in_poll)
 551                siglongjmp(env, 1);
 552}
 553
 554static void sig_sync(int signo)
 555{
 556        do_sync = 1;
 557        if (in_poll)
 558                siglongjmp(env, 1);
 559}
 560
 561static void sig_stats(int signo)
 562{
 563        do_sync = 1;
 564        do_stats = 1;
 565        if (in_poll)
 566                siglongjmp(env, 1);
 567}
 568
 569static void send_stats(void)
 570{
 571        syslog(LOG_INFO, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu",
 572               stats.arp_new, stats.arp_change,
 573
 574               stats.app_recv, stats.app_success,
 575               stats.app_bad, stats.app_neg, stats.app_suppressed
 576               );
 577        syslog(LOG_INFO, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu",
 578               stats.kern_new, stats.kern_change, stats.kern_neg,
 579
 580               stats.probes_sent, stats.probes_suppressed
 581               );
 582        do_stats = 0;
 583}
 584
 585
 586int main(int argc, char **argv)
 587{
 588        int opt;
 589        int do_list = 0;
 590        char *do_load = NULL;
 591
 592        while ((opt = getopt(argc, argv, "h?b:lf:a:n:p:kR:B:")) != EOF) {
 593                switch (opt) {
 594                case 'b':
 595                        dbname = optarg;
 596                        break;
 597                case 'f':
 598                        if (do_load) {
 599                                fprintf(stderr, "Duplicate option -f\n");
 600                                usage();
 601                        }
 602                        do_load = optarg;
 603                        break;
 604                case 'l':
 605                        do_list = 1;
 606                        break;
 607                case 'a':
 608                        active_probing = atoi(optarg);
 609                        break;
 610                case 'n':
 611                        negative_timeout = atoi(optarg);
 612                        break;
 613                case 'k':
 614                        no_kernel_broadcasts = 1;
 615                        break;
 616                case 'p':
 617                        if ((poll_timeout = 1000 * strtod(optarg, NULL)) < 100) {
 618                                fprintf(stderr, "Invalid poll timeout\n");
 619                                exit(-1);
 620                        }
 621                        break;
 622                case 'R':
 623                        if ((broadcast_rate = atoi(optarg)) <= 0 ||
 624                            (broadcast_rate = 1000/broadcast_rate) <= 0) {
 625                                fprintf(stderr, "Invalid ARP rate\n");
 626                                exit(-1);
 627                        }
 628                        break;
 629                case 'B':
 630                        if ((broadcast_burst = atoi(optarg)) <= 0 ||
 631                            (broadcast_burst = 1000*broadcast_burst) <= 0) {
 632                                fprintf(stderr, "Invalid ARP burst\n");
 633                                exit(-1);
 634                        }
 635                        break;
 636                case 'h':
 637                case '?':
 638                default:
 639                        usage();
 640                }
 641        }
 642        argc -= optind;
 643        argv += optind;
 644
 645        if (argc > 0) {
 646                ifnum = argc;
 647                ifnames = argv;
 648                ifvec = malloc(argc*sizeof(int));
 649                if (!ifvec) {
 650                        perror("malloc");
 651                        exit(-1);
 652                }
 653        }
 654
 655        if ((udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 656                perror("socket");
 657                exit(-1);
 658        }
 659
 660        if (ifnum) {
 661                int i;
 662                struct ifreq ifr = {};
 663
 664                for (i = 0; i < ifnum; i++) {
 665                        if (get_ifname(ifr.ifr_name, ifnames[i]))
 666                                invarg("not a valid ifname", ifnames[i]);
 667                        if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) {
 668                                perror("ioctl(SIOCGIFINDEX)");
 669                                exit(-1);
 670                        }
 671                        ifvec[i] = ifr.ifr_ifindex;
 672                }
 673        }
 674
 675        dbase = dbopen(dbname, O_CREAT|O_RDWR, 0644, DB_HASH, NULL);
 676        if (dbase == NULL) {
 677                perror("db_open");
 678                exit(-1);
 679        }
 680
 681        if (do_load) {
 682                char buf[128];
 683                FILE *fp;
 684                struct dbkey k;
 685                DBT dbkey, dbdat;
 686
 687                dbkey.data = &k;
 688                dbkey.size = sizeof(k);
 689
 690                if (strcmp(do_load, "-") == 0 || strcmp(do_load, "--") == 0) {
 691                        fp = stdin;
 692                } else if ((fp = fopen(do_load, "r")) == NULL) {
 693                        perror("fopen");
 694                        goto do_abort;
 695                }
 696
 697                buf[sizeof(buf)-1] = 0;
 698                while (fgets(buf, sizeof(buf), fp)) {
 699                        __u8 b1[6];
 700                        char ipbuf[128];
 701                        char macbuf[128];
 702
 703                        if (buf[0] == '#')
 704                                continue;
 705
 706                        if (sscanf(buf, "%u%s%s", &k.iface, ipbuf, macbuf) != 3) {
 707                                fprintf(stderr, "Wrong format of input file \"%s\"\n", do_load);
 708                                goto do_abort;
 709                        }
 710                        if (strncmp(macbuf, "FAILED:", 7) == 0)
 711                                continue;
 712                        if (!inet_aton(ipbuf, (struct in_addr *)&k.addr)) {
 713                                fprintf(stderr, "Invalid IP address: \"%s\"\n", ipbuf);
 714                                goto do_abort;
 715                        }
 716
 717                        if (ll_addr_a2n((char *) b1, 6, macbuf) != 6)
 718                                goto do_abort;
 719                        dbdat.size = 6;
 720
 721                        if (dbase->put(dbase, &dbkey, &dbdat, 0)) {
 722                                perror("hash->put");
 723                                goto do_abort;
 724                        }
 725                }
 726                dbase->sync(dbase, 0);
 727                if (fp != stdin)
 728                        fclose(fp);
 729        }
 730
 731        if (do_list) {
 732                DBT dbkey, dbdat;
 733
 734                printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
 735                while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
 736                        struct dbkey *key = dbkey.data;
 737
 738                        if (handle_if(key->iface)) {
 739                                if (!IS_NEG(dbdat.data)) {
 740                                        char b1[18];
 741
 742                                        printf("%-8d %-15s %s\n",
 743                                               key->iface,
 744                                               inet_ntoa(*(struct in_addr *)&key->addr),
 745                                               ll_addr_n2a(dbdat.data, 6, ARPHRD_ETHER, b1, 18));
 746                                } else {
 747                                        printf("%-8d %-15s FAILED: %dsec ago\n",
 748                                               key->iface,
 749                                               inet_ntoa(*(struct in_addr *)&key->addr),
 750                                               NEG_AGE(dbdat.data));
 751                                }
 752                        }
 753                }
 754        }
 755
 756        if (do_load || do_list)
 757                goto out;
 758
 759        pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
 760        if (pset[0].fd < 0) {
 761                perror("socket");
 762                exit(-1);
 763        }
 764
 765        if (1) {
 766                struct sockaddr_ll sll = {
 767                        .sll_family = AF_PACKET,
 768                        .sll_protocol = htons(ETH_P_ARP),
 769                        .sll_ifindex = (ifnum == 1 ? ifvec[0] : 0),
 770                };
 771
 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();
 830out:
 831        dbase->close(dbase);
 832        exit(0);
 833
 834do_abort:
 835        dbase->close(dbase);
 836        exit(-1);
 837}
 838