]>
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";
55 #define IS_NEG(x) (((__u8 *)(x))[0] == 0xFF)
56 #define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
57 #define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8 *)x))
58 #define NEG_VALID(x) (NEG_AGE(x) < negative_timeout)
59 #define NEG_CNT(x) (((__u8 *)(x))[1])
61 struct rtnl_handle rth
;
63 struct pollfd pset
[2];
68 volatile int do_stats
;
71 unsigned long arp_new
;
72 unsigned long arp_change
;
74 unsigned long app_recv
;
75 unsigned long app_success
;
76 unsigned long app_bad
;
77 unsigned long app_neg
;
78 unsigned long app_suppressed
;
80 unsigned long kern_neg
;
81 unsigned long kern_new
;
82 unsigned long kern_change
;
84 unsigned long probes_sent
;
85 unsigned long probes_suppressed
;
89 int negative_timeout
= 60;
90 int no_kernel_broadcasts
;
91 int broadcast_rate
= 1000;
92 int broadcast_burst
= 3000;
93 int poll_timeout
= 30000;
95 static void usage(void)
98 "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ] [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n");
102 static int handle_if(int ifindex
)
109 for (i
= 0; i
< ifnum
; i
++)
110 if (ifvec
[i
] == ifindex
)
117 static void do_sysctl_adjustments(void)
124 for (i
= 0; i
< ifnum
; i
++) {
128 if (active_probing
) {
129 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames
[i
]);
130 if ((fp
= fopen(buf
, "w")) != NULL
) {
131 if (no_kernel_broadcasts
)
134 sprintf(buf
, "%d\n", active_probing
>= 2 ? 1 : 3-active_probing
);
140 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames
[i
]);
141 if ((fp
= fopen(buf
, "w")) != NULL
) {
142 sprintf(buf
, "%d\n", active_probing
<= 1 ? 1 : active_probing
);
150 static void undo_sysctl_adjustments(void)
154 if (!sysctl_adjusted
)
157 for (i
= 0; i
< ifnum
; i
++) {
161 if (active_probing
) {
162 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames
[i
]);
163 if ((fp
= fopen(buf
, "w")) != NULL
) {
169 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames
[i
]);
170 if ((fp
= fopen(buf
, "w")) != NULL
) {
180 static int send_probe(int ifindex
, __u32 addr
)
182 struct ifreq ifr
= { .ifr_ifindex
= ifindex
};
183 struct sockaddr_in dst
= {
184 .sin_family
= AF_INET
,
185 .sin_port
= htons(1025),
186 .sin_addr
.s_addr
= addr
,
189 unsigned char buf
[256];
190 struct arphdr
*ah
= (struct arphdr
*)buf
;
191 unsigned char *p
= (unsigned char *)(ah
+1);
192 struct sockaddr_ll sll
= {
193 .sll_family
= AF_PACKET
,
194 .sll_ifindex
= ifindex
,
195 .sll_protocol
= htons(ETH_P_ARP
),
198 if (ioctl(udp_sock
, SIOCGIFNAME
, &ifr
))
200 if (ioctl(udp_sock
, SIOCGIFHWADDR
, &ifr
))
202 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
)
204 if (setsockopt(udp_sock
, SOL_SOCKET
, SO_BINDTODEVICE
, ifr
.ifr_name
, strlen(ifr
.ifr_name
)+1) < 0)
207 if (connect(udp_sock
, (struct sockaddr
*)&dst
, sizeof(dst
)) < 0)
210 if (getsockname(udp_sock
, (struct sockaddr
*)&dst
, &len
) < 0)
213 ah
->ar_hrd
= htons(ifr
.ifr_hwaddr
.sa_family
);
214 ah
->ar_pro
= htons(ETH_P_IP
);
217 ah
->ar_op
= htons(ARPOP_REQUEST
);
219 memcpy(p
, ifr
.ifr_hwaddr
.sa_data
, ah
->ar_hln
);
222 memcpy(p
, &dst
.sin_addr
, 4);
225 memset(sll
.sll_addr
, 0xFF, sizeof(sll
.sll_addr
));
226 memcpy(p
, &sll
.sll_addr
, ah
->ar_hln
);
232 if (sendto(pset
[0].fd
, buf
, p
-buf
, 0, (struct sockaddr
*)&sll
, sizeof(sll
)) < 0)
238 /* Be very tough on sending probes: 1 per second with burst of 3. */
240 static int queue_active_probe(int ifindex
, __u32 addr
)
242 static struct timeval prev
;
246 gettimeofday(&now
, NULL
);
248 int diff
= (now
.tv_sec
-prev
.tv_sec
)*1000+(now
.tv_usec
-prev
.tv_usec
)/1000;
252 buckets
= broadcast_burst
;
254 if (buckets
> broadcast_burst
)
255 buckets
= broadcast_burst
;
256 if (buckets
>= broadcast_rate
&& !send_probe(ifindex
, addr
)) {
257 buckets
-= broadcast_rate
;
261 stats
.probes_suppressed
++;
265 static int respond_to_kernel(int ifindex
, __u32 addr
, char *lla
, int llalen
)
272 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndmsg
)),
273 .n
.nlmsg_flags
= NLM_F_REQUEST
,
274 .n
.nlmsg_type
= RTM_NEWNEIGH
,
275 .ndm
.ndm_family
= AF_INET
,
276 .ndm
.ndm_state
= NUD_STALE
,
277 .ndm
.ndm_ifindex
= ifindex
,
278 .ndm
.ndm_type
= RTN_UNICAST
,
281 addattr_l(&req
.n
, sizeof(req
), NDA_DST
, &addr
, 4);
282 addattr_l(&req
.n
, sizeof(req
), NDA_LLADDR
, lla
, llalen
);
283 return rtnl_send(&rth
, &req
, req
.n
.nlmsg_len
) <= 0;
286 static void prepare_neg_entry(__u8
*ndata
, __u32 stamp
)
290 ndata
[2] = stamp
>>24;
291 ndata
[3] = stamp
>>16;
297 static int do_one_request(struct nlmsghdr
*n
)
299 struct ndmsg
*ndm
= NLMSG_DATA(n
);
300 int len
= n
->nlmsg_len
;
301 struct rtattr
*tb
[NDA_MAX
+1];
306 if (n
->nlmsg_type
== NLMSG_DONE
) {
307 dbase
->sync(dbase
, 0);
309 /* Now we have at least mirror of kernel db, so that
310 * may start real resolution.
312 do_sysctl_adjustments();
316 if (n
->nlmsg_type
!= RTM_GETNEIGH
&& n
->nlmsg_type
!= RTM_NEWNEIGH
)
319 len
-= NLMSG_LENGTH(sizeof(*ndm
));
323 if (ndm
->ndm_family
!= AF_INET
||
324 (ifnum
&& !handle_if(ndm
->ndm_ifindex
)) ||
326 ndm
->ndm_type
!= RTN_UNICAST
||
327 !(ndm
->ndm_state
&~NUD_NOARP
))
330 parse_rtattr(tb
, NDA_MAX
, NDA_RTA(ndm
), len
);
335 key
.iface
= ndm
->ndm_ifindex
;
336 memcpy(&key
.addr
, RTA_DATA(tb
[NDA_DST
]), 4);
338 dbkey
.size
= sizeof(key
);
340 if (dbase
->get(dbase
, &dbkey
, &dbdat
, 0) != 0) {
345 if (n
->nlmsg_type
== RTM_GETNEIGH
) {
346 if (!(n
->nlmsg_flags
&NLM_F_REQUEST
))
349 if (!(ndm
->ndm_state
&(NUD_PROBE
|NUD_INCOMPLETE
))) {
354 if (ndm
->ndm_state
&NUD_PROBE
) {
355 /* If we get this, kernel still has some valid
356 * address, but unicast probing failed and host
357 * is either dead or changed its mac address.
358 * Kernel is going to initiate broadcast resolution.
359 * OK, we invalidate our information as well.
361 if (dbdat
.data
&& !IS_NEG(dbdat
.data
))
364 dbase
->del(dbase
, &dbkey
, 0);
366 /* If we get this kernel does not have any information.
367 * If we have something tell this to kernel. */
369 if (dbdat
.data
&& !IS_NEG(dbdat
.data
)) {
371 respond_to_kernel(key
.iface
, key
.addr
, dbdat
.data
, dbdat
.size
);
375 /* Sheeit! We have nothing to tell. */
376 /* If we have recent negative entry, be silent. */
377 if (dbdat
.data
&& NEG_VALID(dbdat
.data
)) {
378 if (NEG_CNT(dbdat
.data
) >= active_probing
) {
379 stats
.app_suppressed
++;
386 if (active_probing
&&
387 queue_active_probe(ndm
->ndm_ifindex
, key
.addr
) == 0 &&
389 NEG_CNT(dbdat
.data
)++;
390 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
392 } else if (n
->nlmsg_type
== RTM_NEWNEIGH
) {
393 if (n
->nlmsg_flags
&NLM_F_REQUEST
)
396 if (ndm
->ndm_state
&NUD_FAILED
) {
397 /* Kernel was not able to resolve. Host is dead.
398 * Create negative entry if it is not present
399 * or renew it if it is too old. */
401 !IS_NEG(dbdat
.data
) ||
402 !NEG_VALID(dbdat
.data
)) {
406 prepare_neg_entry(ndata
, time(NULL
));
408 dbdat
.size
= sizeof(ndata
);
409 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
411 } else if (tb
[NDA_LLADDR
]) {
412 if (dbdat
.data
&& !IS_NEG(dbdat
.data
)) {
413 if (memcmp(RTA_DATA(tb
[NDA_LLADDR
]), dbdat
.data
, dbdat
.size
) == 0)
419 dbdat
.data
= RTA_DATA(tb
[NDA_LLADDR
]);
420 dbdat
.size
= RTA_PAYLOAD(tb
[NDA_LLADDR
]);
421 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
427 static void load_initial_table(void)
429 if (rtnl_wilddump_request(&rth
, AF_INET
, RTM_GETNEIGH
) < 0) {
430 perror("dump request failed");
436 static void get_kern_msg(void)
440 struct sockaddr_nl nladdr
= {};
443 struct msghdr msg
= {
444 (void *)&nladdr
, sizeof(nladdr
),
451 iov
.iov_len
= sizeof(buf
);
453 status
= recvmsg(rth
.fd
, &msg
, MSG_DONTWAIT
);
458 if (msg
.msg_namelen
!= sizeof(nladdr
))
464 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
465 int len
= h
->nlmsg_len
;
466 int l
= len
- sizeof(*h
);
468 if (l
< 0 || len
> status
)
471 if (do_one_request(h
) < 0)
474 status
-= NLMSG_ALIGN(len
);
475 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
479 /* Receive gratuitous ARP messages and store them, that's all. */
480 static void get_arp_pkt(void)
482 unsigned char buf
[1024];
483 struct sockaddr_ll sll
;
484 socklen_t sll_len
= sizeof(sll
);
485 struct arphdr
*a
= (struct arphdr
*)buf
;
490 n
= recvfrom(pset
[0].fd
, buf
, sizeof(buf
), MSG_DONTWAIT
,
491 (struct sockaddr
*)&sll
, &sll_len
);
493 if (errno
!= EINTR
&& errno
!= EAGAIN
)
494 syslog(LOG_ERR
, "recvfrom: %m");
498 if (ifnum
&& !handle_if(sll
.sll_ifindex
))
503 if (n
< sizeof(*a
) ||
504 (a
->ar_op
!= htons(ARPOP_REQUEST
) &&
505 a
->ar_op
!= htons(ARPOP_REPLY
)) ||
507 a
->ar_pro
!= htons(ETH_P_IP
) ||
508 a
->ar_hln
!= sll
.sll_halen
||
509 sizeof(*a
) + 2*4 + 2*a
->ar_hln
> n
)
512 key
.iface
= sll
.sll_ifindex
;
513 memcpy(&key
.addr
, (char *)(a
+1) + a
->ar_hln
, 4);
515 /* DAD message, ignore. */
520 dbkey
.size
= sizeof(key
);
522 if (dbase
->get(dbase
, &dbkey
, &dbdat
, 0) == 0 && !IS_NEG(dbdat
.data
)) {
523 if (memcmp(dbdat
.data
, a
+1, dbdat
.size
) == 0)
531 dbdat
.size
= a
->ar_hln
;
532 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
535 static void catch_signal(int sig
, void (*handler
)(int))
537 struct sigaction sa
= { .sa_handler
= handler
};
540 sa
.sa_flags
= SA_INTERRUPT
;
542 sigaction(sig
, &sa
, NULL
);
547 volatile int in_poll
;
549 static void sig_exit(int signo
)
556 static void sig_sync(int signo
)
563 static void sig_stats(int signo
)
571 static void send_stats(void)
573 syslog(LOG_INFO
, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu",
574 stats
.arp_new
, stats
.arp_change
,
576 stats
.app_recv
, stats
.app_success
,
577 stats
.app_bad
, stats
.app_neg
, stats
.app_suppressed
579 syslog(LOG_INFO
, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu",
580 stats
.kern_new
, stats
.kern_change
, stats
.kern_neg
,
582 stats
.probes_sent
, stats
.probes_suppressed
588 int main(int argc
, char **argv
)
592 char *do_load
= NULL
;
594 while ((opt
= getopt(argc
, argv
, "h?b:lf:a:n:p:kR:B:")) != EOF
) {
601 fprintf(stderr
, "Duplicate option -f\n");
610 active_probing
= atoi(optarg
);
613 negative_timeout
= atoi(optarg
);
616 no_kernel_broadcasts
= 1;
619 if ((poll_timeout
= 1000 * strtod(optarg
, NULL
)) < 100) {
620 fprintf(stderr
, "Invalid poll timeout\n");
625 if ((broadcast_rate
= atoi(optarg
)) <= 0 ||
626 (broadcast_rate
= 1000/broadcast_rate
) <= 0) {
627 fprintf(stderr
, "Invalid ARP rate\n");
632 if ((broadcast_burst
= atoi(optarg
)) <= 0 ||
633 (broadcast_burst
= 1000*broadcast_burst
) <= 0) {
634 fprintf(stderr
, "Invalid ARP burst\n");
650 ifvec
= malloc(argc
*sizeof(int));
657 if ((udp_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
664 struct ifreq ifr
= {};
666 for (i
= 0; i
< ifnum
; i
++) {
667 if (get_ifname(ifr
.ifr_name
, ifnames
[i
]))
668 invarg("not a valid ifname", ifnames
[i
]);
669 if (ioctl(udp_sock
, SIOCGIFINDEX
, &ifr
)) {
670 perror("ioctl(SIOCGIFINDEX)");
673 ifvec
[i
] = ifr
.ifr_ifindex
;
677 dbase
= dbopen(dbname
, O_CREAT
|O_RDWR
, 0644, DB_HASH
, NULL
);
690 dbkey
.size
= sizeof(k
);
692 if (strcmp(do_load
, "-") == 0 || strcmp(do_load
, "--") == 0) {
694 } else if ((fp
= fopen(do_load
, "r")) == NULL
) {
699 buf
[sizeof(buf
)-1] = 0;
700 while (fgets(buf
, sizeof(buf
), fp
)) {
708 if (sscanf(buf
, "%u%s%s", &k
.iface
, ipbuf
, macbuf
) != 3) {
709 fprintf(stderr
, "Wrong format of input file \"%s\"\n", do_load
);
712 if (strncmp(macbuf
, "FAILED:", 7) == 0)
714 if (!inet_aton(ipbuf
, (struct in_addr
*)&k
.addr
)) {
715 fprintf(stderr
, "Invalid IP address: \"%s\"\n", ipbuf
);
719 if (ll_addr_a2n((char *) b1
, 6, macbuf
) != 6)
723 if (dbase
->put(dbase
, &dbkey
, &dbdat
, 0)) {
728 dbase
->sync(dbase
, 0);
736 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
737 while (dbase
->seq(dbase
, &dbkey
, &dbdat
, R_NEXT
) == 0) {
738 struct dbkey
*key
= dbkey
.data
;
740 if (handle_if(key
->iface
)) {
741 if (!IS_NEG(dbdat
.data
)) {
744 printf("%-8d %-15s %s\n",
746 inet_ntoa(*(struct in_addr
*)&key
->addr
),
747 ll_addr_n2a(dbdat
.data
, 6, ARPHRD_ETHER
, b1
, 18));
749 printf("%-8d %-15s FAILED: %dsec ago\n",
751 inet_ntoa(*(struct in_addr
*)&key
->addr
),
752 NEG_AGE(dbdat
.data
));
758 if (do_load
|| do_list
)
761 pset
[0].fd
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
762 if (pset
[0].fd
< 0) {
768 struct sockaddr_ll sll
= {
769 .sll_family
= AF_PACKET
,
770 .sll_protocol
= htons(ETH_P_ARP
),
771 .sll_ifindex
= (ifnum
== 1 ? ifvec
[0] : 0),
774 if (bind(pset
[0].fd
, (struct sockaddr
*)&sll
, sizeof(sll
)) < 0) {
780 if (rtnl_open(&rth
, RTMGRP_NEIGH
) < 0) {
786 load_initial_table();
789 perror("arpd: daemon");
793 openlog("arpd", LOG_PID
| LOG_CONS
, LOG_DAEMON
);
794 catch_signal(SIGINT
, sig_exit
);
795 catch_signal(SIGTERM
, sig_exit
);
796 catch_signal(SIGHUP
, sig_sync
);
797 catch_signal(SIGUSR1
, sig_stats
);
799 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
800 pset
[0].events
= EVENTS
;
802 pset
[1].events
= EVENTS
;
814 dbase
->sync(dbase
, 0);
820 if (poll(pset
, 2, poll_timeout
) > 0) {
822 if (pset
[0].revents
&EVENTS
)
824 if (pset
[1].revents
&EVENTS
)
831 undo_sysctl_adjustments();