xref: /aosp_15_r20/external/iproute2/misc/arpd.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * arpd.c	ARP helper daemon.
3*de1e4e89SAndroid Build Coastguard Worker  *
4*de1e4e89SAndroid Build Coastguard Worker  *		This program is free software; you can redistribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker  *		modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker  *		as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker  *		2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker  *
9*de1e4e89SAndroid Build Coastguard Worker  * Authors:	Alexey Kuznetsov, <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker  */
11*de1e4e89SAndroid Build Coastguard Worker 
12*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <malloc.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <netdb.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <db_185.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <sys/ioctl.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <sys/poll.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
24*de1e4e89SAndroid Build Coastguard Worker #include <sys/uio.h>
25*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
26*de1e4e89SAndroid Build Coastguard Worker #include <sys/time.h>
27*de1e4e89SAndroid Build Coastguard Worker #include <time.h>
28*de1e4e89SAndroid Build Coastguard Worker #include <signal.h>
29*de1e4e89SAndroid Build Coastguard Worker #include <linux/if.h>
30*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_ether.h>
31*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_arp.h>
32*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
33*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
34*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_packet.h>
35*de1e4e89SAndroid Build Coastguard Worker #include <linux/filter.h>
36*de1e4e89SAndroid Build Coastguard Worker 
37*de1e4e89SAndroid Build Coastguard Worker #include "libnetlink.h"
38*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
39*de1e4e89SAndroid Build Coastguard Worker #include "rt_names.h"
40*de1e4e89SAndroid Build Coastguard Worker 
41*de1e4e89SAndroid Build Coastguard Worker DB	*dbase;
42*de1e4e89SAndroid Build Coastguard Worker char	*dbname = "/var/lib/arpd/arpd.db";
43*de1e4e89SAndroid Build Coastguard Worker 
44*de1e4e89SAndroid Build Coastguard Worker int	ifnum;
45*de1e4e89SAndroid Build Coastguard Worker int	*ifvec;
46*de1e4e89SAndroid Build Coastguard Worker char	**ifnames;
47*de1e4e89SAndroid Build Coastguard Worker 
48*de1e4e89SAndroid Build Coastguard Worker struct dbkey {
49*de1e4e89SAndroid Build Coastguard Worker 	__u32	iface;
50*de1e4e89SAndroid Build Coastguard Worker 	__u32	addr;
51*de1e4e89SAndroid Build Coastguard Worker };
52*de1e4e89SAndroid Build Coastguard Worker 
53*de1e4e89SAndroid Build Coastguard Worker #define IS_NEG(x)	(((__u8 *)(x))[0] == 0xFF)
54*de1e4e89SAndroid Build Coastguard Worker #define NEG_TIME(x)	(((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
55*de1e4e89SAndroid Build Coastguard Worker #define NEG_AGE(x)	((__u32)time(NULL) - NEG_TIME((__u8 *)x))
56*de1e4e89SAndroid Build Coastguard Worker #define NEG_VALID(x)	(NEG_AGE(x) < negative_timeout)
57*de1e4e89SAndroid Build Coastguard Worker #define NEG_CNT(x)	(((__u8 *)(x))[1])
58*de1e4e89SAndroid Build Coastguard Worker 
59*de1e4e89SAndroid Build Coastguard Worker struct rtnl_handle rth;
60*de1e4e89SAndroid Build Coastguard Worker 
61*de1e4e89SAndroid Build Coastguard Worker struct pollfd pset[2];
62*de1e4e89SAndroid Build Coastguard Worker int udp_sock = -1;
63*de1e4e89SAndroid Build Coastguard Worker 
64*de1e4e89SAndroid Build Coastguard Worker volatile int do_exit;
65*de1e4e89SAndroid Build Coastguard Worker volatile int do_sync;
66*de1e4e89SAndroid Build Coastguard Worker volatile int do_stats;
67*de1e4e89SAndroid Build Coastguard Worker 
68*de1e4e89SAndroid Build Coastguard Worker struct {
69*de1e4e89SAndroid Build Coastguard Worker 	unsigned long arp_new;
70*de1e4e89SAndroid Build Coastguard Worker 	unsigned long arp_change;
71*de1e4e89SAndroid Build Coastguard Worker 
72*de1e4e89SAndroid Build Coastguard Worker 	unsigned long app_recv;
73*de1e4e89SAndroid Build Coastguard Worker 	unsigned long app_success;
74*de1e4e89SAndroid Build Coastguard Worker 	unsigned long app_bad;
75*de1e4e89SAndroid Build Coastguard Worker 	unsigned long app_neg;
76*de1e4e89SAndroid Build Coastguard Worker 	unsigned long app_suppressed;
77*de1e4e89SAndroid Build Coastguard Worker 
78*de1e4e89SAndroid Build Coastguard Worker 	unsigned long kern_neg;
79*de1e4e89SAndroid Build Coastguard Worker 	unsigned long kern_new;
80*de1e4e89SAndroid Build Coastguard Worker 	unsigned long kern_change;
81*de1e4e89SAndroid Build Coastguard Worker 
82*de1e4e89SAndroid Build Coastguard Worker 	unsigned long probes_sent;
83*de1e4e89SAndroid Build Coastguard Worker 	unsigned long probes_suppressed;
84*de1e4e89SAndroid Build Coastguard Worker } stats;
85*de1e4e89SAndroid Build Coastguard Worker 
86*de1e4e89SAndroid Build Coastguard Worker int active_probing;
87*de1e4e89SAndroid Build Coastguard Worker int negative_timeout = 60;
88*de1e4e89SAndroid Build Coastguard Worker int no_kernel_broadcasts;
89*de1e4e89SAndroid Build Coastguard Worker int broadcast_rate = 1000;
90*de1e4e89SAndroid Build Coastguard Worker int broadcast_burst = 3000;
91*de1e4e89SAndroid Build Coastguard Worker int poll_timeout = 30000;
92*de1e4e89SAndroid Build Coastguard Worker 
usage(void)93*de1e4e89SAndroid Build Coastguard Worker static void usage(void)
94*de1e4e89SAndroid Build Coastguard Worker {
95*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr,
96*de1e4e89SAndroid Build Coastguard Worker 		"Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ] [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n");
97*de1e4e89SAndroid Build Coastguard Worker 	exit(1);
98*de1e4e89SAndroid Build Coastguard Worker }
99*de1e4e89SAndroid Build Coastguard Worker 
handle_if(int ifindex)100*de1e4e89SAndroid Build Coastguard Worker static int handle_if(int ifindex)
101*de1e4e89SAndroid Build Coastguard Worker {
102*de1e4e89SAndroid Build Coastguard Worker 	int i;
103*de1e4e89SAndroid Build Coastguard Worker 
104*de1e4e89SAndroid Build Coastguard Worker 	if (ifnum == 0)
105*de1e4e89SAndroid Build Coastguard Worker 		return 1;
106*de1e4e89SAndroid Build Coastguard Worker 
107*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < ifnum; i++)
108*de1e4e89SAndroid Build Coastguard Worker 		if (ifvec[i] == ifindex)
109*de1e4e89SAndroid Build Coastguard Worker 			return 1;
110*de1e4e89SAndroid Build Coastguard Worker 	return 0;
111*de1e4e89SAndroid Build Coastguard Worker }
112*de1e4e89SAndroid Build Coastguard Worker 
113*de1e4e89SAndroid Build Coastguard Worker int sysctl_adjusted;
114*de1e4e89SAndroid Build Coastguard Worker 
do_sysctl_adjustments(void)115*de1e4e89SAndroid Build Coastguard Worker static void do_sysctl_adjustments(void)
116*de1e4e89SAndroid Build Coastguard Worker {
117*de1e4e89SAndroid Build Coastguard Worker 	int i;
118*de1e4e89SAndroid Build Coastguard Worker 
119*de1e4e89SAndroid Build Coastguard Worker 	if (!ifnum)
120*de1e4e89SAndroid Build Coastguard Worker 		return;
121*de1e4e89SAndroid Build Coastguard Worker 
122*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < ifnum; i++) {
123*de1e4e89SAndroid Build Coastguard Worker 		char buf[128];
124*de1e4e89SAndroid Build Coastguard Worker 		FILE *fp;
125*de1e4e89SAndroid Build Coastguard Worker 
126*de1e4e89SAndroid Build Coastguard Worker 		if (active_probing) {
127*de1e4e89SAndroid Build Coastguard Worker 			sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
128*de1e4e89SAndroid Build Coastguard Worker 			if ((fp = fopen(buf, "w")) != NULL) {
129*de1e4e89SAndroid Build Coastguard Worker 				if (no_kernel_broadcasts)
130*de1e4e89SAndroid Build Coastguard Worker 					strcpy(buf, "0\n");
131*de1e4e89SAndroid Build Coastguard Worker 				else
132*de1e4e89SAndroid Build Coastguard Worker 					sprintf(buf, "%d\n", active_probing >= 2 ? 1 : 3-active_probing);
133*de1e4e89SAndroid Build Coastguard Worker 				fputs(buf, fp);
134*de1e4e89SAndroid Build Coastguard Worker 				fclose(fp);
135*de1e4e89SAndroid Build Coastguard Worker 			}
136*de1e4e89SAndroid Build Coastguard Worker 		}
137*de1e4e89SAndroid Build Coastguard Worker 
138*de1e4e89SAndroid Build Coastguard Worker 		sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
139*de1e4e89SAndroid Build Coastguard Worker 		if ((fp = fopen(buf, "w")) != NULL) {
140*de1e4e89SAndroid Build Coastguard Worker 			sprintf(buf, "%d\n", active_probing <= 1 ? 1 : active_probing);
141*de1e4e89SAndroid Build Coastguard Worker 			fputs(buf, fp);
142*de1e4e89SAndroid Build Coastguard Worker 			fclose(fp);
143*de1e4e89SAndroid Build Coastguard Worker 		}
144*de1e4e89SAndroid Build Coastguard Worker 	}
145*de1e4e89SAndroid Build Coastguard Worker 	sysctl_adjusted = 1;
146*de1e4e89SAndroid Build Coastguard Worker }
147*de1e4e89SAndroid Build Coastguard Worker 
undo_sysctl_adjustments(void)148*de1e4e89SAndroid Build Coastguard Worker static void undo_sysctl_adjustments(void)
149*de1e4e89SAndroid Build Coastguard Worker {
150*de1e4e89SAndroid Build Coastguard Worker 	int i;
151*de1e4e89SAndroid Build Coastguard Worker 
152*de1e4e89SAndroid Build Coastguard Worker 	if (!sysctl_adjusted)
153*de1e4e89SAndroid Build Coastguard Worker 		return;
154*de1e4e89SAndroid Build Coastguard Worker 
155*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < ifnum; i++) {
156*de1e4e89SAndroid Build Coastguard Worker 		char buf[128];
157*de1e4e89SAndroid Build Coastguard Worker 		FILE *fp;
158*de1e4e89SAndroid Build Coastguard Worker 
159*de1e4e89SAndroid Build Coastguard Worker 		if (active_probing) {
160*de1e4e89SAndroid Build Coastguard Worker 			sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
161*de1e4e89SAndroid Build Coastguard Worker 			if ((fp = fopen(buf, "w")) != NULL) {
162*de1e4e89SAndroid Build Coastguard Worker 				strcpy(buf, "3\n");
163*de1e4e89SAndroid Build Coastguard Worker 				fputs(buf, fp);
164*de1e4e89SAndroid Build Coastguard Worker 				fclose(fp);
165*de1e4e89SAndroid Build Coastguard Worker 			}
166*de1e4e89SAndroid Build Coastguard Worker 		}
167*de1e4e89SAndroid Build Coastguard Worker 		sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
168*de1e4e89SAndroid Build Coastguard Worker 		if ((fp = fopen(buf, "w")) != NULL) {
169*de1e4e89SAndroid Build Coastguard Worker 			strcpy(buf, "0\n");
170*de1e4e89SAndroid Build Coastguard Worker 			fputs(buf, fp);
171*de1e4e89SAndroid Build Coastguard Worker 			fclose(fp);
172*de1e4e89SAndroid Build Coastguard Worker 		}
173*de1e4e89SAndroid Build Coastguard Worker 	}
174*de1e4e89SAndroid Build Coastguard Worker 	sysctl_adjusted = 0;
175*de1e4e89SAndroid Build Coastguard Worker }
176*de1e4e89SAndroid Build Coastguard Worker 
177*de1e4e89SAndroid Build Coastguard Worker 
send_probe(int ifindex,__u32 addr)178*de1e4e89SAndroid Build Coastguard Worker static int send_probe(int ifindex, __u32 addr)
179*de1e4e89SAndroid Build Coastguard Worker {
180*de1e4e89SAndroid Build Coastguard Worker 	struct ifreq ifr = { .ifr_ifindex = ifindex };
181*de1e4e89SAndroid Build Coastguard Worker 	struct sockaddr_in dst = {
182*de1e4e89SAndroid Build Coastguard Worker 		.sin_family = AF_INET,
183*de1e4e89SAndroid Build Coastguard Worker 		.sin_port = htons(1025),
184*de1e4e89SAndroid Build Coastguard Worker 		.sin_addr.s_addr = addr,
185*de1e4e89SAndroid Build Coastguard Worker 	};
186*de1e4e89SAndroid Build Coastguard Worker 	socklen_t len;
187*de1e4e89SAndroid Build Coastguard Worker 	unsigned char buf[256];
188*de1e4e89SAndroid Build Coastguard Worker 	struct arphdr *ah = (struct arphdr *)buf;
189*de1e4e89SAndroid Build Coastguard Worker 	unsigned char *p = (unsigned char *)(ah+1);
190*de1e4e89SAndroid Build Coastguard Worker 	struct sockaddr_ll sll = {
191*de1e4e89SAndroid Build Coastguard Worker 		.sll_family = AF_PACKET,
192*de1e4e89SAndroid Build Coastguard Worker 		.sll_ifindex = ifindex,
193*de1e4e89SAndroid Build Coastguard Worker 		.sll_protocol = htons(ETH_P_ARP),
194*de1e4e89SAndroid Build Coastguard Worker 	};
195*de1e4e89SAndroid Build Coastguard Worker 
196*de1e4e89SAndroid Build Coastguard Worker 	if (ioctl(udp_sock, SIOCGIFNAME, &ifr))
197*de1e4e89SAndroid Build Coastguard Worker 		return -1;
198*de1e4e89SAndroid Build Coastguard Worker 	if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr))
199*de1e4e89SAndroid Build Coastguard Worker 		return -1;
200*de1e4e89SAndroid Build Coastguard Worker 	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
201*de1e4e89SAndroid Build Coastguard Worker 		return -1;
202*de1e4e89SAndroid Build Coastguard Worker 	if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0)
203*de1e4e89SAndroid Build Coastguard Worker 		return -1;
204*de1e4e89SAndroid Build Coastguard Worker 
205*de1e4e89SAndroid Build Coastguard Worker 	if (connect(udp_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0)
206*de1e4e89SAndroid Build Coastguard Worker 		return -1;
207*de1e4e89SAndroid Build Coastguard Worker 	len = sizeof(dst);
208*de1e4e89SAndroid Build Coastguard Worker 	if (getsockname(udp_sock, (struct sockaddr *)&dst, &len) < 0)
209*de1e4e89SAndroid Build Coastguard Worker 		return -1;
210*de1e4e89SAndroid Build Coastguard Worker 
211*de1e4e89SAndroid Build Coastguard Worker 	ah->ar_hrd = htons(ifr.ifr_hwaddr.sa_family);
212*de1e4e89SAndroid Build Coastguard Worker 	ah->ar_pro = htons(ETH_P_IP);
213*de1e4e89SAndroid Build Coastguard Worker 	ah->ar_hln = 6;
214*de1e4e89SAndroid Build Coastguard Worker 	ah->ar_pln = 4;
215*de1e4e89SAndroid Build Coastguard Worker 	ah->ar_op  = htons(ARPOP_REQUEST);
216*de1e4e89SAndroid Build Coastguard Worker 
217*de1e4e89SAndroid Build Coastguard Worker 	memcpy(p, ifr.ifr_hwaddr.sa_data, ah->ar_hln);
218*de1e4e89SAndroid Build Coastguard Worker 	p += ah->ar_hln;
219*de1e4e89SAndroid Build Coastguard Worker 
220*de1e4e89SAndroid Build Coastguard Worker 	memcpy(p, &dst.sin_addr, 4);
221*de1e4e89SAndroid Build Coastguard Worker 	p += 4;
222*de1e4e89SAndroid Build Coastguard Worker 
223*de1e4e89SAndroid Build Coastguard Worker 	memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr));
224*de1e4e89SAndroid Build Coastguard Worker 	memcpy(p, &sll.sll_addr, ah->ar_hln);
225*de1e4e89SAndroid Build Coastguard Worker 	p += ah->ar_hln;
226*de1e4e89SAndroid Build Coastguard Worker 
227*de1e4e89SAndroid Build Coastguard Worker 	memcpy(p, &addr, 4);
228*de1e4e89SAndroid Build Coastguard Worker 	p += 4;
229*de1e4e89SAndroid Build Coastguard Worker 
230*de1e4e89SAndroid Build Coastguard Worker 	if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr *)&sll, sizeof(sll)) < 0)
231*de1e4e89SAndroid Build Coastguard Worker 		return -1;
232*de1e4e89SAndroid Build Coastguard Worker 	stats.probes_sent++;
233*de1e4e89SAndroid Build Coastguard Worker 	return 0;
234*de1e4e89SAndroid Build Coastguard Worker }
235*de1e4e89SAndroid Build Coastguard Worker 
236*de1e4e89SAndroid Build Coastguard Worker /* Be very tough on sending probes: 1 per second with burst of 3. */
237*de1e4e89SAndroid Build Coastguard Worker 
queue_active_probe(int ifindex,__u32 addr)238*de1e4e89SAndroid Build Coastguard Worker static int queue_active_probe(int ifindex, __u32 addr)
239*de1e4e89SAndroid Build Coastguard Worker {
240*de1e4e89SAndroid Build Coastguard Worker 	static struct timeval prev;
241*de1e4e89SAndroid Build Coastguard Worker 	static int buckets;
242*de1e4e89SAndroid Build Coastguard Worker 	struct timeval now;
243*de1e4e89SAndroid Build Coastguard Worker 
244*de1e4e89SAndroid Build Coastguard Worker 	gettimeofday(&now, NULL);
245*de1e4e89SAndroid Build Coastguard Worker 	if (prev.tv_sec) {
246*de1e4e89SAndroid Build Coastguard Worker 		int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000;
247*de1e4e89SAndroid Build Coastguard Worker 
248*de1e4e89SAndroid Build Coastguard Worker 		buckets += diff;
249*de1e4e89SAndroid Build Coastguard Worker 	} else {
250*de1e4e89SAndroid Build Coastguard Worker 		buckets = broadcast_burst;
251*de1e4e89SAndroid Build Coastguard Worker 	}
252*de1e4e89SAndroid Build Coastguard Worker 	if (buckets > broadcast_burst)
253*de1e4e89SAndroid Build Coastguard Worker 		buckets = broadcast_burst;
254*de1e4e89SAndroid Build Coastguard Worker 	if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) {
255*de1e4e89SAndroid Build Coastguard Worker 		buckets -= broadcast_rate;
256*de1e4e89SAndroid Build Coastguard Worker 		prev = now;
257*de1e4e89SAndroid Build Coastguard Worker 		return 0;
258*de1e4e89SAndroid Build Coastguard Worker 	}
259*de1e4e89SAndroid Build Coastguard Worker 	stats.probes_suppressed++;
260*de1e4e89SAndroid Build Coastguard Worker 	return -1;
261*de1e4e89SAndroid Build Coastguard Worker }
262*de1e4e89SAndroid Build Coastguard Worker 
respond_to_kernel(int ifindex,__u32 addr,char * lla,int llalen)263*de1e4e89SAndroid Build Coastguard Worker static int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen)
264*de1e4e89SAndroid Build Coastguard Worker {
265*de1e4e89SAndroid Build Coastguard Worker 	struct {
266*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr	n;
267*de1e4e89SAndroid Build Coastguard Worker 		struct ndmsg		ndm;
268*de1e4e89SAndroid Build Coastguard Worker 		char			buf[256];
269*de1e4e89SAndroid Build Coastguard Worker 	} req = {
270*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
271*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_flags = NLM_F_REQUEST,
272*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_type = RTM_NEWNEIGH,
273*de1e4e89SAndroid Build Coastguard Worker 		.ndm.ndm_family = AF_INET,
274*de1e4e89SAndroid Build Coastguard Worker 		.ndm.ndm_state = NUD_STALE,
275*de1e4e89SAndroid Build Coastguard Worker 		.ndm.ndm_ifindex = ifindex,
276*de1e4e89SAndroid Build Coastguard Worker 		.ndm.ndm_type = RTN_UNICAST,
277*de1e4e89SAndroid Build Coastguard Worker 	};
278*de1e4e89SAndroid Build Coastguard Worker 
279*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
280*de1e4e89SAndroid Build Coastguard Worker 	addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
281*de1e4e89SAndroid Build Coastguard Worker 	return rtnl_send(&rth, &req, req.n.nlmsg_len) <= 0;
282*de1e4e89SAndroid Build Coastguard Worker }
283*de1e4e89SAndroid Build Coastguard Worker 
prepare_neg_entry(__u8 * ndata,__u32 stamp)284*de1e4e89SAndroid Build Coastguard Worker static void prepare_neg_entry(__u8 *ndata, __u32 stamp)
285*de1e4e89SAndroid Build Coastguard Worker {
286*de1e4e89SAndroid Build Coastguard Worker 	ndata[0] = 0xFF;
287*de1e4e89SAndroid Build Coastguard Worker 	ndata[1] = 0;
288*de1e4e89SAndroid Build Coastguard Worker 	ndata[2] = stamp>>24;
289*de1e4e89SAndroid Build Coastguard Worker 	ndata[3] = stamp>>16;
290*de1e4e89SAndroid Build Coastguard Worker 	ndata[4] = stamp>>8;
291*de1e4e89SAndroid Build Coastguard Worker 	ndata[5] = stamp;
292*de1e4e89SAndroid Build Coastguard Worker }
293*de1e4e89SAndroid Build Coastguard Worker 
294*de1e4e89SAndroid Build Coastguard Worker 
do_one_request(struct nlmsghdr * n)295*de1e4e89SAndroid Build Coastguard Worker static int do_one_request(struct nlmsghdr *n)
296*de1e4e89SAndroid Build Coastguard Worker {
297*de1e4e89SAndroid Build Coastguard Worker 	struct ndmsg *ndm = NLMSG_DATA(n);
298*de1e4e89SAndroid Build Coastguard Worker 	int len = n->nlmsg_len;
299*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[NDA_MAX+1];
300*de1e4e89SAndroid Build Coastguard Worker 	struct dbkey key;
301*de1e4e89SAndroid Build Coastguard Worker 	DBT dbkey, dbdat;
302*de1e4e89SAndroid Build Coastguard Worker 	int do_acct = 0;
303*de1e4e89SAndroid Build Coastguard Worker 
304*de1e4e89SAndroid Build Coastguard Worker 	if (n->nlmsg_type == NLMSG_DONE) {
305*de1e4e89SAndroid Build Coastguard Worker 		dbase->sync(dbase, 0);
306*de1e4e89SAndroid Build Coastguard Worker 
307*de1e4e89SAndroid Build Coastguard Worker 		/* Now we have at least mirror of kernel db, so that
308*de1e4e89SAndroid Build Coastguard Worker 		 * may start real resolution.
309*de1e4e89SAndroid Build Coastguard Worker 		 */
310*de1e4e89SAndroid Build Coastguard Worker 		do_sysctl_adjustments();
311*de1e4e89SAndroid Build Coastguard Worker 		return 0;
312*de1e4e89SAndroid Build Coastguard Worker 	}
313*de1e4e89SAndroid Build Coastguard Worker 
314*de1e4e89SAndroid Build Coastguard Worker 	if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH)
315*de1e4e89SAndroid Build Coastguard Worker 		return 0;
316*de1e4e89SAndroid Build Coastguard Worker 
317*de1e4e89SAndroid Build Coastguard Worker 	len -= NLMSG_LENGTH(sizeof(*ndm));
318*de1e4e89SAndroid Build Coastguard Worker 	if (len < 0)
319*de1e4e89SAndroid Build Coastguard Worker 		return -1;
320*de1e4e89SAndroid Build Coastguard Worker 
321*de1e4e89SAndroid Build Coastguard Worker 	if (ndm->ndm_family != AF_INET ||
322*de1e4e89SAndroid Build Coastguard Worker 	    (ifnum && !handle_if(ndm->ndm_ifindex)) ||
323*de1e4e89SAndroid Build Coastguard Worker 	    ndm->ndm_flags ||
324*de1e4e89SAndroid Build Coastguard Worker 	    ndm->ndm_type != RTN_UNICAST ||
325*de1e4e89SAndroid Build Coastguard Worker 	    !(ndm->ndm_state&~NUD_NOARP))
326*de1e4e89SAndroid Build Coastguard Worker 		return 0;
327*de1e4e89SAndroid Build Coastguard Worker 
328*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
329*de1e4e89SAndroid Build Coastguard Worker 
330*de1e4e89SAndroid Build Coastguard Worker 	if (!tb[NDA_DST])
331*de1e4e89SAndroid Build Coastguard Worker 		return 0;
332*de1e4e89SAndroid Build Coastguard Worker 
333*de1e4e89SAndroid Build Coastguard Worker 	key.iface = ndm->ndm_ifindex;
334*de1e4e89SAndroid Build Coastguard Worker 	memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4);
335*de1e4e89SAndroid Build Coastguard Worker 	dbkey.data = &key;
336*de1e4e89SAndroid Build Coastguard Worker 	dbkey.size = sizeof(key);
337*de1e4e89SAndroid Build Coastguard Worker 
338*de1e4e89SAndroid Build Coastguard Worker 	if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) {
339*de1e4e89SAndroid Build Coastguard Worker 		dbdat.data = 0;
340*de1e4e89SAndroid Build Coastguard Worker 		dbdat.size = 0;
341*de1e4e89SAndroid Build Coastguard Worker 	}
342*de1e4e89SAndroid Build Coastguard Worker 
343*de1e4e89SAndroid Build Coastguard Worker 	if (n->nlmsg_type == RTM_GETNEIGH) {
344*de1e4e89SAndroid Build Coastguard Worker 		if (!(n->nlmsg_flags&NLM_F_REQUEST))
345*de1e4e89SAndroid Build Coastguard Worker 			return 0;
346*de1e4e89SAndroid Build Coastguard Worker 
347*de1e4e89SAndroid Build Coastguard Worker 		if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) {
348*de1e4e89SAndroid Build Coastguard Worker 			stats.app_bad++;
349*de1e4e89SAndroid Build Coastguard Worker 			return 0;
350*de1e4e89SAndroid Build Coastguard Worker 		}
351*de1e4e89SAndroid Build Coastguard Worker 
352*de1e4e89SAndroid Build Coastguard Worker 		if (ndm->ndm_state&NUD_PROBE) {
353*de1e4e89SAndroid Build Coastguard Worker 			/* If we get this, kernel still has some valid
354*de1e4e89SAndroid Build Coastguard Worker 			 * address, but unicast probing failed and host
355*de1e4e89SAndroid Build Coastguard Worker 			 * is either dead or changed its mac address.
356*de1e4e89SAndroid Build Coastguard Worker 			 * Kernel is going to initiate broadcast resolution.
357*de1e4e89SAndroid Build Coastguard Worker 			 * OK, we invalidate our information as well.
358*de1e4e89SAndroid Build Coastguard Worker 			 */
359*de1e4e89SAndroid Build Coastguard Worker 			if (dbdat.data && !IS_NEG(dbdat.data))
360*de1e4e89SAndroid Build Coastguard Worker 				stats.app_neg++;
361*de1e4e89SAndroid Build Coastguard Worker 
362*de1e4e89SAndroid Build Coastguard Worker 			dbase->del(dbase, &dbkey, 0);
363*de1e4e89SAndroid Build Coastguard Worker 		} else {
364*de1e4e89SAndroid Build Coastguard Worker 			/* If we get this kernel does not have any information.
365*de1e4e89SAndroid Build Coastguard Worker 			 * If we have something tell this to kernel. */
366*de1e4e89SAndroid Build Coastguard Worker 			stats.app_recv++;
367*de1e4e89SAndroid Build Coastguard Worker 			if (dbdat.data && !IS_NEG(dbdat.data)) {
368*de1e4e89SAndroid Build Coastguard Worker 				stats.app_success++;
369*de1e4e89SAndroid Build Coastguard Worker 				respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size);
370*de1e4e89SAndroid Build Coastguard Worker 				return 0;
371*de1e4e89SAndroid Build Coastguard Worker 			}
372*de1e4e89SAndroid Build Coastguard Worker 
373*de1e4e89SAndroid Build Coastguard Worker 			/* Sheeit! We have nothing to tell. */
374*de1e4e89SAndroid Build Coastguard Worker 			/* If we have recent negative entry, be silent. */
375*de1e4e89SAndroid Build Coastguard Worker 			if (dbdat.data && NEG_VALID(dbdat.data)) {
376*de1e4e89SAndroid Build Coastguard Worker 				if (NEG_CNT(dbdat.data) >= active_probing) {
377*de1e4e89SAndroid Build Coastguard Worker 					stats.app_suppressed++;
378*de1e4e89SAndroid Build Coastguard Worker 					return 0;
379*de1e4e89SAndroid Build Coastguard Worker 				}
380*de1e4e89SAndroid Build Coastguard Worker 				do_acct = 1;
381*de1e4e89SAndroid Build Coastguard Worker 			}
382*de1e4e89SAndroid Build Coastguard Worker 		}
383*de1e4e89SAndroid Build Coastguard Worker 
384*de1e4e89SAndroid Build Coastguard Worker 		if (active_probing &&
385*de1e4e89SAndroid Build Coastguard Worker 		    queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 &&
386*de1e4e89SAndroid Build Coastguard Worker 		    do_acct) {
387*de1e4e89SAndroid Build Coastguard Worker 			NEG_CNT(dbdat.data)++;
388*de1e4e89SAndroid Build Coastguard Worker 			dbase->put(dbase, &dbkey, &dbdat, 0);
389*de1e4e89SAndroid Build Coastguard Worker 		}
390*de1e4e89SAndroid Build Coastguard Worker 	} else if (n->nlmsg_type == RTM_NEWNEIGH) {
391*de1e4e89SAndroid Build Coastguard Worker 		if (n->nlmsg_flags&NLM_F_REQUEST)
392*de1e4e89SAndroid Build Coastguard Worker 			return 0;
393*de1e4e89SAndroid Build Coastguard Worker 
394*de1e4e89SAndroid Build Coastguard Worker 		if (ndm->ndm_state&NUD_FAILED) {
395*de1e4e89SAndroid Build Coastguard Worker 			/* Kernel was not able to resolve. Host is dead.
396*de1e4e89SAndroid Build Coastguard Worker 			 * Create negative entry if it is not present
397*de1e4e89SAndroid Build Coastguard Worker 			 * or renew it if it is too old. */
398*de1e4e89SAndroid Build Coastguard Worker 			if (!dbdat.data ||
399*de1e4e89SAndroid Build Coastguard Worker 			    !IS_NEG(dbdat.data) ||
400*de1e4e89SAndroid Build Coastguard Worker 			    !NEG_VALID(dbdat.data)) {
401*de1e4e89SAndroid Build Coastguard Worker 				__u8 ndata[6];
402*de1e4e89SAndroid Build Coastguard Worker 
403*de1e4e89SAndroid Build Coastguard Worker 				stats.kern_neg++;
404*de1e4e89SAndroid Build Coastguard Worker 				prepare_neg_entry(ndata, time(NULL));
405*de1e4e89SAndroid Build Coastguard Worker 				dbdat.data = ndata;
406*de1e4e89SAndroid Build Coastguard Worker 				dbdat.size = sizeof(ndata);
407*de1e4e89SAndroid Build Coastguard Worker 				dbase->put(dbase, &dbkey, &dbdat, 0);
408*de1e4e89SAndroid Build Coastguard Worker 			}
409*de1e4e89SAndroid Build Coastguard Worker 		} else if (tb[NDA_LLADDR]) {
410*de1e4e89SAndroid Build Coastguard Worker 			if (dbdat.data && !IS_NEG(dbdat.data)) {
411*de1e4e89SAndroid Build Coastguard Worker 				if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0)
412*de1e4e89SAndroid Build Coastguard Worker 					return 0;
413*de1e4e89SAndroid Build Coastguard Worker 				stats.kern_change++;
414*de1e4e89SAndroid Build Coastguard Worker 			} else {
415*de1e4e89SAndroid Build Coastguard Worker 				stats.kern_new++;
416*de1e4e89SAndroid Build Coastguard Worker 			}
417*de1e4e89SAndroid Build Coastguard Worker 			dbdat.data = RTA_DATA(tb[NDA_LLADDR]);
418*de1e4e89SAndroid Build Coastguard Worker 			dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]);
419*de1e4e89SAndroid Build Coastguard Worker 			dbase->put(dbase, &dbkey, &dbdat, 0);
420*de1e4e89SAndroid Build Coastguard Worker 		}
421*de1e4e89SAndroid Build Coastguard Worker 	}
422*de1e4e89SAndroid Build Coastguard Worker 	return 0;
423*de1e4e89SAndroid Build Coastguard Worker }
424*de1e4e89SAndroid Build Coastguard Worker 
load_initial_table(void)425*de1e4e89SAndroid Build Coastguard Worker static void load_initial_table(void)
426*de1e4e89SAndroid Build Coastguard Worker {
427*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH) < 0) {
428*de1e4e89SAndroid Build Coastguard Worker 		perror("dump request failed");
429*de1e4e89SAndroid Build Coastguard Worker 		exit(1);
430*de1e4e89SAndroid Build Coastguard Worker 	}
431*de1e4e89SAndroid Build Coastguard Worker 
432*de1e4e89SAndroid Build Coastguard Worker }
433*de1e4e89SAndroid Build Coastguard Worker 
get_kern_msg(void)434*de1e4e89SAndroid Build Coastguard Worker static void get_kern_msg(void)
435*de1e4e89SAndroid Build Coastguard Worker {
436*de1e4e89SAndroid Build Coastguard Worker 	int status;
437*de1e4e89SAndroid Build Coastguard Worker 	struct nlmsghdr *h;
438*de1e4e89SAndroid Build Coastguard Worker 	struct sockaddr_nl nladdr = {};
439*de1e4e89SAndroid Build Coastguard Worker 	struct iovec iov;
440*de1e4e89SAndroid Build Coastguard Worker 	char   buf[8192];
441*de1e4e89SAndroid Build Coastguard Worker 	struct msghdr msg = {
442*de1e4e89SAndroid Build Coastguard Worker 		(void *)&nladdr, sizeof(nladdr),
443*de1e4e89SAndroid Build Coastguard Worker 		&iov,	1,
444*de1e4e89SAndroid Build Coastguard Worker 		NULL,	0,
445*de1e4e89SAndroid Build Coastguard Worker 		0
446*de1e4e89SAndroid Build Coastguard Worker 	};
447*de1e4e89SAndroid Build Coastguard Worker 
448*de1e4e89SAndroid Build Coastguard Worker 	iov.iov_base = buf;
449*de1e4e89SAndroid Build Coastguard Worker 	iov.iov_len = sizeof(buf);
450*de1e4e89SAndroid Build Coastguard Worker 
451*de1e4e89SAndroid Build Coastguard Worker 	status = recvmsg(rth.fd, &msg, MSG_DONTWAIT);
452*de1e4e89SAndroid Build Coastguard Worker 
453*de1e4e89SAndroid Build Coastguard Worker 	if (status <= 0)
454*de1e4e89SAndroid Build Coastguard Worker 		return;
455*de1e4e89SAndroid Build Coastguard Worker 
456*de1e4e89SAndroid Build Coastguard Worker 	if (msg.msg_namelen != sizeof(nladdr))
457*de1e4e89SAndroid Build Coastguard Worker 		return;
458*de1e4e89SAndroid Build Coastguard Worker 
459*de1e4e89SAndroid Build Coastguard Worker 	if (nladdr.nl_pid)
460*de1e4e89SAndroid Build Coastguard Worker 		return;
461*de1e4e89SAndroid Build Coastguard Worker 
462*de1e4e89SAndroid Build Coastguard Worker 	for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
463*de1e4e89SAndroid Build Coastguard Worker 		int len = h->nlmsg_len;
464*de1e4e89SAndroid Build Coastguard Worker 		int l = len - sizeof(*h);
465*de1e4e89SAndroid Build Coastguard Worker 
466*de1e4e89SAndroid Build Coastguard Worker 		if (l < 0 || len > status)
467*de1e4e89SAndroid Build Coastguard Worker 			return;
468*de1e4e89SAndroid Build Coastguard Worker 
469*de1e4e89SAndroid Build Coastguard Worker 		if (do_one_request(h) < 0)
470*de1e4e89SAndroid Build Coastguard Worker 			return;
471*de1e4e89SAndroid Build Coastguard Worker 
472*de1e4e89SAndroid Build Coastguard Worker 		status -= NLMSG_ALIGN(len);
473*de1e4e89SAndroid Build Coastguard Worker 		h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
474*de1e4e89SAndroid Build Coastguard Worker 	}
475*de1e4e89SAndroid Build Coastguard Worker }
476*de1e4e89SAndroid Build Coastguard Worker 
477*de1e4e89SAndroid Build Coastguard Worker /* Receive gratuitous ARP messages and store them, that's all. */
get_arp_pkt(void)478*de1e4e89SAndroid Build Coastguard Worker static void get_arp_pkt(void)
479*de1e4e89SAndroid Build Coastguard Worker {
480*de1e4e89SAndroid Build Coastguard Worker 	unsigned char buf[1024];
481*de1e4e89SAndroid Build Coastguard Worker 	struct sockaddr_ll sll;
482*de1e4e89SAndroid Build Coastguard Worker 	socklen_t sll_len = sizeof(sll);
483*de1e4e89SAndroid Build Coastguard Worker 	struct arphdr *a = (struct arphdr *)buf;
484*de1e4e89SAndroid Build Coastguard Worker 	struct dbkey key;
485*de1e4e89SAndroid Build Coastguard Worker 	DBT dbkey, dbdat;
486*de1e4e89SAndroid Build Coastguard Worker 	int n;
487*de1e4e89SAndroid Build Coastguard Worker 
488*de1e4e89SAndroid Build Coastguard Worker 	n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT,
489*de1e4e89SAndroid Build Coastguard Worker 		     (struct sockaddr *)&sll, &sll_len);
490*de1e4e89SAndroid Build Coastguard Worker 	if (n < 0) {
491*de1e4e89SAndroid Build Coastguard Worker 		if (errno != EINTR && errno != EAGAIN)
492*de1e4e89SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "recvfrom: %m");
493*de1e4e89SAndroid Build Coastguard Worker 		return;
494*de1e4e89SAndroid Build Coastguard Worker 	}
495*de1e4e89SAndroid Build Coastguard Worker 
496*de1e4e89SAndroid Build Coastguard Worker 	if (ifnum && !handle_if(sll.sll_ifindex))
497*de1e4e89SAndroid Build Coastguard Worker 		return;
498*de1e4e89SAndroid Build Coastguard Worker 
499*de1e4e89SAndroid Build Coastguard Worker 	/* Sanity checks */
500*de1e4e89SAndroid Build Coastguard Worker 
501*de1e4e89SAndroid Build Coastguard Worker 	if (n < sizeof(*a) ||
502*de1e4e89SAndroid Build Coastguard Worker 	    (a->ar_op != htons(ARPOP_REQUEST) &&
503*de1e4e89SAndroid Build Coastguard Worker 	     a->ar_op != htons(ARPOP_REPLY)) ||
504*de1e4e89SAndroid Build Coastguard Worker 	    a->ar_pln != 4 ||
505*de1e4e89SAndroid Build Coastguard Worker 	    a->ar_pro != htons(ETH_P_IP) ||
506*de1e4e89SAndroid Build Coastguard Worker 	    a->ar_hln != sll.sll_halen ||
507*de1e4e89SAndroid Build Coastguard Worker 	    sizeof(*a) + 2*4 + 2*a->ar_hln > n)
508*de1e4e89SAndroid Build Coastguard Worker 		return;
509*de1e4e89SAndroid Build Coastguard Worker 
510*de1e4e89SAndroid Build Coastguard Worker 	key.iface = sll.sll_ifindex;
511*de1e4e89SAndroid Build Coastguard Worker 	memcpy(&key.addr, (char *)(a+1) + a->ar_hln, 4);
512*de1e4e89SAndroid Build Coastguard Worker 
513*de1e4e89SAndroid Build Coastguard Worker 	/* DAD message, ignore. */
514*de1e4e89SAndroid Build Coastguard Worker 	if (key.addr == 0)
515*de1e4e89SAndroid Build Coastguard Worker 		return;
516*de1e4e89SAndroid Build Coastguard Worker 
517*de1e4e89SAndroid Build Coastguard Worker 	dbkey.data = &key;
518*de1e4e89SAndroid Build Coastguard Worker 	dbkey.size = sizeof(key);
519*de1e4e89SAndroid Build Coastguard Worker 
520*de1e4e89SAndroid Build Coastguard Worker 	if (dbase->get(dbase, &dbkey, &dbdat, 0) == 0 && !IS_NEG(dbdat.data)) {
521*de1e4e89SAndroid Build Coastguard Worker 		if (memcmp(dbdat.data, a+1, dbdat.size) == 0)
522*de1e4e89SAndroid Build Coastguard Worker 			return;
523*de1e4e89SAndroid Build Coastguard Worker 		stats.arp_change++;
524*de1e4e89SAndroid Build Coastguard Worker 	} else {
525*de1e4e89SAndroid Build Coastguard Worker 		stats.arp_new++;
526*de1e4e89SAndroid Build Coastguard Worker 	}
527*de1e4e89SAndroid Build Coastguard Worker 
528*de1e4e89SAndroid Build Coastguard Worker 	dbdat.data = a+1;
529*de1e4e89SAndroid Build Coastguard Worker 	dbdat.size = a->ar_hln;
530*de1e4e89SAndroid Build Coastguard Worker 	dbase->put(dbase, &dbkey, &dbdat, 0);
531*de1e4e89SAndroid Build Coastguard Worker }
532*de1e4e89SAndroid Build Coastguard Worker 
catch_signal(int sig,void (* handler)(int))533*de1e4e89SAndroid Build Coastguard Worker static void catch_signal(int sig, void (*handler)(int))
534*de1e4e89SAndroid Build Coastguard Worker {
535*de1e4e89SAndroid Build Coastguard Worker 	struct sigaction sa = { .sa_handler = handler };
536*de1e4e89SAndroid Build Coastguard Worker 
537*de1e4e89SAndroid Build Coastguard Worker #ifdef SA_INTERRUPT
538*de1e4e89SAndroid Build Coastguard Worker 	sa.sa_flags = SA_INTERRUPT;
539*de1e4e89SAndroid Build Coastguard Worker #endif
540*de1e4e89SAndroid Build Coastguard Worker 	sigaction(sig, &sa, NULL);
541*de1e4e89SAndroid Build Coastguard Worker }
542*de1e4e89SAndroid Build Coastguard Worker 
543*de1e4e89SAndroid Build Coastguard Worker #include <setjmp.h>
544*de1e4e89SAndroid Build Coastguard Worker sigjmp_buf env;
545*de1e4e89SAndroid Build Coastguard Worker volatile int in_poll;
546*de1e4e89SAndroid Build Coastguard Worker 
sig_exit(int signo)547*de1e4e89SAndroid Build Coastguard Worker static void sig_exit(int signo)
548*de1e4e89SAndroid Build Coastguard Worker {
549*de1e4e89SAndroid Build Coastguard Worker 	do_exit = 1;
550*de1e4e89SAndroid Build Coastguard Worker 	if (in_poll)
551*de1e4e89SAndroid Build Coastguard Worker 		siglongjmp(env, 1);
552*de1e4e89SAndroid Build Coastguard Worker }
553*de1e4e89SAndroid Build Coastguard Worker 
sig_sync(int signo)554*de1e4e89SAndroid Build Coastguard Worker static void sig_sync(int signo)
555*de1e4e89SAndroid Build Coastguard Worker {
556*de1e4e89SAndroid Build Coastguard Worker 	do_sync = 1;
557*de1e4e89SAndroid Build Coastguard Worker 	if (in_poll)
558*de1e4e89SAndroid Build Coastguard Worker 		siglongjmp(env, 1);
559*de1e4e89SAndroid Build Coastguard Worker }
560*de1e4e89SAndroid Build Coastguard Worker 
sig_stats(int signo)561*de1e4e89SAndroid Build Coastguard Worker static void sig_stats(int signo)
562*de1e4e89SAndroid Build Coastguard Worker {
563*de1e4e89SAndroid Build Coastguard Worker 	do_sync = 1;
564*de1e4e89SAndroid Build Coastguard Worker 	do_stats = 1;
565*de1e4e89SAndroid Build Coastguard Worker 	if (in_poll)
566*de1e4e89SAndroid Build Coastguard Worker 		siglongjmp(env, 1);
567*de1e4e89SAndroid Build Coastguard Worker }
568*de1e4e89SAndroid Build Coastguard Worker 
send_stats(void)569*de1e4e89SAndroid Build Coastguard Worker static void send_stats(void)
570*de1e4e89SAndroid Build Coastguard Worker {
571*de1e4e89SAndroid Build Coastguard Worker 	syslog(LOG_INFO, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu",
572*de1e4e89SAndroid Build Coastguard Worker 	       stats.arp_new, stats.arp_change,
573*de1e4e89SAndroid Build Coastguard Worker 
574*de1e4e89SAndroid Build Coastguard Worker 	       stats.app_recv, stats.app_success,
575*de1e4e89SAndroid Build Coastguard Worker 	       stats.app_bad, stats.app_neg, stats.app_suppressed
576*de1e4e89SAndroid Build Coastguard Worker 	       );
577*de1e4e89SAndroid Build Coastguard Worker 	syslog(LOG_INFO, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu",
578*de1e4e89SAndroid Build Coastguard Worker 	       stats.kern_new, stats.kern_change, stats.kern_neg,
579*de1e4e89SAndroid Build Coastguard Worker 
580*de1e4e89SAndroid Build Coastguard Worker 	       stats.probes_sent, stats.probes_suppressed
581*de1e4e89SAndroid Build Coastguard Worker 	       );
582*de1e4e89SAndroid Build Coastguard Worker 	do_stats = 0;
583*de1e4e89SAndroid Build Coastguard Worker }
584*de1e4e89SAndroid Build Coastguard Worker 
585*de1e4e89SAndroid Build Coastguard Worker 
main(int argc,char ** argv)586*de1e4e89SAndroid Build Coastguard Worker int main(int argc, char **argv)
587*de1e4e89SAndroid Build Coastguard Worker {
588*de1e4e89SAndroid Build Coastguard Worker 	int opt;
589*de1e4e89SAndroid Build Coastguard Worker 	int do_list = 0;
590*de1e4e89SAndroid Build Coastguard Worker 	char *do_load = NULL;
591*de1e4e89SAndroid Build Coastguard Worker 
592*de1e4e89SAndroid Build Coastguard Worker 	while ((opt = getopt(argc, argv, "h?b:lf:a:n:p:kR:B:")) != EOF) {
593*de1e4e89SAndroid Build Coastguard Worker 		switch (opt) {
594*de1e4e89SAndroid Build Coastguard Worker 		case 'b':
595*de1e4e89SAndroid Build Coastguard Worker 			dbname = optarg;
596*de1e4e89SAndroid Build Coastguard Worker 			break;
597*de1e4e89SAndroid Build Coastguard Worker 		case 'f':
598*de1e4e89SAndroid Build Coastguard Worker 			if (do_load) {
599*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Duplicate option -f\n");
600*de1e4e89SAndroid Build Coastguard Worker 				usage();
601*de1e4e89SAndroid Build Coastguard Worker 			}
602*de1e4e89SAndroid Build Coastguard Worker 			do_load = optarg;
603*de1e4e89SAndroid Build Coastguard Worker 			break;
604*de1e4e89SAndroid Build Coastguard Worker 		case 'l':
605*de1e4e89SAndroid Build Coastguard Worker 			do_list = 1;
606*de1e4e89SAndroid Build Coastguard Worker 			break;
607*de1e4e89SAndroid Build Coastguard Worker 		case 'a':
608*de1e4e89SAndroid Build Coastguard Worker 			active_probing = atoi(optarg);
609*de1e4e89SAndroid Build Coastguard Worker 			break;
610*de1e4e89SAndroid Build Coastguard Worker 		case 'n':
611*de1e4e89SAndroid Build Coastguard Worker 			negative_timeout = atoi(optarg);
612*de1e4e89SAndroid Build Coastguard Worker 			break;
613*de1e4e89SAndroid Build Coastguard Worker 		case 'k':
614*de1e4e89SAndroid Build Coastguard Worker 			no_kernel_broadcasts = 1;
615*de1e4e89SAndroid Build Coastguard Worker 			break;
616*de1e4e89SAndroid Build Coastguard Worker 		case 'p':
617*de1e4e89SAndroid Build Coastguard Worker 			if ((poll_timeout = 1000 * strtod(optarg, NULL)) < 100) {
618*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Invalid poll timeout\n");
619*de1e4e89SAndroid Build Coastguard Worker 				exit(-1);
620*de1e4e89SAndroid Build Coastguard Worker 			}
621*de1e4e89SAndroid Build Coastguard Worker 			break;
622*de1e4e89SAndroid Build Coastguard Worker 		case 'R':
623*de1e4e89SAndroid Build Coastguard Worker 			if ((broadcast_rate = atoi(optarg)) <= 0 ||
624*de1e4e89SAndroid Build Coastguard Worker 			    (broadcast_rate = 1000/broadcast_rate) <= 0) {
625*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Invalid ARP rate\n");
626*de1e4e89SAndroid Build Coastguard Worker 				exit(-1);
627*de1e4e89SAndroid Build Coastguard Worker 			}
628*de1e4e89SAndroid Build Coastguard Worker 			break;
629*de1e4e89SAndroid Build Coastguard Worker 		case 'B':
630*de1e4e89SAndroid Build Coastguard Worker 			if ((broadcast_burst = atoi(optarg)) <= 0 ||
631*de1e4e89SAndroid Build Coastguard Worker 			    (broadcast_burst = 1000*broadcast_burst) <= 0) {
632*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Invalid ARP burst\n");
633*de1e4e89SAndroid Build Coastguard Worker 				exit(-1);
634*de1e4e89SAndroid Build Coastguard Worker 			}
635*de1e4e89SAndroid Build Coastguard Worker 			break;
636*de1e4e89SAndroid Build Coastguard Worker 		case 'h':
637*de1e4e89SAndroid Build Coastguard Worker 		case '?':
638*de1e4e89SAndroid Build Coastguard Worker 		default:
639*de1e4e89SAndroid Build Coastguard Worker 			usage();
640*de1e4e89SAndroid Build Coastguard Worker 		}
641*de1e4e89SAndroid Build Coastguard Worker 	}
642*de1e4e89SAndroid Build Coastguard Worker 	argc -= optind;
643*de1e4e89SAndroid Build Coastguard Worker 	argv += optind;
644*de1e4e89SAndroid Build Coastguard Worker 
645*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 0) {
646*de1e4e89SAndroid Build Coastguard Worker 		ifnum = argc;
647*de1e4e89SAndroid Build Coastguard Worker 		ifnames = argv;
648*de1e4e89SAndroid Build Coastguard Worker 		ifvec = malloc(argc*sizeof(int));
649*de1e4e89SAndroid Build Coastguard Worker 		if (!ifvec) {
650*de1e4e89SAndroid Build Coastguard Worker 			perror("malloc");
651*de1e4e89SAndroid Build Coastguard Worker 			exit(-1);
652*de1e4e89SAndroid Build Coastguard Worker 		}
653*de1e4e89SAndroid Build Coastguard Worker 	}
654*de1e4e89SAndroid Build Coastguard Worker 
655*de1e4e89SAndroid Build Coastguard Worker 	if ((udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
656*de1e4e89SAndroid Build Coastguard Worker 		perror("socket");
657*de1e4e89SAndroid Build Coastguard Worker 		exit(-1);
658*de1e4e89SAndroid Build Coastguard Worker 	}
659*de1e4e89SAndroid Build Coastguard Worker 
660*de1e4e89SAndroid Build Coastguard Worker 	if (ifnum) {
661*de1e4e89SAndroid Build Coastguard Worker 		int i;
662*de1e4e89SAndroid Build Coastguard Worker 		struct ifreq ifr = {};
663*de1e4e89SAndroid Build Coastguard Worker 
664*de1e4e89SAndroid Build Coastguard Worker 		for (i = 0; i < ifnum; i++) {
665*de1e4e89SAndroid Build Coastguard Worker 			if (get_ifname(ifr.ifr_name, ifnames[i]))
666*de1e4e89SAndroid Build Coastguard Worker 				invarg("not a valid ifname", ifnames[i]);
667*de1e4e89SAndroid Build Coastguard Worker 			if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) {
668*de1e4e89SAndroid Build Coastguard Worker 				perror("ioctl(SIOCGIFINDEX)");
669*de1e4e89SAndroid Build Coastguard Worker 				exit(-1);
670*de1e4e89SAndroid Build Coastguard Worker 			}
671*de1e4e89SAndroid Build Coastguard Worker 			ifvec[i] = ifr.ifr_ifindex;
672*de1e4e89SAndroid Build Coastguard Worker 		}
673*de1e4e89SAndroid Build Coastguard Worker 	}
674*de1e4e89SAndroid Build Coastguard Worker 
675*de1e4e89SAndroid Build Coastguard Worker 	dbase = dbopen(dbname, O_CREAT|O_RDWR, 0644, DB_HASH, NULL);
676*de1e4e89SAndroid Build Coastguard Worker 	if (dbase == NULL) {
677*de1e4e89SAndroid Build Coastguard Worker 		perror("db_open");
678*de1e4e89SAndroid Build Coastguard Worker 		exit(-1);
679*de1e4e89SAndroid Build Coastguard Worker 	}
680*de1e4e89SAndroid Build Coastguard Worker 
681*de1e4e89SAndroid Build Coastguard Worker 	if (do_load) {
682*de1e4e89SAndroid Build Coastguard Worker 		char buf[128];
683*de1e4e89SAndroid Build Coastguard Worker 		FILE *fp;
684*de1e4e89SAndroid Build Coastguard Worker 		struct dbkey k;
685*de1e4e89SAndroid Build Coastguard Worker 		DBT dbkey, dbdat;
686*de1e4e89SAndroid Build Coastguard Worker 
687*de1e4e89SAndroid Build Coastguard Worker 		dbkey.data = &k;
688*de1e4e89SAndroid Build Coastguard Worker 		dbkey.size = sizeof(k);
689*de1e4e89SAndroid Build Coastguard Worker 
690*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(do_load, "-") == 0 || strcmp(do_load, "--") == 0) {
691*de1e4e89SAndroid Build Coastguard Worker 			fp = stdin;
692*de1e4e89SAndroid Build Coastguard Worker 		} else if ((fp = fopen(do_load, "r")) == NULL) {
693*de1e4e89SAndroid Build Coastguard Worker 			perror("fopen");
694*de1e4e89SAndroid Build Coastguard Worker 			goto do_abort;
695*de1e4e89SAndroid Build Coastguard Worker 		}
696*de1e4e89SAndroid Build Coastguard Worker 
697*de1e4e89SAndroid Build Coastguard Worker 		buf[sizeof(buf)-1] = 0;
698*de1e4e89SAndroid Build Coastguard Worker 		while (fgets(buf, sizeof(buf), fp)) {
699*de1e4e89SAndroid Build Coastguard Worker 			__u8 b1[6];
700*de1e4e89SAndroid Build Coastguard Worker 			char ipbuf[128];
701*de1e4e89SAndroid Build Coastguard Worker 			char macbuf[128];
702*de1e4e89SAndroid Build Coastguard Worker 
703*de1e4e89SAndroid Build Coastguard Worker 			if (buf[0] == '#')
704*de1e4e89SAndroid Build Coastguard Worker 				continue;
705*de1e4e89SAndroid Build Coastguard Worker 
706*de1e4e89SAndroid Build Coastguard Worker 			if (sscanf(buf, "%u%s%s", &k.iface, ipbuf, macbuf) != 3) {
707*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Wrong format of input file \"%s\"\n", do_load);
708*de1e4e89SAndroid Build Coastguard Worker 				goto do_abort;
709*de1e4e89SAndroid Build Coastguard Worker 			}
710*de1e4e89SAndroid Build Coastguard Worker 			if (strncmp(macbuf, "FAILED:", 7) == 0)
711*de1e4e89SAndroid Build Coastguard Worker 				continue;
712*de1e4e89SAndroid Build Coastguard Worker 			if (!inet_aton(ipbuf, (struct in_addr *)&k.addr)) {
713*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Invalid IP address: \"%s\"\n", ipbuf);
714*de1e4e89SAndroid Build Coastguard Worker 				goto do_abort;
715*de1e4e89SAndroid Build Coastguard Worker 			}
716*de1e4e89SAndroid Build Coastguard Worker 
717*de1e4e89SAndroid Build Coastguard Worker 			if (ll_addr_a2n((char *) b1, 6, macbuf) != 6)
718*de1e4e89SAndroid Build Coastguard Worker 				goto do_abort;
719*de1e4e89SAndroid Build Coastguard Worker 			dbdat.size = 6;
720*de1e4e89SAndroid Build Coastguard Worker 
721*de1e4e89SAndroid Build Coastguard Worker 			if (dbase->put(dbase, &dbkey, &dbdat, 0)) {
722*de1e4e89SAndroid Build Coastguard Worker 				perror("hash->put");
723*de1e4e89SAndroid Build Coastguard Worker 				goto do_abort;
724*de1e4e89SAndroid Build Coastguard Worker 			}
725*de1e4e89SAndroid Build Coastguard Worker 		}
726*de1e4e89SAndroid Build Coastguard Worker 		dbase->sync(dbase, 0);
727*de1e4e89SAndroid Build Coastguard Worker 		if (fp != stdin)
728*de1e4e89SAndroid Build Coastguard Worker 			fclose(fp);
729*de1e4e89SAndroid Build Coastguard Worker 	}
730*de1e4e89SAndroid Build Coastguard Worker 
731*de1e4e89SAndroid Build Coastguard Worker 	if (do_list) {
732*de1e4e89SAndroid Build Coastguard Worker 		DBT dbkey, dbdat;
733*de1e4e89SAndroid Build Coastguard Worker 
734*de1e4e89SAndroid Build Coastguard Worker 		printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
735*de1e4e89SAndroid Build Coastguard Worker 		while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
736*de1e4e89SAndroid Build Coastguard Worker 			struct dbkey *key = dbkey.data;
737*de1e4e89SAndroid Build Coastguard Worker 
738*de1e4e89SAndroid Build Coastguard Worker 			if (handle_if(key->iface)) {
739*de1e4e89SAndroid Build Coastguard Worker 				if (!IS_NEG(dbdat.data)) {
740*de1e4e89SAndroid Build Coastguard Worker 					char b1[18];
741*de1e4e89SAndroid Build Coastguard Worker 
742*de1e4e89SAndroid Build Coastguard Worker 					printf("%-8d %-15s %s\n",
743*de1e4e89SAndroid Build Coastguard Worker 					       key->iface,
744*de1e4e89SAndroid Build Coastguard Worker 					       inet_ntoa(*(struct in_addr *)&key->addr),
745*de1e4e89SAndroid Build Coastguard Worker 					       ll_addr_n2a(dbdat.data, 6, ARPHRD_ETHER, b1, 18));
746*de1e4e89SAndroid Build Coastguard Worker 				} else {
747*de1e4e89SAndroid Build Coastguard Worker 					printf("%-8d %-15s FAILED: %dsec ago\n",
748*de1e4e89SAndroid Build Coastguard Worker 					       key->iface,
749*de1e4e89SAndroid Build Coastguard Worker 					       inet_ntoa(*(struct in_addr *)&key->addr),
750*de1e4e89SAndroid Build Coastguard Worker 					       NEG_AGE(dbdat.data));
751*de1e4e89SAndroid Build Coastguard Worker 				}
752*de1e4e89SAndroid Build Coastguard Worker 			}
753*de1e4e89SAndroid Build Coastguard Worker 		}
754*de1e4e89SAndroid Build Coastguard Worker 	}
755*de1e4e89SAndroid Build Coastguard Worker 
756*de1e4e89SAndroid Build Coastguard Worker 	if (do_load || do_list)
757*de1e4e89SAndroid Build Coastguard Worker 		goto out;
758*de1e4e89SAndroid Build Coastguard Worker 
759*de1e4e89SAndroid Build Coastguard Worker 	pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
760*de1e4e89SAndroid Build Coastguard Worker 	if (pset[0].fd < 0) {
761*de1e4e89SAndroid Build Coastguard Worker 		perror("socket");
762*de1e4e89SAndroid Build Coastguard Worker 		exit(-1);
763*de1e4e89SAndroid Build Coastguard Worker 	}
764*de1e4e89SAndroid Build Coastguard Worker 
765*de1e4e89SAndroid Build Coastguard Worker 	if (1) {
766*de1e4e89SAndroid Build Coastguard Worker 		struct sockaddr_ll sll = {
767*de1e4e89SAndroid Build Coastguard Worker 			.sll_family = AF_PACKET,
768*de1e4e89SAndroid Build Coastguard Worker 			.sll_protocol = htons(ETH_P_ARP),
769*de1e4e89SAndroid Build Coastguard Worker 			.sll_ifindex = (ifnum == 1 ? ifvec[0] : 0),
770*de1e4e89SAndroid Build Coastguard Worker 		};
771*de1e4e89SAndroid Build Coastguard Worker 
772*de1e4e89SAndroid Build Coastguard Worker 		if (bind(pset[0].fd, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
773*de1e4e89SAndroid Build Coastguard Worker 			perror("bind");
774*de1e4e89SAndroid Build Coastguard Worker 			goto do_abort;
775*de1e4e89SAndroid Build Coastguard Worker 		}
776*de1e4e89SAndroid Build Coastguard Worker 	}
777*de1e4e89SAndroid Build Coastguard Worker 
778*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_open(&rth, RTMGRP_NEIGH) < 0) {
779*de1e4e89SAndroid Build Coastguard Worker 		perror("rtnl_open");
780*de1e4e89SAndroid Build Coastguard Worker 		goto do_abort;
781*de1e4e89SAndroid Build Coastguard Worker 	}
782*de1e4e89SAndroid Build Coastguard Worker 	pset[1].fd = rth.fd;
783*de1e4e89SAndroid Build Coastguard Worker 
784*de1e4e89SAndroid Build Coastguard Worker 	load_initial_table();
785*de1e4e89SAndroid Build Coastguard Worker 
786*de1e4e89SAndroid Build Coastguard Worker 	if (daemon(0, 0)) {
787*de1e4e89SAndroid Build Coastguard Worker 		perror("arpd: daemon");
788*de1e4e89SAndroid Build Coastguard Worker 		goto do_abort;
789*de1e4e89SAndroid Build Coastguard Worker 	}
790*de1e4e89SAndroid Build Coastguard Worker 
791*de1e4e89SAndroid Build Coastguard Worker 	openlog("arpd", LOG_PID | LOG_CONS, LOG_DAEMON);
792*de1e4e89SAndroid Build Coastguard Worker 	catch_signal(SIGINT, sig_exit);
793*de1e4e89SAndroid Build Coastguard Worker 	catch_signal(SIGTERM, sig_exit);
794*de1e4e89SAndroid Build Coastguard Worker 	catch_signal(SIGHUP, sig_sync);
795*de1e4e89SAndroid Build Coastguard Worker 	catch_signal(SIGUSR1, sig_stats);
796*de1e4e89SAndroid Build Coastguard Worker 
797*de1e4e89SAndroid Build Coastguard Worker #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
798*de1e4e89SAndroid Build Coastguard Worker 	pset[0].events = EVENTS;
799*de1e4e89SAndroid Build Coastguard Worker 	pset[0].revents = 0;
800*de1e4e89SAndroid Build Coastguard Worker 	pset[1].events = EVENTS;
801*de1e4e89SAndroid Build Coastguard Worker 	pset[1].revents = 0;
802*de1e4e89SAndroid Build Coastguard Worker 
803*de1e4e89SAndroid Build Coastguard Worker 	sigsetjmp(env, 1);
804*de1e4e89SAndroid Build Coastguard Worker 
805*de1e4e89SAndroid Build Coastguard Worker 	for (;;) {
806*de1e4e89SAndroid Build Coastguard Worker 		in_poll = 1;
807*de1e4e89SAndroid Build Coastguard Worker 
808*de1e4e89SAndroid Build Coastguard Worker 		if (do_exit)
809*de1e4e89SAndroid Build Coastguard Worker 			break;
810*de1e4e89SAndroid Build Coastguard Worker 		if (do_sync) {
811*de1e4e89SAndroid Build Coastguard Worker 			in_poll = 0;
812*de1e4e89SAndroid Build Coastguard Worker 			dbase->sync(dbase, 0);
813*de1e4e89SAndroid Build Coastguard Worker 			do_sync = 0;
814*de1e4e89SAndroid Build Coastguard Worker 			in_poll = 1;
815*de1e4e89SAndroid Build Coastguard Worker 		}
816*de1e4e89SAndroid Build Coastguard Worker 		if (do_stats)
817*de1e4e89SAndroid Build Coastguard Worker 			send_stats();
818*de1e4e89SAndroid Build Coastguard Worker 		if (poll(pset, 2, poll_timeout) > 0) {
819*de1e4e89SAndroid Build Coastguard Worker 			in_poll = 0;
820*de1e4e89SAndroid Build Coastguard Worker 			if (pset[0].revents&EVENTS)
821*de1e4e89SAndroid Build Coastguard Worker 				get_arp_pkt();
822*de1e4e89SAndroid Build Coastguard Worker 			if (pset[1].revents&EVENTS)
823*de1e4e89SAndroid Build Coastguard Worker 				get_kern_msg();
824*de1e4e89SAndroid Build Coastguard Worker 		} else {
825*de1e4e89SAndroid Build Coastguard Worker 			do_sync = 1;
826*de1e4e89SAndroid Build Coastguard Worker 		}
827*de1e4e89SAndroid Build Coastguard Worker 	}
828*de1e4e89SAndroid Build Coastguard Worker 
829*de1e4e89SAndroid Build Coastguard Worker 	undo_sysctl_adjustments();
830*de1e4e89SAndroid Build Coastguard Worker out:
831*de1e4e89SAndroid Build Coastguard Worker 	dbase->close(dbase);
832*de1e4e89SAndroid Build Coastguard Worker 	exit(0);
833*de1e4e89SAndroid Build Coastguard Worker 
834*de1e4e89SAndroid Build Coastguard Worker do_abort:
835*de1e4e89SAndroid Build Coastguard Worker 	dbase->close(dbase);
836*de1e4e89SAndroid Build Coastguard Worker 	exit(-1);
837*de1e4e89SAndroid Build Coastguard Worker }
838