]>
git.proxmox.com Git - mirror_iproute2.git/blob - misc/arpd.c
2 * arpd.c ARP helper daemon.
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
20 #include <sys/ioctl.h>
25 #include <sys/socket.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>
37 #include "libnetlink.h"
42 char *dbname
= "/var/lib/arpd/arpd.db";
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])
59 struct rtnl_handle rth
;
61 struct pollfd pset
[2];
66 volatile int do_stats
;
69 unsigned long arp_new
;
70 unsigned long arp_change
;
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
;
78 unsigned long kern_neg
;
79 unsigned long kern_new
;
80 unsigned long kern_change
;
82 unsigned long probes_sent
;
83 unsigned long probes_suppressed
;
87 int negative_timeout
= 60;
88 int no_kernel_broadcasts
;
89 int broadcast_rate
= 1000;
90 int broadcast_burst
= 3000;
91 int poll_timeout
= 30000;
93 static void usage(void)
96 "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ] [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n");
100 static int handle_if(int ifindex
)
107 for (i
= 0; i
< ifnum
; i
++)
108 if (ifvec
[i
] == ifindex
)
115 static void do_sysctl_adjustments(void)
122 for (i
= 0; i
< ifnum
; i
++) {
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
)
132 sprintf(buf
, "%d\n", active_probing
>= 2 ? 1 : 3-active_probing
);
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
);
148 static void undo_sysctl_adjustments(void)
152 if (!sysctl_adjusted
)
155 for (i
= 0; i
< ifnum
; i
++) {
159 if (active_probing
) {
160 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames
[i
]);
161 if ((fp
= fopen(buf
, "w")) != NULL
) {
167 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames
[i
]);
168 if ((fp
= fopen(buf
, "w")) != NULL
) {
178 static int send_probe(int ifindex
, __u32 addr
)
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
,
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
),
196 if (ioctl(udp_sock
, SIOCGIFNAME
, &ifr
))
198 if (ioctl(udp_sock
, SIOCGIFHWADDR
, &ifr
))
200 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
)
202 if (setsockopt(udp_sock
, SOL_SOCKET
, SO_BINDTODEVICE
, ifr
.ifr_name
, strlen(ifr
.ifr_name
)+1) < 0)
205 if (connect(udp_sock
, (struct sockaddr
*)&dst
, sizeof(dst
)) < 0)
208 if (getsockname(udp_sock
, (struct sockaddr
*)&dst
, &len
) < 0)
211 ah
->ar_hrd
= htons(ifr
.ifr_hwaddr
.sa_family
);
212 ah
->ar_pro
= htons(ETH_P_IP
);
215 ah
->ar_op
= htons(ARPOP_REQUEST
);
217 memcpy(p
, ifr
.ifr_hwaddr
.sa_data
, ah
->ar_hln
);
220 memcpy(p
, &dst
.sin_addr
, 4);
223 memset(sll
.sll_addr
, 0xFF, sizeof(sll
.sll_addr
));
224 memcpy(p
, &sll
.sll_addr
, ah
->ar_hln
);
230 if (sendto(pset
[0].fd
, buf
, p
-buf
, 0, (struct sockaddr
*)&sll
, sizeof(sll
)) < 0)
236 /* Be very tough on sending probes: 1 per second with burst of 3. */
238 static int queue_active_probe(int ifindex
, __u32 addr
)
240 static struct timeval prev
;
244 gettimeofday(&now
, NULL
);
246 int diff
= (now
.tv_sec
-prev
.tv_sec
)*1000+(now
.tv_usec
-prev
.tv_usec
)/1000;
250 buckets
= broadcast_burst
;
252 if (buckets
> broadcast_burst
)
253 buckets
= broadcast_burst
;
254 if (buckets
>= broadcast_rate
&& !send_probe(ifindex
, addr
)) {
255 buckets
-= broadcast_rate
;
259 stats
.probes_suppressed
++;
263 static int respond_to_kernel(int ifindex
, __u32 addr
, char *lla
, int llalen
)
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
,
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;
284 static void prepare_neg_entry(__u8
*ndata
, __u32 stamp
)
288 ndata
[2] = stamp
>>24;
289 ndata
[3] = stamp
>>16;
295 static int do_one_request(struct nlmsghdr
*n
)
297 struct ndmsg
*ndm
= NLMSG_DATA(n
);
298 int len
= n
->nlmsg_len
;
299 struct rtattr
*tb
[NDA_MAX
+1];
304 if (n
->nlmsg_type
== NLMSG_DONE
) {
305 dbase
->sync(dbase
, 0);
307 /* Now we have at least mirror of kernel db, so that
308 * may start real resolution.
310 do_sysctl_adjustments();
314 if (n
->nlmsg_type
!= RTM_GETNEIGH
&& n
->nlmsg_type
!= RTM_NEWNEIGH
)
317 len
-= NLMSG_LENGTH(sizeof(*ndm
));
321 if (ndm
->ndm_family
!= AF_INET
||
322 (ifnum
&& !handle_if(ndm
->ndm_ifindex
)) ||
324 ndm
->ndm_type
!= RTN_UNICAST
||
325 !(ndm
->ndm_state
&~NUD_NOARP
))
328 parse_rtattr(tb
, NDA_MAX
, NDA_RTA(ndm
), len
);
333 key
.iface
= ndm
->ndm_ifindex
;
334 memcpy(&key
.addr
, RTA_DATA(tb
[NDA_DST
]), 4);
336 dbkey
.size
= sizeof(key
);
338 if (dbase
->get(dbase
, &dbkey
, &dbdat
, 0) != 0) {
343 if (n
->nlmsg_type
== RTM_GETNEIGH
) {
344 if (!(n
->nlmsg_flags
&NLM_F_REQUEST
))
347 if (!(ndm
->ndm_state
&(NUD_PROBE
|NUD_INCOMPLETE
))) {
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.
359 if (dbdat
.data
&& !IS_NEG(dbdat
.data
))
362 dbase
->del(dbase
, &dbkey
, 0);
364 /* If we get this kernel does not have any information.
365 * If we have something tell this to kernel. */
367 if (dbdat
.data
&& !IS_NEG(dbdat
.data
)) {
369 respond_to_kernel(key
.iface
, key
.addr
, dbdat
.data
, dbdat
.size
);
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
++;
384 if (active_probing
&&
385 queue_active_probe(ndm
->ndm_ifindex
, key
.addr
) == 0 &&
387 NEG_CNT(dbdat
.data
)++;
388 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
390 } else if (n
->nlmsg_type
== RTM_NEWNEIGH
) {
391 if (n
->nlmsg_flags
&NLM_F_REQUEST
)
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. */
399 !IS_NEG(dbdat
.data
) ||
400 !NEG_VALID(dbdat
.data
)) {
404 prepare_neg_entry(ndata
, time(NULL
));
406 dbdat
.size
= sizeof(ndata
);
407 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
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)
417 dbdat
.data
= RTA_DATA(tb
[NDA_LLADDR
]);
418 dbdat
.size
= RTA_PAYLOAD(tb
[NDA_LLADDR
]);
419 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
425 static void load_initial_table(void)
427 if (rtnl_neighdump_req(&rth
, AF_INET
, NULL
) < 0) {
428 perror("dump request failed");
434 static void get_kern_msg(void)
438 struct sockaddr_nl nladdr
= {};
441 struct msghdr msg
= {
442 (void *)&nladdr
, sizeof(nladdr
),
449 iov
.iov_len
= sizeof(buf
);
451 status
= recvmsg(rth
.fd
, &msg
, MSG_DONTWAIT
);
456 if (msg
.msg_namelen
!= sizeof(nladdr
))
462 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
463 int len
= h
->nlmsg_len
;
464 int l
= len
- sizeof(*h
);
466 if (l
< 0 || len
> status
)
469 if (do_one_request(h
) < 0)
472 status
-= NLMSG_ALIGN(len
);
473 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
477 /* Receive gratuitous ARP messages and store them, that's all. */
478 static void get_arp_pkt(void)
480 unsigned char buf
[1024];
481 struct sockaddr_ll sll
;
482 socklen_t sll_len
= sizeof(sll
);
483 struct arphdr
*a
= (struct arphdr
*)buf
;
488 n
= recvfrom(pset
[0].fd
, buf
, sizeof(buf
), MSG_DONTWAIT
,
489 (struct sockaddr
*)&sll
, &sll_len
);
491 if (errno
!= EINTR
&& errno
!= EAGAIN
)
492 syslog(LOG_ERR
, "recvfrom: %m");
496 if (ifnum
&& !handle_if(sll
.sll_ifindex
))
501 if (n
< sizeof(*a
) ||
502 (a
->ar_op
!= htons(ARPOP_REQUEST
) &&
503 a
->ar_op
!= htons(ARPOP_REPLY
)) ||
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
)
510 key
.iface
= sll
.sll_ifindex
;
511 memcpy(&key
.addr
, (char *)(a
+1) + a
->ar_hln
, 4);
513 /* DAD message, ignore. */
518 dbkey
.size
= sizeof(key
);
520 if (dbase
->get(dbase
, &dbkey
, &dbdat
, 0) == 0 && !IS_NEG(dbdat
.data
)) {
521 if (memcmp(dbdat
.data
, a
+1, dbdat
.size
) == 0)
529 dbdat
.size
= a
->ar_hln
;
530 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
533 static void catch_signal(int sig
, void (*handler
)(int))
535 struct sigaction sa
= { .sa_handler
= handler
};
538 sa
.sa_flags
= SA_INTERRUPT
;
540 sigaction(sig
, &sa
, NULL
);
545 volatile int in_poll
;
547 static void sig_exit(int signo
)
554 static void sig_sync(int signo
)
561 static void sig_stats(int signo
)
569 static void send_stats(void)
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
,
574 stats
.app_recv
, stats
.app_success
,
575 stats
.app_bad
, stats
.app_neg
, stats
.app_suppressed
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
,
580 stats
.probes_sent
, stats
.probes_suppressed
586 int main(int argc
, char **argv
)
590 char *do_load
= NULL
;
592 while ((opt
= getopt(argc
, argv
, "h?b:lf:a:n:p:kR:B:")) != EOF
) {
599 fprintf(stderr
, "Duplicate option -f\n");
608 active_probing
= atoi(optarg
);
611 negative_timeout
= atoi(optarg
);
614 no_kernel_broadcasts
= 1;
617 if ((poll_timeout
= 1000 * strtod(optarg
, NULL
)) < 100) {
618 fprintf(stderr
, "Invalid poll timeout\n");
623 if ((broadcast_rate
= atoi(optarg
)) <= 0 ||
624 (broadcast_rate
= 1000/broadcast_rate
) <= 0) {
625 fprintf(stderr
, "Invalid ARP rate\n");
630 if ((broadcast_burst
= atoi(optarg
)) <= 0 ||
631 (broadcast_burst
= 1000*broadcast_burst
) <= 0) {
632 fprintf(stderr
, "Invalid ARP burst\n");
648 ifvec
= malloc(argc
*sizeof(int));
655 if ((udp_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
662 struct ifreq ifr
= {};
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)");
671 ifvec
[i
] = ifr
.ifr_ifindex
;
675 dbase
= dbopen(dbname
, O_CREAT
|O_RDWR
, 0644, DB_HASH
, NULL
);
688 dbkey
.size
= sizeof(k
);
690 if (strcmp(do_load
, "-") == 0 || strcmp(do_load
, "--") == 0) {
692 } else if ((fp
= fopen(do_load
, "r")) == NULL
) {
697 buf
[sizeof(buf
)-1] = 0;
698 while (fgets(buf
, sizeof(buf
), fp
)) {
706 if (sscanf(buf
, "%u%s%s", &k
.iface
, ipbuf
, macbuf
) != 3) {
707 fprintf(stderr
, "Wrong format of input file \"%s\"\n", do_load
);
710 if (strncmp(macbuf
, "FAILED:", 7) == 0)
712 if (!inet_aton(ipbuf
, (struct in_addr
*)&k
.addr
)) {
713 fprintf(stderr
, "Invalid IP address: \"%s\"\n", ipbuf
);
717 if (ll_addr_a2n((char *) b1
, 6, macbuf
) != 6)
721 if (dbase
->put(dbase
, &dbkey
, &dbdat
, 0)) {
726 dbase
->sync(dbase
, 0);
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
;
738 if (handle_if(key
->iface
)) {
739 if (!IS_NEG(dbdat
.data
)) {
742 printf("%-8d %-15s %s\n",
744 inet_ntoa(*(struct in_addr
*)&key
->addr
),
745 ll_addr_n2a(dbdat
.data
, 6, ARPHRD_ETHER
, b1
, 18));
747 printf("%-8d %-15s FAILED: %dsec ago\n",
749 inet_ntoa(*(struct in_addr
*)&key
->addr
),
750 NEG_AGE(dbdat
.data
));
756 if (do_load
|| do_list
)
759 pset
[0].fd
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
760 if (pset
[0].fd
< 0) {
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),
772 if (bind(pset
[0].fd
, (struct sockaddr
*)&sll
, sizeof(sll
)) < 0) {
778 if (rtnl_open(&rth
, RTMGRP_NEIGH
) < 0) {
784 load_initial_table();
787 perror("arpd: daemon");
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
);
797 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
798 pset
[0].events
= EVENTS
;
800 pset
[1].events
= EVENTS
;
812 dbase
->sync(dbase
, 0);
818 if (poll(pset
, 2, poll_timeout
) > 0) {
820 if (pset
[0].revents
&EVENTS
)
822 if (pset
[1].revents
&EVENTS
)
829 undo_sysctl_adjustments();