]> git.proxmox.com Git - mirror_iproute2.git/blame - misc/arpd.c
ss: in --numeric mode, print raw numbers for data rates
[mirror_iproute2.git] / misc / arpd.c
CommitLineData
aba5acdf
SH
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>
16efac57 19#include <db_185.h>
aba5acdf
SH
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>
17ce7fd5 30#include <linux/if_ether.h>
aba5acdf
SH
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"
dd50247d 39#include "rt_names.h"
aba5acdf 40
aba5acdf
SH
41DB *dbase;
42char *dbname = "/var/lib/arpd/arpd.db";
43
ae665a52 44int ifnum;
aba5acdf
SH
45int *ifvec;
46char **ifnames;
47
acd1e437 48struct dbkey {
aba5acdf
SH
49 __u32 iface;
50 __u32 addr;
51};
52
acd1e437 53#define IS_NEG(x) (((__u8 *)(x))[0] == 0xFF)
ae665a52 54#define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
acd1e437 55#define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8 *)x))
aba5acdf 56#define NEG_VALID(x) (NEG_AGE(x) < negative_timeout)
acd1e437 57#define NEG_CNT(x) (((__u8 *)(x))[1])
aba5acdf
SH
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;
0df7db3c 91int poll_timeout = 30000;
aba5acdf 92
d1f28cf1 93static void usage(void)
aba5acdf
SH
94{
95 fprintf(stderr,
acd1e437 96 "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ] [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n");
aba5acdf
SH
97 exit(1);
98}
99
d1f28cf1 100static int handle_if(int ifindex)
aba5acdf
SH
101{
102 int i;
103
104 if (ifnum == 0)
105 return 1;
106
acd1e437 107 for (i = 0; i < ifnum; i++)
aba5acdf
SH
108 if (ifvec[i] == ifindex)
109 return 1;
110 return 0;
111}
112
113int sysctl_adjusted;
114
d1f28cf1 115static void do_sysctl_adjustments(void)
aba5acdf
SH
116{
117 int i;
118
119 if (!ifnum)
120 return;
121
acd1e437 122 for (i = 0; i < ifnum; i++) {
aba5acdf
SH
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
acd1e437 132 sprintf(buf, "%d\n", active_probing >= 2 ? 1 : 3-active_probing);
aba5acdf
SH
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) {
acd1e437 140 sprintf(buf, "%d\n", active_probing <= 1 ? 1 : active_probing);
aba5acdf
SH
141 fputs(buf, fp);
142 fclose(fp);
143 }
144 }
145 sysctl_adjusted = 1;
146}
147
d1f28cf1 148static void undo_sysctl_adjustments(void)
aba5acdf
SH
149{
150 int i;
151
152 if (!sysctl_adjusted)
153 return;
154
acd1e437 155 for (i = 0; i < ifnum; i++) {
aba5acdf
SH
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
d1f28cf1 178static int send_probe(int ifindex, __u32 addr)
aba5acdf 179{
d17b136f
PS
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 };
f332d169 186 socklen_t len;
aba5acdf 187 unsigned char buf[256];
acd1e437 188 struct arphdr *ah = (struct arphdr *)buf;
aba5acdf 189 unsigned char *p = (unsigned char *)(ah+1);
d17b136f
PS
190 struct sockaddr_ll sll = {
191 .sll_family = AF_PACKET,
192 .sll_ifindex = ifindex,
193 .sll_protocol = htons(ETH_P_ARP),
194 };
aba5acdf 195
aba5acdf
SH
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
acd1e437 205 if (connect(udp_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0)
aba5acdf
SH
206 return -1;
207 len = sizeof(dst);
acd1e437 208 if (getsockname(udp_sock, (struct sockaddr *)&dst, &len) < 0)
aba5acdf
SH
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);
acd1e437 221 p += 4;
aba5acdf 222
aba5acdf 223 memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr));
aba5acdf 224 memcpy(p, &sll.sll_addr, ah->ar_hln);
acd1e437 225 p += ah->ar_hln;
aba5acdf
SH
226
227 memcpy(p, &addr, 4);
acd1e437 228 p += 4;
aba5acdf 229
acd1e437 230 if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr *)&sll, sizeof(sll)) < 0)
aba5acdf
SH
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
d1f28cf1 238static int queue_active_probe(int ifindex, __u32 addr)
aba5acdf
SH
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;
acd1e437 247
aba5acdf
SH
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
d1f28cf1 263static int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen)
aba5acdf
SH
264{
265 struct {
acd1e437
SH
266 struct nlmsghdr n;
267 struct ndmsg ndm;
268 char buf[256];
d17b136f
PS
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 };
aba5acdf
SH
278
279 addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
280 addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
6cf8398f 281 return rtnl_send(&rth, &req, req.n.nlmsg_len) <= 0;
aba5acdf
SH
282}
283
d1f28cf1 284static void prepare_neg_entry(__u8 *ndata, __u32 stamp)
aba5acdf
SH
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
d1f28cf1 295static int do_one_request(struct nlmsghdr *n)
aba5acdf
SH
296{
297 struct ndmsg *ndm = NLMSG_DATA(n);
298 int len = n->nlmsg_len;
acd1e437 299 struct rtattr *tb[NDA_MAX+1];
aba5acdf
SH
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
aba5acdf
SH
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];
acd1e437 402
aba5acdf
SH
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
d1f28cf1 425static void load_initial_table(void)
aba5acdf 426{
f255ab12 427 if (rtnl_neighdump_req(&rth, AF_INET, NULL) < 0) {
d2468da0
SH
428 perror("dump request failed");
429 exit(1);
430 }
3d0b7439 431
aba5acdf
SH
432}
433
d1f28cf1 434static void get_kern_msg(void)
aba5acdf
SH
435{
436 int status;
437 struct nlmsghdr *h;
d17b136f 438 struct sockaddr_nl nladdr = {};
aba5acdf
SH
439 struct iovec iov;
440 char buf[8192];
441 struct msghdr msg = {
acd1e437 442 (void *)&nladdr, sizeof(nladdr),
aba5acdf
SH
443 &iov, 1,
444 NULL, 0,
445 0
446 };
447
aba5acdf
SH
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
acd1e437 462 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
aba5acdf
SH
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);
acd1e437 473 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
aba5acdf
SH
474 }
475}
476
477/* Receive gratuitous ARP messages and store them, that's all. */
d1f28cf1 478static void get_arp_pkt(void)
aba5acdf
SH
479{
480 unsigned char buf[1024];
481 struct sockaddr_ll sll;
f332d169 482 socklen_t sll_len = sizeof(sll);
acd1e437 483 struct arphdr *a = (struct arphdr *)buf;
aba5acdf
SH
484 struct dbkey key;
485 DBT dbkey, dbdat;
486 int n;
487
ae665a52 488 n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT,
acd1e437 489 (struct sockaddr *)&sll, &sll_len);
aba5acdf
SH
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;
acd1e437 511 memcpy(&key.addr, (char *)(a+1) + a->ar_hln, 4);
aba5acdf 512
ae665a52 513 /* DAD message, ignore. */
aba5acdf
SH
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
d1f28cf1 533static void catch_signal(int sig, void (*handler)(int))
aba5acdf 534{
d17b136f 535 struct sigaction sa = { .sa_handler = handler };
aba5acdf 536
aba5acdf
SH
537#ifdef SA_INTERRUPT
538 sa.sa_flags = SA_INTERRUPT;
ae665a52 539#endif
aba5acdf
SH
540 sigaction(sig, &sa, NULL);
541}
542
543#include <setjmp.h>
544sigjmp_buf env;
545volatile int in_poll;
546
d1f28cf1 547static void sig_exit(int signo)
aba5acdf
SH
548{
549 do_exit = 1;
550 if (in_poll)
551 siglongjmp(env, 1);
552}
553
d1f28cf1 554static void sig_sync(int signo)
aba5acdf
SH
555{
556 do_sync = 1;
557 if (in_poll)
558 siglongjmp(env, 1);
559}
560
d1f28cf1 561static void sig_stats(int signo)
aba5acdf
SH
562{
563 do_sync = 1;
564 do_stats = 1;
565 if (in_poll)
566 siglongjmp(env, 1);
567}
568
d1f28cf1 569static void send_stats(void)
aba5acdf
SH
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
0df7db3c 592 while ((opt = getopt(argc, argv, "h?b:lf:a:n:p:kR:B:")) != EOF) {
aba5acdf 593 switch (opt) {
acd1e437 594 case 'b':
aba5acdf
SH
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;
0df7db3c
SH
616 case 'p':
617 if ((poll_timeout = 1000 * strtod(optarg, NULL)) < 100) {
acd1e437 618 fprintf(stderr, "Invalid poll timeout\n");
0df7db3c
SH
619 exit(-1);
620 }
621 break;
aba5acdf
SH
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
acd1e437 660 if (ifnum) {
aba5acdf 661 int i;
d17b136f 662 struct ifreq ifr = {};
acd1e437 663
acd1e437 664 for (i = 0; i < ifnum; i++) {
625df645
PS
665 if (get_ifname(ifr.ifr_name, ifnames[i]))
666 invarg("not a valid ifname", ifnames[i]);
aba5acdf
SH
667 if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) {
668 perror("ioctl(SIOCGIFINDEX)");
acd1e437 669 exit(-1);
aba5acdf
SH
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;
61170fd8 698 while (fgets(buf, sizeof(buf), fp)) {
aba5acdf
SH
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;
acd1e437 712 if (!inet_aton(ipbuf, (struct in_addr *)&k.addr)) {
aba5acdf
SH
713 fprintf(stderr, "Invalid IP address: \"%s\"\n", ipbuf);
714 goto do_abort;
715 }
f332d169 716
dd50247d 717 if (ll_addr_a2n((char *) b1, 6, macbuf) != 6)
aba5acdf
SH
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;
acd1e437 733
aba5acdf
SH
734 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
735 while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
ae665a52 736 struct dbkey *key = dbkey.data;
acd1e437 737
aba5acdf
SH
738 if (handle_if(key->iface)) {
739 if (!IS_NEG(dbdat.data)) {
f332d169 740 char b1[18];
acd1e437 741
aba5acdf
SH
742 printf("%-8d %-15s %s\n",
743 key->iface,
acd1e437 744 inet_ntoa(*(struct in_addr *)&key->addr),
dd50247d 745 ll_addr_n2a(dbdat.data, 6, ARPHRD_ETHER, b1, 18));
aba5acdf
SH
746 } else {
747 printf("%-8d %-15s FAILED: %dsec ago\n",
748 key->iface,
acd1e437 749 inet_ntoa(*(struct in_addr *)&key->addr),
aba5acdf
SH
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) {
d17b136f
PS
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 };
acd1e437 771
acd1e437 772 if (bind(pset[0].fd, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
aba5acdf
SH
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
a7a9ddbb
MF
786 if (daemon(0, 0)) {
787 perror("arpd: daemon");
788 goto do_abort;
aba5acdf
SH
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();
0df7db3c 818 if (poll(pset, 2, poll_timeout) > 0) {
aba5acdf
SH
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}