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;
97 "Usage: arpd [ -lk ] [ -a N ] [ -b dbase ] [ -f file ] [ interfaces ]\n");
101 int handle_if(int ifindex
)
108 for (i
=0; i
<ifnum
; i
++)
109 if (ifvec
[i
] == ifindex
)
116 void do_sysctl_adjustments(void)
123 for (i
=0; i
<ifnum
; i
++) {
127 if (active_probing
) {
128 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames
[i
]);
129 if ((fp
= fopen(buf
, "w")) != NULL
) {
130 if (no_kernel_broadcasts
)
133 sprintf(buf
, "%d\n", active_probing
>=2 ? 1 : 3-active_probing
);
139 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames
[i
]);
140 if ((fp
= fopen(buf
, "w")) != NULL
) {
141 sprintf(buf
, "%d\n", active_probing
<=1 ? 1 : active_probing
);
149 void undo_sysctl_adjustments(void)
153 if (!sysctl_adjusted
)
156 for (i
=0; i
<ifnum
; i
++) {
160 if (active_probing
) {
161 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames
[i
]);
162 if ((fp
= fopen(buf
, "w")) != NULL
) {
168 sprintf(buf
, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames
[i
]);
169 if ((fp
= fopen(buf
, "w")) != NULL
) {
179 int send_probe(int ifindex
, __u32 addr
)
182 struct sockaddr_in dst
;
184 unsigned char buf
[256];
185 struct arphdr
*ah
= (struct arphdr
*)buf
;
186 unsigned char *p
= (unsigned char *)(ah
+1);
187 struct sockaddr_ll sll
;
189 memset(&ifr
, 0, sizeof(ifr
));
190 ifr
.ifr_ifindex
= ifindex
;
191 if (ioctl(udp_sock
, SIOCGIFNAME
, &ifr
))
193 if (ioctl(udp_sock
, SIOCGIFHWADDR
, &ifr
))
195 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
)
197 if (setsockopt(udp_sock
, SOL_SOCKET
, SO_BINDTODEVICE
, ifr
.ifr_name
, strlen(ifr
.ifr_name
)+1) < 0)
200 dst
.sin_family
= AF_INET
;
201 dst
.sin_port
= htons(1025);
202 dst
.sin_addr
.s_addr
= addr
;
203 if (connect(udp_sock
, (struct sockaddr
*)&dst
, sizeof(dst
)) < 0)
206 if (getsockname(udp_sock
, (struct sockaddr
*)&dst
, &len
) < 0)
209 ah
->ar_hrd
= htons(ifr
.ifr_hwaddr
.sa_family
);
210 ah
->ar_pro
= htons(ETH_P_IP
);
213 ah
->ar_op
= htons(ARPOP_REQUEST
);
215 memcpy(p
, ifr
.ifr_hwaddr
.sa_data
, ah
->ar_hln
);
218 memcpy(p
, &dst
.sin_addr
, 4);
221 sll
.sll_family
= AF_PACKET
;
222 memset(sll
.sll_addr
, 0xFF, sizeof(sll
.sll_addr
));
223 sll
.sll_ifindex
= ifindex
;
224 sll
.sll_protocol
= htons(ETH_P_ARP
);
225 memcpy(p
, &sll
.sll_addr
, ah
->ar_hln
);
231 if (sendto(pset
[0].fd
, buf
, p
-buf
, 0, (struct sockaddr
*)&sll
, sizeof(sll
)) < 0)
237 /* Be very tough on sending probes: 1 per second with burst of 3. */
239 int queue_active_probe(int ifindex
, __u32 addr
)
241 static struct timeval prev
;
245 gettimeofday(&now
, NULL
);
247 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 int respond_to_kernel(int ifindex
, __u32 addr
, char *lla
, int llalen
)
271 memset(&req
.n
, 0, sizeof(req
.n
));
272 memset(&req
.ndm
, 0, sizeof(req
.ndm
));
274 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndmsg
));
275 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
276 req
.n
.nlmsg_type
= RTM_NEWNEIGH
;
277 req
.ndm
.ndm_family
= AF_INET
;
278 req
.ndm
.ndm_state
= NUD_STALE
;
279 req
.ndm
.ndm_ifindex
= ifindex
;
280 req
.ndm
.ndm_type
= RTN_UNICAST
;
282 addattr_l(&req
.n
, sizeof(req
), NDA_DST
, &addr
, 4);
283 addattr_l(&req
.n
, sizeof(req
), NDA_LLADDR
, lla
, llalen
);
284 return rtnl_send(&rth
, (char*)&req
, req
.n
.nlmsg_len
) <= 0;
287 void prepare_neg_entry(__u8
*ndata
, __u32 stamp
)
291 ndata
[2] = stamp
>>24;
292 ndata
[3] = stamp
>>16;
298 int do_one_request(struct nlmsghdr
*n
)
300 struct ndmsg
*ndm
= NLMSG_DATA(n
);
301 int len
= n
->nlmsg_len
;
302 struct rtattr
* tb
[NDA_MAX
+1];
307 if (n
->nlmsg_type
== NLMSG_DONE
) {
308 dbase
->sync(dbase
, 0);
310 /* Now we have at least mirror of kernel db, so that
311 * may start real resolution.
313 do_sysctl_adjustments();
317 if (n
->nlmsg_type
!= RTM_GETNEIGH
&& n
->nlmsg_type
!= RTM_NEWNEIGH
)
320 len
-= NLMSG_LENGTH(sizeof(*ndm
));
324 if (ndm
->ndm_family
!= AF_INET
||
325 (ifnum
&& !handle_if(ndm
->ndm_ifindex
)) ||
327 ndm
->ndm_type
!= RTN_UNICAST
||
328 !(ndm
->ndm_state
&~NUD_NOARP
))
331 parse_rtattr(tb
, NDA_MAX
, NDA_RTA(ndm
), len
);
336 key
.iface
= ndm
->ndm_ifindex
;
337 memcpy(&key
.addr
, RTA_DATA(tb
[NDA_DST
]), 4);
339 dbkey
.size
= sizeof(key
);
341 if (dbase
->get(dbase
, &dbkey
, &dbdat
, 0) != 0) {
346 if (n
->nlmsg_type
== RTM_GETNEIGH
) {
347 if (!(n
->nlmsg_flags
&NLM_F_REQUEST
))
350 if (!(ndm
->ndm_state
&(NUD_PROBE
|NUD_INCOMPLETE
))) {
355 if (ndm
->ndm_state
&NUD_PROBE
) {
356 /* If we get this, kernel still has some valid
357 * address, but unicast probing failed and host
358 * is either dead or changed its mac address.
359 * Kernel is going to initiate broadcast resolution.
360 * OK, we invalidate our information as well.
362 if (dbdat
.data
&& !IS_NEG(dbdat
.data
))
365 dbase
->del(dbase
, &dbkey
, 0);
367 /* If we get this kernel does not have any information.
368 * If we have something tell this to kernel. */
370 if (dbdat
.data
&& !IS_NEG(dbdat
.data
)) {
372 respond_to_kernel(key
.iface
, key
.addr
, dbdat
.data
, dbdat
.size
);
376 /* Sheeit! We have nothing to tell. */
377 /* If we have recent negative entry, be silent. */
378 if (dbdat
.data
&& NEG_VALID(dbdat
.data
)) {
379 if (NEG_CNT(dbdat
.data
) >= active_probing
) {
380 stats
.app_suppressed
++;
387 if (active_probing
&&
388 queue_active_probe(ndm
->ndm_ifindex
, key
.addr
) == 0 &&
390 NEG_CNT(dbdat
.data
)++;
391 dbase
->put(dbase
, &dbkey
, &dbdat
, 0);
393 } else if (n
->nlmsg_type
== RTM_NEWNEIGH
) {
394 if (n
->nlmsg_flags
&NLM_F_REQUEST
)
397 if (ndm
->ndm_state
&NUD_FAILED
) {
398 /* Kernel was not able to resolve. Host is dead.
399 * Create negative entry if it is not present
400 * or renew it if it is too old. */
402 !IS_NEG(dbdat
.data
) ||
403 !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 void load_initial_table(void)
429 rtnl_wilddump_request(&rth
, AF_INET
, RTM_GETNEIGH
);
432 void get_kern_msg(void)
436 struct sockaddr_nl nladdr
;
439 struct msghdr msg
= {
440 (void*)&nladdr
, sizeof(nladdr
),
446 memset(&nladdr
, 0, 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 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 void catch_signal(int sig
, void (*handler
)(int))
537 memset(&sa
, 0, sizeof(sa
));
538 sa
.sa_handler
= handler
;
540 sa
.sa_flags
= SA_INTERRUPT
;
542 sigaction(sig
, &sa
, NULL
);
547 volatile int in_poll
;
549 void sig_exit(int signo
)
556 void sig_sync(int signo
)
563 void sig_stats(int signo
)
571 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: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 ((broadcast_rate
= atoi(optarg
)) <= 0 ||
620 (broadcast_rate
= 1000/broadcast_rate
) <= 0) {
621 fprintf(stderr
, "Invalid ARP rate\n");
626 if ((broadcast_burst
= atoi(optarg
)) <= 0 ||
627 (broadcast_burst
= 1000*broadcast_burst
) <= 0) {
628 fprintf(stderr
, "Invalid ARP burst\n");
644 ifvec
= malloc(argc
*sizeof(int));
651 if ((udp_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
659 memset(&ifr
, 0, sizeof(ifr
));
660 for (i
=0; i
<ifnum
; i
++) {
661 strncpy(ifr
.ifr_name
, ifnames
[i
], IFNAMSIZ
);
662 if (ioctl(udp_sock
, SIOCGIFINDEX
, &ifr
)) {
663 perror("ioctl(SIOCGIFINDEX)");
666 ifvec
[i
] = ifr
.ifr_ifindex
;
670 dbase
= dbopen(dbname
, O_CREAT
|O_RDWR
, 0644, DB_HASH
, NULL
);
683 dbkey
.size
= sizeof(k
);
685 if (strcmp(do_load
, "-") == 0 || strcmp(do_load
, "--") == 0) {
687 } else if ((fp
= fopen(do_load
, "r")) == NULL
) {
692 buf
[sizeof(buf
)-1] = 0;
693 while (fgets(buf
, sizeof(buf
)-1, fp
)) {
701 if (sscanf(buf
, "%u%s%s", &k
.iface
, ipbuf
, macbuf
) != 3) {
702 fprintf(stderr
, "Wrong format of input file \"%s\"\n", do_load
);
705 if (strncmp(macbuf
, "FAILED:", 7) == 0)
707 if (!inet_aton(ipbuf
, (struct in_addr
*)&k
.addr
)) {
708 fprintf(stderr
, "Invalid IP address: \"%s\"\n", ipbuf
);
712 dbdat
.data
= hexstring_a2n(macbuf
, b1
, 6);
713 if (dbdat
.data
== NULL
)
717 if (dbase
->put(dbase
, &dbkey
, &dbdat
, 0)) {
722 dbase
->sync(dbase
, 0);
729 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
730 while (dbase
->seq(dbase
, &dbkey
, &dbdat
, R_NEXT
) == 0) {
731 struct dbkey
*key
= dbkey
.data
;
732 if (handle_if(key
->iface
)) {
733 if (!IS_NEG(dbdat
.data
)) {
735 printf("%-8d %-15s %s\n",
737 inet_ntoa(*(struct in_addr
*)&key
->addr
),
738 hexstring_n2a(dbdat
.data
, 6, b1
, 18));
740 printf("%-8d %-15s FAILED: %dsec ago\n",
742 inet_ntoa(*(struct in_addr
*)&key
->addr
),
743 NEG_AGE(dbdat
.data
));
749 if (do_load
|| do_list
)
752 pset
[0].fd
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
753 if (pset
[0].fd
< 0) {
759 struct sockaddr_ll sll
;
760 memset(&sll
, 0, sizeof(sll
));
761 sll
.sll_family
= AF_PACKET
;
762 sll
.sll_protocol
= htons(ETH_P_ARP
);
763 sll
.sll_ifindex
= (ifnum
== 1 ? ifvec
[0] : 0);
764 if (bind(pset
[0].fd
, (struct sockaddr
*)&sll
, sizeof(sll
)) < 0) {
770 if (rtnl_open(&rth
, RTMGRP_NEIGH
) < 0) {
776 load_initial_table();
785 perror("arpd: fork");
790 fd
= open("/dev/null", O_RDWR
);
801 openlog("arpd", LOG_PID
| LOG_CONS
, LOG_DAEMON
);
802 catch_signal(SIGINT
, sig_exit
);
803 catch_signal(SIGTERM
, sig_exit
);
804 catch_signal(SIGHUP
, sig_sync
);
805 catch_signal(SIGUSR1
, sig_stats
);
807 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
808 pset
[0].events
= EVENTS
;
810 pset
[1].events
= EVENTS
;
822 dbase
->sync(dbase
, 0);
828 if (poll(pset
, 2, 30000) > 0) {
830 if (pset
[0].revents
&EVENTS
)
832 if (pset
[1].revents
&EVENTS
)
839 undo_sysctl_adjustments();