]>
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"
43 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 ]"
99 " [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n");
103 static int handle_if(int ifindex
)
110 for (i
=0; i
<ifnum
; i
++)
111 if (ifvec
[i
] == ifindex
)
118 static void do_sysctl_adjustments(void)
125 for (i
=0; i
<ifnum
; i
++) {
129 if (active_probing
) {
130 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames
[i
]);
131 if ((fp
= fopen(buf
, "w")) != NULL
) {
132 if (no_kernel_broadcasts
)
135 sprintf(buf
, "%d\n", active_probing
>=2 ? 1 : 3-active_probing
);
141 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames
[i
]);
142 if ((fp
= fopen(buf
, "w")) != NULL
) {
143 sprintf(buf
, "%d\n", active_probing
<=1 ? 1 : active_probing
);
151 static void undo_sysctl_adjustments(void)
155 if (!sysctl_adjusted
)
158 for (i
=0; i
<ifnum
; i
++) {
162 if (active_probing
) {
163 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames
[i
]);
164 if ((fp
= fopen(buf
, "w")) != NULL
) {
170 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames
[i
]);
171 if ((fp
= fopen(buf
, "w")) != NULL
) {
181 static int send_probe(int ifindex
, __u32 addr
)
184 struct sockaddr_in dst
;
186 unsigned char buf
[256];
187 struct arphdr
*ah
= (struct arphdr
*)buf
;
188 unsigned char *p
= (unsigned char *)(ah
+1);
189 struct sockaddr_ll sll
;
191 memset(&ifr
, 0, sizeof(ifr
));
192 ifr
.ifr_ifindex
= ifindex
;
193 if (ioctl(udp_sock
, SIOCGIFNAME
, &ifr
))
195 if (ioctl(udp_sock
, SIOCGIFHWADDR
, &ifr
))
197 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
)
199 if (setsockopt(udp_sock
, SOL_SOCKET
, SO_BINDTODEVICE
, ifr
.ifr_name
, strlen(ifr
.ifr_name
)+1) < 0)
202 dst
.sin_family
= AF_INET
;
203 dst
.sin_port
= htons(1025);
204 dst
.sin_addr
.s_addr
= addr
;
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 sll
.sll_family
= AF_PACKET
;
224 memset(sll
.sll_addr
, 0xFF, sizeof(sll
.sll_addr
));
225 sll
.sll_ifindex
= ifindex
;
226 sll
.sll_protocol
= htons(ETH_P_ARP
);
227 memcpy(p
, &sll
.sll_addr
, ah
->ar_hln
);
233 if (sendto(pset
[0].fd
, buf
, p
-buf
, 0, (struct sockaddr
*)&sll
, sizeof(sll
)) < 0)
239 /* Be very tough on sending probes: 1 per second with burst of 3. */
241 static int queue_active_probe(int ifindex
, __u32 addr
)
243 static struct timeval prev
;
247 gettimeofday(&now
, NULL
);
249 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
)
273 memset(&req
.n
, 0, sizeof(req
.n
));
274 memset(&req
.ndm
, 0, sizeof(req
.ndm
));
276 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndmsg
));
277 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
278 req
.n
.nlmsg_type
= RTM_NEWNEIGH
;
279 req
.ndm
.ndm_family
= AF_INET
;
280 req
.ndm
.ndm_state
= NUD_STALE
;
281 req
.ndm
.ndm_ifindex
= ifindex
;
282 req
.ndm
.ndm_type
= RTN_UNICAST
;
284 addattr_l(&req
.n
, sizeof(req
), NDA_DST
, &addr
, 4);
285 addattr_l(&req
.n
, sizeof(req
), NDA_LLADDR
, lla
, llalen
);
286 return rtnl_send(&rth
, &req
, req
.n
.nlmsg_len
) <= 0;
289 static void prepare_neg_entry(__u8
*ndata
, __u32 stamp
)
293 ndata
[2] = stamp
>>24;
294 ndata
[3] = stamp
>>16;
300 static int do_one_request(struct nlmsghdr
*n
)
302 struct ndmsg
*ndm
= NLMSG_DATA(n
);
303 int len
= n
->nlmsg_len
;
304 struct rtattr
* tb
[NDA_MAX
+1];
309 if (n
->nlmsg_type
== NLMSG_DONE
) {
310 dbase
->sync(dbase
, 0);
312 /* Now we have at least mirror of kernel db, so that
313 * may start real resolution.
315 do_sysctl_adjustments();
319 if (n
->nlmsg_type
!= RTM_GETNEIGH
&& n
->nlmsg_type
!= RTM_NEWNEIGH
)
322 len
-= NLMSG_LENGTH(sizeof(*ndm
));
326 if (ndm
->ndm_family
!= AF_INET
||
327 (ifnum
&& !handle_if(ndm
->ndm_ifindex
)) ||
329 ndm
->ndm_type
!= RTN_UNICAST
||
330 !(ndm
->ndm_state
&~NUD_NOARP
))
333 parse_rtattr(tb
, NDA_MAX
, NDA_RTA(ndm
), len
);
338 key
.iface
= ndm
->ndm_ifindex
;
339 memcpy(&key
.addr
, RTA_DATA(tb
[NDA_DST
]), 4);
341 dbkey
.size
= sizeof(key
);
343 if (dbase
->get(dbase
, &dbkey
, &dbdat
, 0) != 0) {
348 if (n
->nlmsg_type
== RTM_GETNEIGH
) {
349 if (!(n
->nlmsg_flags
&NLM_F_REQUEST
))
352 if (!(ndm
->ndm_state
&(NUD_PROBE
|NUD_INCOMPLETE
))) {
357 if (ndm
->ndm_state
&NUD_PROBE
) {
358 /* If we get this, kernel still has some valid
359 * address, but unicast probing failed and host
360 * is either dead or changed its mac address.
361 * Kernel is going to initiate broadcast resolution.
362 * OK, we invalidate our information as well.
364 if (dbdat
.data
&& !IS_NEG(dbdat
.data
))
367 dbase
->del(dbase
, &dbkey
, 0);
369 /* If we get this kernel does not have any information.
370 * If we have something tell this to kernel. */
372 if (dbdat
.data
&& !IS_NEG(dbdat
.data
)) {
374 respond_to_kernel(key
.iface
, key
.addr
, dbdat
.data
, dbdat
.size
);
378 /* Sheeit! We have nothing to tell. */
379 /* If we have recent negative entry, be silent. */
380 if (dbdat
.data
&& NEG_VALID(dbdat
.data
)) {
381 if (NEG_CNT(dbdat
.data
) >= active_probing
) {
382 stats
.app_suppressed
++;
389 if (active_probing
&&
390 queue_active_probe(ndm
->ndm_ifindex
, key
.addr
) == 0 &&
392 NEG_CNT(dbdat
.data
)++;
393 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
395 } else if (n
->nlmsg_type
== RTM_NEWNEIGH
) {
396 if (n
->nlmsg_flags
&NLM_F_REQUEST
)
399 if (ndm
->ndm_state
&NUD_FAILED
) {
400 /* Kernel was not able to resolve. Host is dead.
401 * Create negative entry if it is not present
402 * or renew it if it is too old. */
404 !IS_NEG(dbdat
.data
) ||
405 !NEG_VALID(dbdat
.data
)) {
408 prepare_neg_entry(ndata
, time(NULL
));
410 dbdat
.size
= sizeof(ndata
);
411 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
413 } else if (tb
[NDA_LLADDR
]) {
414 if (dbdat
.data
&& !IS_NEG(dbdat
.data
)) {
415 if (memcmp(RTA_DATA(tb
[NDA_LLADDR
]), dbdat
.data
, dbdat
.size
) == 0)
421 dbdat
.data
= RTA_DATA(tb
[NDA_LLADDR
]);
422 dbdat
.size
= RTA_PAYLOAD(tb
[NDA_LLADDR
]);
423 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
429 static void load_initial_table(void)
431 rtnl_wilddump_request(&rth
, AF_INET
, RTM_GETNEIGH
);
434 static void get_kern_msg(void)
438 struct sockaddr_nl nladdr
;
441 struct msghdr msg
= {
442 (void*)&nladdr
, sizeof(nladdr
),
448 memset(&nladdr
, 0, 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))
539 memset(&sa
, 0, sizeof(sa
));
540 sa
.sa_handler
= handler
;
542 sa
.sa_flags
= SA_INTERRUPT
;
544 sigaction(sig
, &sa
, NULL
);
549 volatile int in_poll
;
551 static void sig_exit(int signo
)
558 static void sig_sync(int signo
)
565 static void sig_stats(int signo
)
573 static void send_stats(void)
575 syslog(LOG_INFO
, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu",
576 stats
.arp_new
, stats
.arp_change
,
578 stats
.app_recv
, stats
.app_success
,
579 stats
.app_bad
, stats
.app_neg
, stats
.app_suppressed
581 syslog(LOG_INFO
, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu",
582 stats
.kern_new
, stats
.kern_change
, stats
.kern_neg
,
584 stats
.probes_sent
, stats
.probes_suppressed
590 int main(int argc
, char **argv
)
594 char *do_load
= NULL
;
596 while ((opt
= getopt(argc
, argv
, "h?b:lf:a:n:p:kR:B:")) != EOF
) {
603 fprintf(stderr
, "Duplicate option -f\n");
612 active_probing
= atoi(optarg
);
615 negative_timeout
= atoi(optarg
);
618 no_kernel_broadcasts
= 1;
621 if ((poll_timeout
= 1000 * strtod(optarg
, NULL
)) < 100) {
622 fprintf(stderr
,"Invalid poll timeout\n");
627 if ((broadcast_rate
= atoi(optarg
)) <= 0 ||
628 (broadcast_rate
= 1000/broadcast_rate
) <= 0) {
629 fprintf(stderr
, "Invalid ARP rate\n");
634 if ((broadcast_burst
= atoi(optarg
)) <= 0 ||
635 (broadcast_burst
= 1000*broadcast_burst
) <= 0) {
636 fprintf(stderr
, "Invalid ARP burst\n");
652 ifvec
= malloc(argc
*sizeof(int));
659 if ((udp_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
667 memset(&ifr
, 0, sizeof(ifr
));
668 for (i
=0; i
<ifnum
; i
++) {
669 strncpy(ifr
.ifr_name
, ifnames
[i
], IFNAMSIZ
);
670 if (ioctl(udp_sock
, SIOCGIFINDEX
, &ifr
)) {
671 perror("ioctl(SIOCGIFINDEX)");
674 ifvec
[i
] = ifr
.ifr_ifindex
;
678 dbase
= dbopen(dbname
, O_CREAT
|O_RDWR
, 0644, DB_HASH
, NULL
);
691 dbkey
.size
= sizeof(k
);
693 if (strcmp(do_load
, "-") == 0 || strcmp(do_load
, "--") == 0) {
695 } else if ((fp
= fopen(do_load
, "r")) == NULL
) {
700 buf
[sizeof(buf
)-1] = 0;
701 while (fgets(buf
, sizeof(buf
)-1, fp
)) {
709 if (sscanf(buf
, "%u%s%s", &k
.iface
, ipbuf
, macbuf
) != 3) {
710 fprintf(stderr
, "Wrong format of input file \"%s\"\n", do_load
);
713 if (strncmp(macbuf
, "FAILED:", 7) == 0)
715 if (!inet_aton(ipbuf
, (struct in_addr
*)&k
.addr
)) {
716 fprintf(stderr
, "Invalid IP address: \"%s\"\n", ipbuf
);
720 dbdat
.data
= hexstring_a2n(macbuf
, b1
, 6);
721 if (dbdat
.data
== NULL
)
725 if (dbase
->put(dbase
, &dbkey
, &dbdat
, 0)) {
730 dbase
->sync(dbase
, 0);
737 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
738 while (dbase
->seq(dbase
, &dbkey
, &dbdat
, R_NEXT
) == 0) {
739 struct dbkey
*key
= dbkey
.data
;
740 if (handle_if(key
->iface
)) {
741 if (!IS_NEG(dbdat
.data
)) {
743 printf("%-8d %-15s %s\n",
745 inet_ntoa(*(struct in_addr
*)&key
->addr
),
746 hexstring_n2a(dbdat
.data
, 6, b1
, 18));
748 printf("%-8d %-15s FAILED: %dsec ago\n",
750 inet_ntoa(*(struct in_addr
*)&key
->addr
),
751 NEG_AGE(dbdat
.data
));
757 if (do_load
|| do_list
)
760 pset
[0].fd
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
761 if (pset
[0].fd
< 0) {
767 struct sockaddr_ll sll
;
768 memset(&sll
, 0, sizeof(sll
));
769 sll
.sll_family
= AF_PACKET
;
770 sll
.sll_protocol
= htons(ETH_P_ARP
);
771 sll
.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();