]>
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"
44 char *dbname
= "/var/lib/arpd/arpd.db";
56 #define IS_NEG(x) (((__u8*)(x))[0] == 0xFF)
57 #define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
58 #define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8*)x))
59 #define NEG_VALID(x) (NEG_AGE(x) < negative_timeout)
60 #define NEG_CNT(x) (((__u8*)(x))[1])
62 struct rtnl_handle rth
;
64 struct pollfd pset
[2];
69 volatile int do_stats
;
72 unsigned long arp_new
;
73 unsigned long arp_change
;
75 unsigned long app_recv
;
76 unsigned long app_success
;
77 unsigned long app_bad
;
78 unsigned long app_neg
;
79 unsigned long app_suppressed
;
81 unsigned long kern_neg
;
82 unsigned long kern_new
;
83 unsigned long kern_change
;
85 unsigned long probes_sent
;
86 unsigned long probes_suppressed
;
90 int negative_timeout
= 60;
91 int no_kernel_broadcasts
;
92 int broadcast_rate
= 1000;
93 int broadcast_burst
= 3000;
94 int poll_timeout
= 30000;
96 static void usage(void)
99 "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ]"
100 " [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n");
104 static int handle_if(int ifindex
)
111 for (i
=0; i
<ifnum
; i
++)
112 if (ifvec
[i
] == ifindex
)
119 static void do_sysctl_adjustments(void)
126 for (i
=0; i
<ifnum
; i
++) {
130 if (active_probing
) {
131 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames
[i
]);
132 if ((fp
= fopen(buf
, "w")) != NULL
) {
133 if (no_kernel_broadcasts
)
136 sprintf(buf
, "%d\n", active_probing
>=2 ? 1 : 3-active_probing
);
142 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames
[i
]);
143 if ((fp
= fopen(buf
, "w")) != NULL
) {
144 sprintf(buf
, "%d\n", active_probing
<=1 ? 1 : active_probing
);
152 static void undo_sysctl_adjustments(void)
156 if (!sysctl_adjusted
)
159 for (i
=0; i
<ifnum
; i
++) {
163 if (active_probing
) {
164 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames
[i
]);
165 if ((fp
= fopen(buf
, "w")) != NULL
) {
171 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames
[i
]);
172 if ((fp
= fopen(buf
, "w")) != NULL
) {
182 static int send_probe(int ifindex
, __u32 addr
)
185 struct sockaddr_in dst
;
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
;
192 memset(&ifr
, 0, sizeof(ifr
));
193 ifr
.ifr_ifindex
= ifindex
;
194 if (ioctl(udp_sock
, SIOCGIFNAME
, &ifr
))
196 if (ioctl(udp_sock
, SIOCGIFHWADDR
, &ifr
))
198 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
)
200 if (setsockopt(udp_sock
, SOL_SOCKET
, SO_BINDTODEVICE
, ifr
.ifr_name
, strlen(ifr
.ifr_name
)+1) < 0)
203 dst
.sin_family
= AF_INET
;
204 dst
.sin_port
= htons(1025);
205 dst
.sin_addr
.s_addr
= addr
;
206 if (connect(udp_sock
, (struct sockaddr
*)&dst
, sizeof(dst
)) < 0)
209 if (getsockname(udp_sock
, (struct sockaddr
*)&dst
, &len
) < 0)
212 ah
->ar_hrd
= htons(ifr
.ifr_hwaddr
.sa_family
);
213 ah
->ar_pro
= htons(ETH_P_IP
);
216 ah
->ar_op
= htons(ARPOP_REQUEST
);
218 memcpy(p
, ifr
.ifr_hwaddr
.sa_data
, ah
->ar_hln
);
221 memcpy(p
, &dst
.sin_addr
, 4);
224 sll
.sll_family
= AF_PACKET
;
225 memset(sll
.sll_addr
, 0xFF, sizeof(sll
.sll_addr
));
226 sll
.sll_ifindex
= ifindex
;
227 sll
.sll_protocol
= htons(ETH_P_ARP
);
228 memcpy(p
, &sll
.sll_addr
, ah
->ar_hln
);
234 if (sendto(pset
[0].fd
, buf
, p
-buf
, 0, (struct sockaddr
*)&sll
, sizeof(sll
)) < 0)
240 /* Be very tough on sending probes: 1 per second with burst of 3. */
242 static int queue_active_probe(int ifindex
, __u32 addr
)
244 static struct timeval prev
;
248 gettimeofday(&now
, NULL
);
250 int diff
= (now
.tv_sec
-prev
.tv_sec
)*1000+(now
.tv_usec
-prev
.tv_usec
)/1000;
253 buckets
= broadcast_burst
;
255 if (buckets
> broadcast_burst
)
256 buckets
= broadcast_burst
;
257 if (buckets
>= broadcast_rate
&& !send_probe(ifindex
, addr
)) {
258 buckets
-= broadcast_rate
;
262 stats
.probes_suppressed
++;
266 static int respond_to_kernel(int ifindex
, __u32 addr
, char *lla
, int llalen
)
274 memset(&req
.n
, 0, sizeof(req
.n
));
275 memset(&req
.ndm
, 0, sizeof(req
.ndm
));
277 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndmsg
));
278 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
279 req
.n
.nlmsg_type
= RTM_NEWNEIGH
;
280 req
.ndm
.ndm_family
= AF_INET
;
281 req
.ndm
.ndm_state
= NUD_STALE
;
282 req
.ndm
.ndm_ifindex
= ifindex
;
283 req
.ndm
.ndm_type
= RTN_UNICAST
;
285 addattr_l(&req
.n
, sizeof(req
), NDA_DST
, &addr
, 4);
286 addattr_l(&req
.n
, sizeof(req
), NDA_LLADDR
, lla
, llalen
);
287 return rtnl_send(&rth
, &req
, req
.n
.nlmsg_len
) <= 0;
290 static void prepare_neg_entry(__u8
*ndata
, __u32 stamp
)
294 ndata
[2] = stamp
>>24;
295 ndata
[3] = stamp
>>16;
301 static int do_one_request(struct nlmsghdr
*n
)
303 struct ndmsg
*ndm
= NLMSG_DATA(n
);
304 int len
= n
->nlmsg_len
;
305 struct rtattr
* tb
[NDA_MAX
+1];
310 if (n
->nlmsg_type
== NLMSG_DONE
) {
311 dbase
->sync(dbase
, 0);
313 /* Now we have at least mirror of kernel db, so that
314 * may start real resolution.
316 do_sysctl_adjustments();
320 if (n
->nlmsg_type
!= RTM_GETNEIGH
&& n
->nlmsg_type
!= RTM_NEWNEIGH
)
323 len
-= NLMSG_LENGTH(sizeof(*ndm
));
327 if (ndm
->ndm_family
!= AF_INET
||
328 (ifnum
&& !handle_if(ndm
->ndm_ifindex
)) ||
330 ndm
->ndm_type
!= RTN_UNICAST
||
331 !(ndm
->ndm_state
&~NUD_NOARP
))
334 parse_rtattr(tb
, NDA_MAX
, NDA_RTA(ndm
), len
);
339 key
.iface
= ndm
->ndm_ifindex
;
340 memcpy(&key
.addr
, RTA_DATA(tb
[NDA_DST
]), 4);
342 dbkey
.size
= sizeof(key
);
344 if (dbase
->get(dbase
, &dbkey
, &dbdat
, 0) != 0) {
349 if (n
->nlmsg_type
== RTM_GETNEIGH
) {
350 if (!(n
->nlmsg_flags
&NLM_F_REQUEST
))
353 if (!(ndm
->ndm_state
&(NUD_PROBE
|NUD_INCOMPLETE
))) {
358 if (ndm
->ndm_state
&NUD_PROBE
) {
359 /* If we get this, kernel still has some valid
360 * address, but unicast probing failed and host
361 * is either dead or changed its mac address.
362 * Kernel is going to initiate broadcast resolution.
363 * OK, we invalidate our information as well.
365 if (dbdat
.data
&& !IS_NEG(dbdat
.data
))
368 dbase
->del(dbase
, &dbkey
, 0);
370 /* If we get this kernel does not have any information.
371 * If we have something tell this to kernel. */
373 if (dbdat
.data
&& !IS_NEG(dbdat
.data
)) {
375 respond_to_kernel(key
.iface
, key
.addr
, dbdat
.data
, dbdat
.size
);
379 /* Sheeit! We have nothing to tell. */
380 /* If we have recent negative entry, be silent. */
381 if (dbdat
.data
&& NEG_VALID(dbdat
.data
)) {
382 if (NEG_CNT(dbdat
.data
) >= active_probing
) {
383 stats
.app_suppressed
++;
390 if (active_probing
&&
391 queue_active_probe(ndm
->ndm_ifindex
, key
.addr
) == 0 &&
393 NEG_CNT(dbdat
.data
)++;
394 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
396 } else if (n
->nlmsg_type
== RTM_NEWNEIGH
) {
397 if (n
->nlmsg_flags
&NLM_F_REQUEST
)
400 if (ndm
->ndm_state
&NUD_FAILED
) {
401 /* Kernel was not able to resolve. Host is dead.
402 * Create negative entry if it is not present
403 * or renew it if it is too old. */
405 !IS_NEG(dbdat
.data
) ||
406 !NEG_VALID(dbdat
.data
)) {
409 prepare_neg_entry(ndata
, time(NULL
));
411 dbdat
.size
= sizeof(ndata
);
412 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
414 } else if (tb
[NDA_LLADDR
]) {
415 if (dbdat
.data
&& !IS_NEG(dbdat
.data
)) {
416 if (memcmp(RTA_DATA(tb
[NDA_LLADDR
]), dbdat
.data
, dbdat
.size
) == 0)
422 dbdat
.data
= RTA_DATA(tb
[NDA_LLADDR
]);
423 dbdat
.size
= RTA_PAYLOAD(tb
[NDA_LLADDR
]);
424 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
430 static void load_initial_table(void)
432 if (rtnl_wilddump_request(&rth
, AF_INET
, RTM_GETNEIGH
) < 0) {
433 perror("dump request failed");
439 static void get_kern_msg(void)
443 struct sockaddr_nl nladdr
;
446 struct msghdr msg
= {
447 (void*)&nladdr
, sizeof(nladdr
),
453 memset(&nladdr
, 0, sizeof(nladdr
));
456 iov
.iov_len
= sizeof(buf
);
458 status
= recvmsg(rth
.fd
, &msg
, MSG_DONTWAIT
);
463 if (msg
.msg_namelen
!= sizeof(nladdr
))
469 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
470 int len
= h
->nlmsg_len
;
471 int l
= len
- sizeof(*h
);
473 if (l
< 0 || len
> status
)
476 if (do_one_request(h
) < 0)
479 status
-= NLMSG_ALIGN(len
);
480 h
= (struct nlmsghdr
*)((char*)h
+ NLMSG_ALIGN(len
));
484 /* Receive gratuitous ARP messages and store them, that's all. */
485 static void get_arp_pkt(void)
487 unsigned char buf
[1024];
488 struct sockaddr_ll sll
;
489 socklen_t sll_len
= sizeof(sll
);
490 struct arphdr
*a
= (struct arphdr
*)buf
;
495 n
= recvfrom(pset
[0].fd
, buf
, sizeof(buf
), MSG_DONTWAIT
,
496 (struct sockaddr
*)&sll
, &sll_len
);
498 if (errno
!= EINTR
&& errno
!= EAGAIN
)
499 syslog(LOG_ERR
, "recvfrom: %m");
503 if (ifnum
&& !handle_if(sll
.sll_ifindex
))
508 if (n
< sizeof(*a
) ||
509 (a
->ar_op
!= htons(ARPOP_REQUEST
) &&
510 a
->ar_op
!= htons(ARPOP_REPLY
)) ||
512 a
->ar_pro
!= htons(ETH_P_IP
) ||
513 a
->ar_hln
!= sll
.sll_halen
||
514 sizeof(*a
) + 2*4 + 2*a
->ar_hln
> n
)
517 key
.iface
= sll
.sll_ifindex
;
518 memcpy(&key
.addr
, (char*)(a
+1) + a
->ar_hln
, 4);
520 /* DAD message, ignore. */
525 dbkey
.size
= sizeof(key
);
527 if (dbase
->get(dbase
, &dbkey
, &dbdat
, 0) == 0 && !IS_NEG(dbdat
.data
)) {
528 if (memcmp(dbdat
.data
, a
+1, dbdat
.size
) == 0)
536 dbdat
.size
= a
->ar_hln
;
537 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
540 static void catch_signal(int sig
, void (*handler
)(int))
544 memset(&sa
, 0, sizeof(sa
));
545 sa
.sa_handler
= handler
;
547 sa
.sa_flags
= SA_INTERRUPT
;
549 sigaction(sig
, &sa
, NULL
);
554 volatile int in_poll
;
556 static void sig_exit(int signo
)
563 static void sig_sync(int signo
)
570 static void sig_stats(int signo
)
578 static void send_stats(void)
580 syslog(LOG_INFO
, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu",
581 stats
.arp_new
, stats
.arp_change
,
583 stats
.app_recv
, stats
.app_success
,
584 stats
.app_bad
, stats
.app_neg
, stats
.app_suppressed
586 syslog(LOG_INFO
, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu",
587 stats
.kern_new
, stats
.kern_change
, stats
.kern_neg
,
589 stats
.probes_sent
, stats
.probes_suppressed
595 int main(int argc
, char **argv
)
599 char *do_load
= NULL
;
601 while ((opt
= getopt(argc
, argv
, "h?b:lf:a:n:p:kR:B:")) != EOF
) {
608 fprintf(stderr
, "Duplicate option -f\n");
617 active_probing
= atoi(optarg
);
620 negative_timeout
= atoi(optarg
);
623 no_kernel_broadcasts
= 1;
626 if ((poll_timeout
= 1000 * strtod(optarg
, NULL
)) < 100) {
627 fprintf(stderr
,"Invalid poll timeout\n");
632 if ((broadcast_rate
= atoi(optarg
)) <= 0 ||
633 (broadcast_rate
= 1000/broadcast_rate
) <= 0) {
634 fprintf(stderr
, "Invalid ARP rate\n");
639 if ((broadcast_burst
= atoi(optarg
)) <= 0 ||
640 (broadcast_burst
= 1000*broadcast_burst
) <= 0) {
641 fprintf(stderr
, "Invalid ARP burst\n");
657 ifvec
= malloc(argc
*sizeof(int));
664 if ((udp_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
672 memset(&ifr
, 0, sizeof(ifr
));
673 for (i
=0; i
<ifnum
; i
++) {
674 strncpy(ifr
.ifr_name
, ifnames
[i
], IFNAMSIZ
);
675 if (ioctl(udp_sock
, SIOCGIFINDEX
, &ifr
)) {
676 perror("ioctl(SIOCGIFINDEX)");
679 ifvec
[i
] = ifr
.ifr_ifindex
;
683 dbase
= dbopen(dbname
, O_CREAT
|O_RDWR
, 0644, DB_HASH
, NULL
);
696 dbkey
.size
= sizeof(k
);
698 if (strcmp(do_load
, "-") == 0 || strcmp(do_load
, "--") == 0) {
700 } else if ((fp
= fopen(do_load
, "r")) == NULL
) {
705 buf
[sizeof(buf
)-1] = 0;
706 while (fgets(buf
, sizeof(buf
)-1, fp
)) {
714 if (sscanf(buf
, "%u%s%s", &k
.iface
, ipbuf
, macbuf
) != 3) {
715 fprintf(stderr
, "Wrong format of input file \"%s\"\n", do_load
);
718 if (strncmp(macbuf
, "FAILED:", 7) == 0)
720 if (!inet_aton(ipbuf
, (struct in_addr
*)&k
.addr
)) {
721 fprintf(stderr
, "Invalid IP address: \"%s\"\n", ipbuf
);
725 if (ll_addr_a2n((char *) b1
, 6, macbuf
) != 6)
729 if (dbase
->put(dbase
, &dbkey
, &dbdat
, 0)) {
734 dbase
->sync(dbase
, 0);
741 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
742 while (dbase
->seq(dbase
, &dbkey
, &dbdat
, R_NEXT
) == 0) {
743 struct dbkey
*key
= dbkey
.data
;
744 if (handle_if(key
->iface
)) {
745 if (!IS_NEG(dbdat
.data
)) {
747 printf("%-8d %-15s %s\n",
749 inet_ntoa(*(struct in_addr
*)&key
->addr
),
750 ll_addr_n2a(dbdat
.data
, 6, ARPHRD_ETHER
, b1
, 18));
752 printf("%-8d %-15s FAILED: %dsec ago\n",
754 inet_ntoa(*(struct in_addr
*)&key
->addr
),
755 NEG_AGE(dbdat
.data
));
761 if (do_load
|| do_list
)
764 pset
[0].fd
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
765 if (pset
[0].fd
< 0) {
771 struct sockaddr_ll sll
;
772 memset(&sll
, 0, sizeof(sll
));
773 sll
.sll_family
= AF_PACKET
;
774 sll
.sll_protocol
= htons(ETH_P_ARP
);
775 sll
.sll_ifindex
= (ifnum
== 1 ? ifvec
[0] : 0);
776 if (bind(pset
[0].fd
, (struct sockaddr
*)&sll
, sizeof(sll
)) < 0) {
782 if (rtnl_open(&rth
, RTMGRP_NEIGH
) < 0) {
788 load_initial_table();
791 perror("arpd: daemon");
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
);
801 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
802 pset
[0].events
= EVENTS
;
804 pset
[1].events
= EVENTS
;
816 dbase
->sync(dbase
, 0);
822 if (poll(pset
, 2, poll_timeout
) > 0) {
824 if (pset
[0].revents
&EVENTS
)
826 if (pset
[1].revents
&EVENTS
)
833 undo_sysctl_adjustments();