xref: /aosp_15_r20/external/iputils/rarpd.c (revision bd1f8aeb6080fa6544ec30aeca3eb4da100f359f)
1*bd1f8aebSAndroid Build Coastguard Worker /*
2*bd1f8aebSAndroid Build Coastguard Worker  * rarpd.c	RARP daemon.
3*bd1f8aebSAndroid Build Coastguard Worker  *
4*bd1f8aebSAndroid Build Coastguard Worker  *		This program is free software; you can redistribute it and/or
5*bd1f8aebSAndroid Build Coastguard Worker  *		modify it under the terms of the GNU General Public License
6*bd1f8aebSAndroid Build Coastguard Worker  *		as published by the Free Software Foundation; either version
7*bd1f8aebSAndroid Build Coastguard Worker  *		2 of the License, or (at your option) any later version.
8*bd1f8aebSAndroid Build Coastguard Worker  *
9*bd1f8aebSAndroid Build Coastguard Worker  * Authors:	Alexey Kuznetsov, <[email protected]>
10*bd1f8aebSAndroid Build Coastguard Worker  */
11*bd1f8aebSAndroid Build Coastguard Worker 
12*bd1f8aebSAndroid Build Coastguard Worker #include <stdio.h>
13*bd1f8aebSAndroid Build Coastguard Worker #include <syslog.h>
14*bd1f8aebSAndroid Build Coastguard Worker #include <dirent.h>
15*bd1f8aebSAndroid Build Coastguard Worker #include <malloc.h>
16*bd1f8aebSAndroid Build Coastguard Worker #include <string.h>
17*bd1f8aebSAndroid Build Coastguard Worker #include <unistd.h>
18*bd1f8aebSAndroid Build Coastguard Worker #include <stdlib.h>
19*bd1f8aebSAndroid Build Coastguard Worker #include <netdb.h>
20*bd1f8aebSAndroid Build Coastguard Worker #include <arpa/inet.h>
21*bd1f8aebSAndroid Build Coastguard Worker #include <sys/ioctl.h>
22*bd1f8aebSAndroid Build Coastguard Worker #include <sys/poll.h>
23*bd1f8aebSAndroid Build Coastguard Worker #include <sys/errno.h>
24*bd1f8aebSAndroid Build Coastguard Worker #include <sys/fcntl.h>
25*bd1f8aebSAndroid Build Coastguard Worker #include <sys/socket.h>
26*bd1f8aebSAndroid Build Coastguard Worker #include <sys/signal.h>
27*bd1f8aebSAndroid Build Coastguard Worker #include <linux/if.h>
28*bd1f8aebSAndroid Build Coastguard Worker #include <linux/if_arp.h>
29*bd1f8aebSAndroid Build Coastguard Worker #include <netinet/in.h>
30*bd1f8aebSAndroid Build Coastguard Worker #include <linux/if_packet.h>
31*bd1f8aebSAndroid Build Coastguard Worker #include <linux/filter.h>
32*bd1f8aebSAndroid Build Coastguard Worker 
33*bd1f8aebSAndroid Build Coastguard Worker int do_reload = 1;
34*bd1f8aebSAndroid Build Coastguard Worker 
35*bd1f8aebSAndroid Build Coastguard Worker int debug;
36*bd1f8aebSAndroid Build Coastguard Worker int verbose;
37*bd1f8aebSAndroid Build Coastguard Worker int ifidx;
38*bd1f8aebSAndroid Build Coastguard Worker int allow_offlink;
39*bd1f8aebSAndroid Build Coastguard Worker int only_ethers;
40*bd1f8aebSAndroid Build Coastguard Worker int all_ifaces;
41*bd1f8aebSAndroid Build Coastguard Worker int listen_arp;
42*bd1f8aebSAndroid Build Coastguard Worker char *ifname;
43*bd1f8aebSAndroid Build Coastguard Worker char *tftp_dir = "/etc/tftpboot";
44*bd1f8aebSAndroid Build Coastguard Worker 
45*bd1f8aebSAndroid Build Coastguard Worker extern int ether_ntohost(char *name, unsigned char *ea);
46*bd1f8aebSAndroid Build Coastguard Worker void usage(void) __attribute__((noreturn));
47*bd1f8aebSAndroid Build Coastguard Worker 
48*bd1f8aebSAndroid Build Coastguard Worker struct iflink
49*bd1f8aebSAndroid Build Coastguard Worker {
50*bd1f8aebSAndroid Build Coastguard Worker 	struct iflink	*next;
51*bd1f8aebSAndroid Build Coastguard Worker 	int	       	index;
52*bd1f8aebSAndroid Build Coastguard Worker 	int		hatype;
53*bd1f8aebSAndroid Build Coastguard Worker 	unsigned char	lladdr[16];
54*bd1f8aebSAndroid Build Coastguard Worker 	char		name[IFNAMSIZ];
55*bd1f8aebSAndroid Build Coastguard Worker 	struct ifaddr 	*ifa_list;
56*bd1f8aebSAndroid Build Coastguard Worker } *ifl_list;
57*bd1f8aebSAndroid Build Coastguard Worker 
58*bd1f8aebSAndroid Build Coastguard Worker struct ifaddr
59*bd1f8aebSAndroid Build Coastguard Worker {
60*bd1f8aebSAndroid Build Coastguard Worker 	struct ifaddr 	*next;
61*bd1f8aebSAndroid Build Coastguard Worker 	__u32		prefix;
62*bd1f8aebSAndroid Build Coastguard Worker 	__u32		mask;
63*bd1f8aebSAndroid Build Coastguard Worker 	__u32		local;
64*bd1f8aebSAndroid Build Coastguard Worker };
65*bd1f8aebSAndroid Build Coastguard Worker 
66*bd1f8aebSAndroid Build Coastguard Worker struct rarp_map
67*bd1f8aebSAndroid Build Coastguard Worker {
68*bd1f8aebSAndroid Build Coastguard Worker 	struct rarp_map *next;
69*bd1f8aebSAndroid Build Coastguard Worker 
70*bd1f8aebSAndroid Build Coastguard Worker 	int		ifindex;
71*bd1f8aebSAndroid Build Coastguard Worker 	int		arp_type;
72*bd1f8aebSAndroid Build Coastguard Worker 	int		lladdr_len;
73*bd1f8aebSAndroid Build Coastguard Worker 	unsigned char	lladdr[16];
74*bd1f8aebSAndroid Build Coastguard Worker 	__u32		ipaddr;
75*bd1f8aebSAndroid Build Coastguard Worker } *rarp_db;
76*bd1f8aebSAndroid Build Coastguard Worker 
usage()77*bd1f8aebSAndroid Build Coastguard Worker void usage()
78*bd1f8aebSAndroid Build Coastguard Worker {
79*bd1f8aebSAndroid Build Coastguard Worker 	fprintf(stderr, "Usage: rarpd [ -dveaA ] [ -b tftpdir ] [ interface]\n");
80*bd1f8aebSAndroid Build Coastguard Worker 	exit(1);
81*bd1f8aebSAndroid Build Coastguard Worker }
82*bd1f8aebSAndroid Build Coastguard Worker 
load_db(void)83*bd1f8aebSAndroid Build Coastguard Worker void load_db(void)
84*bd1f8aebSAndroid Build Coastguard Worker {
85*bd1f8aebSAndroid Build Coastguard Worker }
86*bd1f8aebSAndroid Build Coastguard Worker 
load_if(void)87*bd1f8aebSAndroid Build Coastguard Worker void load_if(void)
88*bd1f8aebSAndroid Build Coastguard Worker {
89*bd1f8aebSAndroid Build Coastguard Worker 	int fd;
90*bd1f8aebSAndroid Build Coastguard Worker 	struct ifreq *ifrp, *ifend;
91*bd1f8aebSAndroid Build Coastguard Worker 	struct iflink *ifl;
92*bd1f8aebSAndroid Build Coastguard Worker 	struct ifaddr *ifa;
93*bd1f8aebSAndroid Build Coastguard Worker 	struct ifconf ifc;
94*bd1f8aebSAndroid Build Coastguard Worker 	struct ifreq ibuf[256];
95*bd1f8aebSAndroid Build Coastguard Worker 
96*bd1f8aebSAndroid Build Coastguard Worker 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
97*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "socket: %m");
98*bd1f8aebSAndroid Build Coastguard Worker 		return;
99*bd1f8aebSAndroid Build Coastguard Worker 	}
100*bd1f8aebSAndroid Build Coastguard Worker 
101*bd1f8aebSAndroid Build Coastguard Worker 	ifc.ifc_len = sizeof ibuf;
102*bd1f8aebSAndroid Build Coastguard Worker 	ifc.ifc_buf = (caddr_t)ibuf;
103*bd1f8aebSAndroid Build Coastguard Worker 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
104*bd1f8aebSAndroid Build Coastguard Worker 	    ifc.ifc_len < (int)sizeof(struct ifreq)) {
105*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "SIOCGIFCONF: %m");
106*bd1f8aebSAndroid Build Coastguard Worker 		close(fd);
107*bd1f8aebSAndroid Build Coastguard Worker 		return;
108*bd1f8aebSAndroid Build Coastguard Worker 	}
109*bd1f8aebSAndroid Build Coastguard Worker 
110*bd1f8aebSAndroid Build Coastguard Worker 	while ((ifl = ifl_list) != NULL) {
111*bd1f8aebSAndroid Build Coastguard Worker 		while ((ifa = ifl->ifa_list) != NULL) {
112*bd1f8aebSAndroid Build Coastguard Worker 			ifl->ifa_list = ifa->next;
113*bd1f8aebSAndroid Build Coastguard Worker 			free(ifa);
114*bd1f8aebSAndroid Build Coastguard Worker 		}
115*bd1f8aebSAndroid Build Coastguard Worker 		ifl_list = ifl->next;
116*bd1f8aebSAndroid Build Coastguard Worker 		free(ifl);
117*bd1f8aebSAndroid Build Coastguard Worker 	}
118*bd1f8aebSAndroid Build Coastguard Worker 
119*bd1f8aebSAndroid Build Coastguard Worker 	ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
120*bd1f8aebSAndroid Build Coastguard Worker 	for (ifrp = ibuf; ifrp < ifend; ifrp++) {
121*bd1f8aebSAndroid Build Coastguard Worker 		__u32 addr;
122*bd1f8aebSAndroid Build Coastguard Worker 		__u32 mask;
123*bd1f8aebSAndroid Build Coastguard Worker 		__u32 prefix;
124*bd1f8aebSAndroid Build Coastguard Worker 
125*bd1f8aebSAndroid Build Coastguard Worker 		if (ifrp->ifr_addr.sa_family != AF_INET)
126*bd1f8aebSAndroid Build Coastguard Worker 			continue;
127*bd1f8aebSAndroid Build Coastguard Worker 		addr = ((struct sockaddr_in*)&ifrp->ifr_addr)->sin_addr.s_addr;
128*bd1f8aebSAndroid Build Coastguard Worker 		if (addr == 0)
129*bd1f8aebSAndroid Build Coastguard Worker 			continue;
130*bd1f8aebSAndroid Build Coastguard Worker 		if (ioctl(fd, SIOCGIFINDEX, ifrp)) {
131*bd1f8aebSAndroid Build Coastguard Worker 			syslog(LOG_ERR, "ioctl(SIOCGIFNAME): %m");
132*bd1f8aebSAndroid Build Coastguard Worker 			continue;
133*bd1f8aebSAndroid Build Coastguard Worker 		}
134*bd1f8aebSAndroid Build Coastguard Worker 		if (ifidx && ifrp->ifr_ifindex != ifidx)
135*bd1f8aebSAndroid Build Coastguard Worker 			continue;
136*bd1f8aebSAndroid Build Coastguard Worker 		for (ifl = ifl_list; ifl; ifl = ifl->next)
137*bd1f8aebSAndroid Build Coastguard Worker 			if (ifl->index == ifrp->ifr_ifindex)
138*bd1f8aebSAndroid Build Coastguard Worker 				break;
139*bd1f8aebSAndroid Build Coastguard Worker 		if (ifl == NULL) {
140*bd1f8aebSAndroid Build Coastguard Worker 			char *p;
141*bd1f8aebSAndroid Build Coastguard Worker 			int index = ifrp->ifr_ifindex;
142*bd1f8aebSAndroid Build Coastguard Worker 
143*bd1f8aebSAndroid Build Coastguard Worker 			if (ioctl(fd, SIOCGIFHWADDR, ifrp)) {
144*bd1f8aebSAndroid Build Coastguard Worker 				syslog(LOG_ERR, "ioctl(SIOCGIFHWADDR): %m");
145*bd1f8aebSAndroid Build Coastguard Worker 				continue;
146*bd1f8aebSAndroid Build Coastguard Worker 			}
147*bd1f8aebSAndroid Build Coastguard Worker 
148*bd1f8aebSAndroid Build Coastguard Worker 			ifl = (struct iflink*)malloc(sizeof(*ifl));
149*bd1f8aebSAndroid Build Coastguard Worker 			if (ifl == NULL)
150*bd1f8aebSAndroid Build Coastguard Worker 				continue;
151*bd1f8aebSAndroid Build Coastguard Worker 			memset(ifl, 0, sizeof(*ifl));
152*bd1f8aebSAndroid Build Coastguard Worker 			ifl->next = ifl_list;
153*bd1f8aebSAndroid Build Coastguard Worker 			ifl_list = ifl;
154*bd1f8aebSAndroid Build Coastguard Worker 			ifl->index = index;
155*bd1f8aebSAndroid Build Coastguard Worker 			ifl->hatype = ifrp->ifr_hwaddr.sa_family;
156*bd1f8aebSAndroid Build Coastguard Worker 			memcpy(ifl->lladdr, ifrp->ifr_hwaddr.sa_data, 14);
157*bd1f8aebSAndroid Build Coastguard Worker 			strncpy(ifl->name, ifrp->ifr_name, IFNAMSIZ);
158*bd1f8aebSAndroid Build Coastguard Worker 			p = strchr(ifl->name, ':');
159*bd1f8aebSAndroid Build Coastguard Worker 			if (p)
160*bd1f8aebSAndroid Build Coastguard Worker 				*p = 0;
161*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose)
162*bd1f8aebSAndroid Build Coastguard Worker 				syslog(LOG_INFO, "link %s", ifl->name);
163*bd1f8aebSAndroid Build Coastguard Worker 		}
164*bd1f8aebSAndroid Build Coastguard Worker 		if (ioctl(fd, SIOCGIFNETMASK, ifrp)) {
165*bd1f8aebSAndroid Build Coastguard Worker 			syslog(LOG_ERR, "ioctl(SIOCGIFMASK): %m");
166*bd1f8aebSAndroid Build Coastguard Worker 			continue;
167*bd1f8aebSAndroid Build Coastguard Worker 		}
168*bd1f8aebSAndroid Build Coastguard Worker 		mask = ((struct sockaddr_in*)&ifrp->ifr_netmask)->sin_addr.s_addr;
169*bd1f8aebSAndroid Build Coastguard Worker 		if (ioctl(fd, SIOCGIFDSTADDR, ifrp)) {
170*bd1f8aebSAndroid Build Coastguard Worker 			syslog(LOG_ERR, "ioctl(SIOCGIFDSTADDR): %m");
171*bd1f8aebSAndroid Build Coastguard Worker 			continue;
172*bd1f8aebSAndroid Build Coastguard Worker 		}
173*bd1f8aebSAndroid Build Coastguard Worker 		prefix = ((struct sockaddr_in*)&ifrp->ifr_dstaddr)->sin_addr.s_addr;
174*bd1f8aebSAndroid Build Coastguard Worker 		for (ifa = ifl->ifa_list; ifa; ifa = ifa->next) {
175*bd1f8aebSAndroid Build Coastguard Worker 			if (ifa->local == addr &&
176*bd1f8aebSAndroid Build Coastguard Worker 			    ifa->prefix == prefix &&
177*bd1f8aebSAndroid Build Coastguard Worker 			    ifa->mask == mask)
178*bd1f8aebSAndroid Build Coastguard Worker 				break;
179*bd1f8aebSAndroid Build Coastguard Worker 		}
180*bd1f8aebSAndroid Build Coastguard Worker 		if (ifa == NULL) {
181*bd1f8aebSAndroid Build Coastguard Worker 			if (mask == 0 || prefix == 0)
182*bd1f8aebSAndroid Build Coastguard Worker 				continue;
183*bd1f8aebSAndroid Build Coastguard Worker 			ifa = (struct ifaddr*)malloc(sizeof(*ifa));
184*bd1f8aebSAndroid Build Coastguard Worker 			memset(ifa, 0, sizeof(*ifa));
185*bd1f8aebSAndroid Build Coastguard Worker 			ifa->local = addr;
186*bd1f8aebSAndroid Build Coastguard Worker 			ifa->prefix = prefix;
187*bd1f8aebSAndroid Build Coastguard Worker 			ifa->mask = mask;
188*bd1f8aebSAndroid Build Coastguard Worker 			ifa->next = ifl->ifa_list;
189*bd1f8aebSAndroid Build Coastguard Worker 			ifl->ifa_list = ifa;
190*bd1f8aebSAndroid Build Coastguard Worker 
191*bd1f8aebSAndroid Build Coastguard Worker 			if (verbose) {
192*bd1f8aebSAndroid Build Coastguard Worker 				int i;
193*bd1f8aebSAndroid Build Coastguard Worker 				__u32 m = ~0U;
194*bd1f8aebSAndroid Build Coastguard Worker 				for (i=32; i>=0; i--) {
195*bd1f8aebSAndroid Build Coastguard Worker 					if (htonl(m) == mask)
196*bd1f8aebSAndroid Build Coastguard Worker 						break;
197*bd1f8aebSAndroid Build Coastguard Worker 					m <<= 1;
198*bd1f8aebSAndroid Build Coastguard Worker 				}
199*bd1f8aebSAndroid Build Coastguard Worker 				if (addr == prefix) {
200*bd1f8aebSAndroid Build Coastguard Worker 					syslog(LOG_INFO, "  addr %s/%d on %s\n",
201*bd1f8aebSAndroid Build Coastguard Worker 					       inet_ntoa(*(struct in_addr*)&addr), i, ifl->name);
202*bd1f8aebSAndroid Build Coastguard Worker 				} else {
203*bd1f8aebSAndroid Build Coastguard Worker 					char tmpa[64];
204*bd1f8aebSAndroid Build Coastguard Worker 					sprintf(tmpa, "%s", inet_ntoa(*(struct in_addr*)&addr));
205*bd1f8aebSAndroid Build Coastguard Worker 					syslog(LOG_INFO, "  addr %s %s/%d on %s\n", tmpa,
206*bd1f8aebSAndroid Build Coastguard Worker 					       inet_ntoa(*(struct in_addr*)&prefix), i, ifl->name);
207*bd1f8aebSAndroid Build Coastguard Worker 				}
208*bd1f8aebSAndroid Build Coastguard Worker 			}
209*bd1f8aebSAndroid Build Coastguard Worker 		}
210*bd1f8aebSAndroid Build Coastguard Worker 	}
211*bd1f8aebSAndroid Build Coastguard Worker }
212*bd1f8aebSAndroid Build Coastguard Worker 
configure(void)213*bd1f8aebSAndroid Build Coastguard Worker void configure(void)
214*bd1f8aebSAndroid Build Coastguard Worker {
215*bd1f8aebSAndroid Build Coastguard Worker 	load_if();
216*bd1f8aebSAndroid Build Coastguard Worker 	load_db();
217*bd1f8aebSAndroid Build Coastguard Worker }
218*bd1f8aebSAndroid Build Coastguard Worker 
bootable(__u32 addr)219*bd1f8aebSAndroid Build Coastguard Worker int bootable(__u32 addr)
220*bd1f8aebSAndroid Build Coastguard Worker {
221*bd1f8aebSAndroid Build Coastguard Worker 	struct dirent *dent;
222*bd1f8aebSAndroid Build Coastguard Worker 	DIR *d;
223*bd1f8aebSAndroid Build Coastguard Worker 	char name[9];
224*bd1f8aebSAndroid Build Coastguard Worker 
225*bd1f8aebSAndroid Build Coastguard Worker 	sprintf(name, "%08X", (__u32)ntohl(addr));
226*bd1f8aebSAndroid Build Coastguard Worker 	d = opendir(tftp_dir);
227*bd1f8aebSAndroid Build Coastguard Worker 	if (d == NULL) {
228*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "opendir: %m");
229*bd1f8aebSAndroid Build Coastguard Worker 		return 0;
230*bd1f8aebSAndroid Build Coastguard Worker 	}
231*bd1f8aebSAndroid Build Coastguard Worker 	while ((dent = readdir(d)) != NULL) {
232*bd1f8aebSAndroid Build Coastguard Worker 		if (strncmp(dent->d_name, name, 8) == 0)
233*bd1f8aebSAndroid Build Coastguard Worker 			break;
234*bd1f8aebSAndroid Build Coastguard Worker 	}
235*bd1f8aebSAndroid Build Coastguard Worker 	closedir(d);
236*bd1f8aebSAndroid Build Coastguard Worker 	return dent != NULL;
237*bd1f8aebSAndroid Build Coastguard Worker }
238*bd1f8aebSAndroid Build Coastguard Worker 
select_ipaddr(int ifindex,__u32 * sel_addr,__u32 ** alist)239*bd1f8aebSAndroid Build Coastguard Worker struct ifaddr *select_ipaddr(int ifindex, __u32 *sel_addr, __u32 **alist)
240*bd1f8aebSAndroid Build Coastguard Worker {
241*bd1f8aebSAndroid Build Coastguard Worker 	struct iflink *ifl;
242*bd1f8aebSAndroid Build Coastguard Worker 	struct ifaddr *ifa;
243*bd1f8aebSAndroid Build Coastguard Worker 	int retry = 0;
244*bd1f8aebSAndroid Build Coastguard Worker 	int i;
245*bd1f8aebSAndroid Build Coastguard Worker 
246*bd1f8aebSAndroid Build Coastguard Worker retry:
247*bd1f8aebSAndroid Build Coastguard Worker 	for (ifl=ifl_list; ifl; ifl=ifl->next)
248*bd1f8aebSAndroid Build Coastguard Worker 		if (ifl->index == ifindex)
249*bd1f8aebSAndroid Build Coastguard Worker 			break;
250*bd1f8aebSAndroid Build Coastguard Worker 	if (ifl == NULL && !retry) {
251*bd1f8aebSAndroid Build Coastguard Worker 		retry++;
252*bd1f8aebSAndroid Build Coastguard Worker 		load_if();
253*bd1f8aebSAndroid Build Coastguard Worker 		goto retry;
254*bd1f8aebSAndroid Build Coastguard Worker 	}
255*bd1f8aebSAndroid Build Coastguard Worker 	if (ifl == NULL)
256*bd1f8aebSAndroid Build Coastguard Worker 		return NULL;
257*bd1f8aebSAndroid Build Coastguard Worker 
258*bd1f8aebSAndroid Build Coastguard Worker 	for (i=0; alist[i]; i++) {
259*bd1f8aebSAndroid Build Coastguard Worker 		__u32 addr = *(alist[i]);
260*bd1f8aebSAndroid Build Coastguard Worker 		for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) {
261*bd1f8aebSAndroid Build Coastguard Worker 			if (!((ifa->prefix^addr)&ifa->mask)) {
262*bd1f8aebSAndroid Build Coastguard Worker 				*sel_addr = addr;
263*bd1f8aebSAndroid Build Coastguard Worker 				return ifa;
264*bd1f8aebSAndroid Build Coastguard Worker 			}
265*bd1f8aebSAndroid Build Coastguard Worker 		}
266*bd1f8aebSAndroid Build Coastguard Worker 		if (ifa == NULL && retry==0) {
267*bd1f8aebSAndroid Build Coastguard Worker 			retry++;
268*bd1f8aebSAndroid Build Coastguard Worker 			load_if();
269*bd1f8aebSAndroid Build Coastguard Worker 			goto retry;
270*bd1f8aebSAndroid Build Coastguard Worker 		}
271*bd1f8aebSAndroid Build Coastguard Worker 	}
272*bd1f8aebSAndroid Build Coastguard Worker 	if (i==1 && allow_offlink) {
273*bd1f8aebSAndroid Build Coastguard Worker 		*sel_addr = *(alist[0]);
274*bd1f8aebSAndroid Build Coastguard Worker 		return ifl->ifa_list;
275*bd1f8aebSAndroid Build Coastguard Worker 	}
276*bd1f8aebSAndroid Build Coastguard Worker 	syslog(LOG_ERR, "Off-link request on %s", ifl->name);
277*bd1f8aebSAndroid Build Coastguard Worker 	return NULL;
278*bd1f8aebSAndroid Build Coastguard Worker }
279*bd1f8aebSAndroid Build Coastguard Worker 
rarp_lookup(int ifindex,int hatype,int halen,unsigned char * lladdr)280*bd1f8aebSAndroid Build Coastguard Worker struct rarp_map *rarp_lookup(int ifindex, int hatype,
281*bd1f8aebSAndroid Build Coastguard Worker 			     int halen, unsigned char *lladdr)
282*bd1f8aebSAndroid Build Coastguard Worker {
283*bd1f8aebSAndroid Build Coastguard Worker 	struct rarp_map *r;
284*bd1f8aebSAndroid Build Coastguard Worker 
285*bd1f8aebSAndroid Build Coastguard Worker 	for (r=rarp_db; r; r=r->next) {
286*bd1f8aebSAndroid Build Coastguard Worker 		if (r->arp_type != hatype && r->arp_type != -1)
287*bd1f8aebSAndroid Build Coastguard Worker 			continue;
288*bd1f8aebSAndroid Build Coastguard Worker 		if (r->lladdr_len != halen)
289*bd1f8aebSAndroid Build Coastguard Worker 			continue;
290*bd1f8aebSAndroid Build Coastguard Worker 		if (r->ifindex != ifindex && r->ifindex != 0)
291*bd1f8aebSAndroid Build Coastguard Worker 			continue;
292*bd1f8aebSAndroid Build Coastguard Worker 		if (memcmp(r->lladdr, lladdr, halen) == 0)
293*bd1f8aebSAndroid Build Coastguard Worker 			break;
294*bd1f8aebSAndroid Build Coastguard Worker 	}
295*bd1f8aebSAndroid Build Coastguard Worker 
296*bd1f8aebSAndroid Build Coastguard Worker 	if (r == NULL) {
297*bd1f8aebSAndroid Build Coastguard Worker 		if (hatype == ARPHRD_ETHER && halen == 6) {
298*bd1f8aebSAndroid Build Coastguard Worker 			struct ifaddr *ifa;
299*bd1f8aebSAndroid Build Coastguard Worker 			struct hostent *hp;
300*bd1f8aebSAndroid Build Coastguard Worker 			char ename[256];
301*bd1f8aebSAndroid Build Coastguard Worker 			static struct rarp_map emap = {
302*bd1f8aebSAndroid Build Coastguard Worker 				NULL,
303*bd1f8aebSAndroid Build Coastguard Worker 				0,
304*bd1f8aebSAndroid Build Coastguard Worker 				ARPHRD_ETHER,
305*bd1f8aebSAndroid Build Coastguard Worker 				6,
306*bd1f8aebSAndroid Build Coastguard Worker 			};
307*bd1f8aebSAndroid Build Coastguard Worker 
308*bd1f8aebSAndroid Build Coastguard Worker 			if (ether_ntohost(ename, lladdr) != 0 ||
309*bd1f8aebSAndroid Build Coastguard Worker 			    (hp = gethostbyname(ename)) == NULL) {
310*bd1f8aebSAndroid Build Coastguard Worker 				if (verbose)
311*bd1f8aebSAndroid Build Coastguard Worker 					syslog(LOG_INFO, "not found in /etc/ethers");
312*bd1f8aebSAndroid Build Coastguard Worker 				return NULL;
313*bd1f8aebSAndroid Build Coastguard Worker 			}
314*bd1f8aebSAndroid Build Coastguard Worker 			if (hp->h_addrtype != AF_INET) {
315*bd1f8aebSAndroid Build Coastguard Worker 				syslog(LOG_ERR, "no IP address");
316*bd1f8aebSAndroid Build Coastguard Worker 				return NULL;
317*bd1f8aebSAndroid Build Coastguard Worker 			}
318*bd1f8aebSAndroid Build Coastguard Worker 			ifa = select_ipaddr(ifindex, &emap.ipaddr, (__u32 **)hp->h_addr_list);
319*bd1f8aebSAndroid Build Coastguard Worker 			if (ifa) {
320*bd1f8aebSAndroid Build Coastguard Worker 				memcpy(emap.lladdr, lladdr, 6);
321*bd1f8aebSAndroid Build Coastguard Worker 				if (only_ethers || bootable(emap.ipaddr))
322*bd1f8aebSAndroid Build Coastguard Worker 					return &emap;
323*bd1f8aebSAndroid Build Coastguard Worker 				if (verbose)
324*bd1f8aebSAndroid Build Coastguard Worker 					syslog(LOG_INFO, "not bootable");
325*bd1f8aebSAndroid Build Coastguard Worker 			}
326*bd1f8aebSAndroid Build Coastguard Worker 		}
327*bd1f8aebSAndroid Build Coastguard Worker 	}
328*bd1f8aebSAndroid Build Coastguard Worker 	return r;
329*bd1f8aebSAndroid Build Coastguard Worker }
330*bd1f8aebSAndroid Build Coastguard Worker 
load_arp_bpflet(int fd)331*bd1f8aebSAndroid Build Coastguard Worker static int load_arp_bpflet(int fd)
332*bd1f8aebSAndroid Build Coastguard Worker {
333*bd1f8aebSAndroid Build Coastguard Worker 	static struct sock_filter insns[] = {
334*bd1f8aebSAndroid Build Coastguard Worker 		BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
335*bd1f8aebSAndroid Build Coastguard Worker 		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ARPOP_RREQUEST, 0, 1),
336*bd1f8aebSAndroid Build Coastguard Worker 		BPF_STMT(BPF_RET|BPF_K, 1024),
337*bd1f8aebSAndroid Build Coastguard Worker 		BPF_STMT(BPF_RET|BPF_K, 0),
338*bd1f8aebSAndroid Build Coastguard Worker 	};
339*bd1f8aebSAndroid Build Coastguard Worker 	static struct sock_fprog filter = {
340*bd1f8aebSAndroid Build Coastguard Worker 		sizeof insns / sizeof(insns[0]),
341*bd1f8aebSAndroid Build Coastguard Worker 		insns
342*bd1f8aebSAndroid Build Coastguard Worker 	};
343*bd1f8aebSAndroid Build Coastguard Worker 
344*bd1f8aebSAndroid Build Coastguard Worker 	return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
345*bd1f8aebSAndroid Build Coastguard Worker }
346*bd1f8aebSAndroid Build Coastguard Worker 
put_mylladdr(unsigned char ** ptr_p,int ifindex,int alen)347*bd1f8aebSAndroid Build Coastguard Worker int put_mylladdr(unsigned char **ptr_p, int ifindex, int alen)
348*bd1f8aebSAndroid Build Coastguard Worker {
349*bd1f8aebSAndroid Build Coastguard Worker 	struct iflink *ifl;
350*bd1f8aebSAndroid Build Coastguard Worker 
351*bd1f8aebSAndroid Build Coastguard Worker 	for (ifl=ifl_list; ifl; ifl = ifl->next)
352*bd1f8aebSAndroid Build Coastguard Worker 		if (ifl->index == ifindex)
353*bd1f8aebSAndroid Build Coastguard Worker 			break;
354*bd1f8aebSAndroid Build Coastguard Worker 
355*bd1f8aebSAndroid Build Coastguard Worker 	if (ifl==NULL)
356*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
357*bd1f8aebSAndroid Build Coastguard Worker 
358*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(*ptr_p, ifl->lladdr, alen);
359*bd1f8aebSAndroid Build Coastguard Worker 	*ptr_p += alen;
360*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
361*bd1f8aebSAndroid Build Coastguard Worker }
362*bd1f8aebSAndroid Build Coastguard Worker 
put_myipaddr(unsigned char ** ptr_p,int ifindex,__u32 hisipaddr)363*bd1f8aebSAndroid Build Coastguard Worker int put_myipaddr(unsigned char **ptr_p, int ifindex, __u32 hisipaddr)
364*bd1f8aebSAndroid Build Coastguard Worker {
365*bd1f8aebSAndroid Build Coastguard Worker 	__u32 laddr = 0;
366*bd1f8aebSAndroid Build Coastguard Worker 	struct iflink *ifl;
367*bd1f8aebSAndroid Build Coastguard Worker 	struct ifaddr *ifa;
368*bd1f8aebSAndroid Build Coastguard Worker 
369*bd1f8aebSAndroid Build Coastguard Worker 	for (ifl=ifl_list; ifl; ifl = ifl->next)
370*bd1f8aebSAndroid Build Coastguard Worker 		if (ifl->index == ifindex)
371*bd1f8aebSAndroid Build Coastguard Worker 			break;
372*bd1f8aebSAndroid Build Coastguard Worker 
373*bd1f8aebSAndroid Build Coastguard Worker 	if (ifl==NULL)
374*bd1f8aebSAndroid Build Coastguard Worker 		return -1;
375*bd1f8aebSAndroid Build Coastguard Worker 
376*bd1f8aebSAndroid Build Coastguard Worker 	for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) {
377*bd1f8aebSAndroid Build Coastguard Worker 		if (!((ifa->prefix^hisipaddr)&ifa->mask)) {
378*bd1f8aebSAndroid Build Coastguard Worker 			laddr = ifa->local;
379*bd1f8aebSAndroid Build Coastguard Worker 			break;
380*bd1f8aebSAndroid Build Coastguard Worker 		}
381*bd1f8aebSAndroid Build Coastguard Worker 	}
382*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(*ptr_p, &laddr, 4);
383*bd1f8aebSAndroid Build Coastguard Worker 	*ptr_p += 4;
384*bd1f8aebSAndroid Build Coastguard Worker 	return 0;
385*bd1f8aebSAndroid Build Coastguard Worker }
386*bd1f8aebSAndroid Build Coastguard Worker 
arp_advise(int ifindex,unsigned char * lladdr,int lllen,__u32 ipaddr)387*bd1f8aebSAndroid Build Coastguard Worker void arp_advise(int ifindex, unsigned char *lladdr, int lllen, __u32 ipaddr)
388*bd1f8aebSAndroid Build Coastguard Worker {
389*bd1f8aebSAndroid Build Coastguard Worker 	int fd;
390*bd1f8aebSAndroid Build Coastguard Worker 	struct arpreq req;
391*bd1f8aebSAndroid Build Coastguard Worker 	struct sockaddr_in *sin;
392*bd1f8aebSAndroid Build Coastguard Worker 	struct iflink *ifl;
393*bd1f8aebSAndroid Build Coastguard Worker 
394*bd1f8aebSAndroid Build Coastguard Worker 	for (ifl=ifl_list; ifl; ifl = ifl->next)
395*bd1f8aebSAndroid Build Coastguard Worker 		if (ifl->index == ifindex)
396*bd1f8aebSAndroid Build Coastguard Worker 			break;
397*bd1f8aebSAndroid Build Coastguard Worker 
398*bd1f8aebSAndroid Build Coastguard Worker 	if (ifl == NULL)
399*bd1f8aebSAndroid Build Coastguard Worker 		return;
400*bd1f8aebSAndroid Build Coastguard Worker 
401*bd1f8aebSAndroid Build Coastguard Worker 	fd = socket(AF_INET, SOCK_DGRAM, 0);
402*bd1f8aebSAndroid Build Coastguard Worker 	memset(&req, 0, sizeof(req));
403*bd1f8aebSAndroid Build Coastguard Worker 	req.arp_flags = ATF_COM;
404*bd1f8aebSAndroid Build Coastguard Worker 	sin = (struct sockaddr_in *)&req.arp_pa;
405*bd1f8aebSAndroid Build Coastguard Worker 	sin->sin_family = AF_INET;
406*bd1f8aebSAndroid Build Coastguard Worker 	sin->sin_addr.s_addr = ipaddr;
407*bd1f8aebSAndroid Build Coastguard Worker 	req.arp_ha.sa_family = ifl->hatype;
408*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(req.arp_ha.sa_data, lladdr, lllen);
409*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(req.arp_dev, ifl->name, IFNAMSIZ);
410*bd1f8aebSAndroid Build Coastguard Worker 
411*bd1f8aebSAndroid Build Coastguard Worker 	if (ioctl(fd, SIOCSARP, &req))
412*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "SIOCSARP: %m");
413*bd1f8aebSAndroid Build Coastguard Worker 	close(fd);
414*bd1f8aebSAndroid Build Coastguard Worker }
415*bd1f8aebSAndroid Build Coastguard Worker 
serve_it(int fd)416*bd1f8aebSAndroid Build Coastguard Worker void serve_it(int fd)
417*bd1f8aebSAndroid Build Coastguard Worker {
418*bd1f8aebSAndroid Build Coastguard Worker 	unsigned char buf[1024];
419*bd1f8aebSAndroid Build Coastguard Worker 	struct sockaddr_ll sll;
420*bd1f8aebSAndroid Build Coastguard Worker 	socklen_t sll_len = sizeof(sll);
421*bd1f8aebSAndroid Build Coastguard Worker 	struct arphdr *a = (struct arphdr*)buf;
422*bd1f8aebSAndroid Build Coastguard Worker 	struct rarp_map *rmap;
423*bd1f8aebSAndroid Build Coastguard Worker 	unsigned char *ptr;
424*bd1f8aebSAndroid Build Coastguard Worker 	int n;
425*bd1f8aebSAndroid Build Coastguard Worker 
426*bd1f8aebSAndroid Build Coastguard Worker 	n = recvfrom(fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sll, &sll_len);
427*bd1f8aebSAndroid Build Coastguard Worker 	if (n<0) {
428*bd1f8aebSAndroid Build Coastguard Worker 		if (errno != EINTR && errno != EAGAIN)
429*bd1f8aebSAndroid Build Coastguard Worker 			syslog(LOG_ERR, "recvfrom: %m");
430*bd1f8aebSAndroid Build Coastguard Worker 		return;
431*bd1f8aebSAndroid Build Coastguard Worker 	}
432*bd1f8aebSAndroid Build Coastguard Worker 
433*bd1f8aebSAndroid Build Coastguard Worker 	/* Do not accept packets for other hosts and our own ones */
434*bd1f8aebSAndroid Build Coastguard Worker 	if (sll.sll_pkttype != PACKET_BROADCAST &&
435*bd1f8aebSAndroid Build Coastguard Worker 	    sll.sll_pkttype != PACKET_MULTICAST &&
436*bd1f8aebSAndroid Build Coastguard Worker 	    sll.sll_pkttype != PACKET_HOST)
437*bd1f8aebSAndroid Build Coastguard Worker 		return;
438*bd1f8aebSAndroid Build Coastguard Worker 
439*bd1f8aebSAndroid Build Coastguard Worker 	if (ifidx && sll.sll_ifindex != ifidx)
440*bd1f8aebSAndroid Build Coastguard Worker 		return;
441*bd1f8aebSAndroid Build Coastguard Worker 
442*bd1f8aebSAndroid Build Coastguard Worker 	if (n<sizeof(*a)) {
443*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "truncated arp packet; len=%d", n);
444*bd1f8aebSAndroid Build Coastguard Worker 		return;
445*bd1f8aebSAndroid Build Coastguard Worker 	}
446*bd1f8aebSAndroid Build Coastguard Worker 
447*bd1f8aebSAndroid Build Coastguard Worker 	/* Accept only RARP requests */
448*bd1f8aebSAndroid Build Coastguard Worker 	if (a->ar_op != htons(ARPOP_RREQUEST))
449*bd1f8aebSAndroid Build Coastguard Worker 		return;
450*bd1f8aebSAndroid Build Coastguard Worker 
451*bd1f8aebSAndroid Build Coastguard Worker 	if (verbose) {
452*bd1f8aebSAndroid Build Coastguard Worker 		int i;
453*bd1f8aebSAndroid Build Coastguard Worker 		char tmpbuf[16*3];
454*bd1f8aebSAndroid Build Coastguard Worker 		char *ptr = tmpbuf;
455*bd1f8aebSAndroid Build Coastguard Worker 		for (i=0; i<sll.sll_halen; i++) {
456*bd1f8aebSAndroid Build Coastguard Worker 			if (i) {
457*bd1f8aebSAndroid Build Coastguard Worker 				sprintf(ptr, ":%02x", sll.sll_addr[i]);
458*bd1f8aebSAndroid Build Coastguard Worker 				ptr++;
459*bd1f8aebSAndroid Build Coastguard Worker 			} else
460*bd1f8aebSAndroid Build Coastguard Worker 				sprintf(ptr, "%02x", sll.sll_addr[i]);
461*bd1f8aebSAndroid Build Coastguard Worker 			ptr += 2;
462*bd1f8aebSAndroid Build Coastguard Worker 		}
463*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_INFO, "RARP request from %s on if%d", tmpbuf, sll.sll_ifindex);
464*bd1f8aebSAndroid Build Coastguard Worker 	}
465*bd1f8aebSAndroid Build Coastguard Worker 
466*bd1f8aebSAndroid Build Coastguard Worker 	/* Sanity checks */
467*bd1f8aebSAndroid Build Coastguard Worker 
468*bd1f8aebSAndroid Build Coastguard Worker 	/* 1. IP only -> pln==4 */
469*bd1f8aebSAndroid Build Coastguard Worker 	if (a->ar_pln != 4) {
470*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "interesting rarp_req plen=%d", a->ar_pln);
471*bd1f8aebSAndroid Build Coastguard Worker 		return;
472*bd1f8aebSAndroid Build Coastguard Worker 	}
473*bd1f8aebSAndroid Build Coastguard Worker 	/* 2. ARP protocol must be IP */
474*bd1f8aebSAndroid Build Coastguard Worker 	if (a->ar_pro != htons(ETH_P_IP)) {
475*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "rarp protocol is not IP %04x", ntohs(a->ar_pro));
476*bd1f8aebSAndroid Build Coastguard Worker 		return;
477*bd1f8aebSAndroid Build Coastguard Worker 	}
478*bd1f8aebSAndroid Build Coastguard Worker 	/* 3. ARP types must match */
479*bd1f8aebSAndroid Build Coastguard Worker 	if (htons(sll.sll_hatype) != a->ar_hrd) {
480*bd1f8aebSAndroid Build Coastguard Worker 		switch (sll.sll_hatype) {
481*bd1f8aebSAndroid Build Coastguard Worker 		case ARPHRD_FDDI:
482*bd1f8aebSAndroid Build Coastguard Worker 			if (a->ar_hrd == htons(ARPHRD_ETHER) ||
483*bd1f8aebSAndroid Build Coastguard Worker 			    a->ar_hrd == htons(ARPHRD_IEEE802))
484*bd1f8aebSAndroid Build Coastguard Worker 				break;
485*bd1f8aebSAndroid Build Coastguard Worker 		default:
486*bd1f8aebSAndroid Build Coastguard Worker 			syslog(LOG_ERR, "rarp htype mismatch");
487*bd1f8aebSAndroid Build Coastguard Worker 			return;
488*bd1f8aebSAndroid Build Coastguard Worker 		}
489*bd1f8aebSAndroid Build Coastguard Worker 	}
490*bd1f8aebSAndroid Build Coastguard Worker 	/* 3. LL address lengths must be equal */
491*bd1f8aebSAndroid Build Coastguard Worker 	if (a->ar_hln != sll.sll_halen) {
492*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "rarp hlen mismatch");
493*bd1f8aebSAndroid Build Coastguard Worker 		return;
494*bd1f8aebSAndroid Build Coastguard Worker 	}
495*bd1f8aebSAndroid Build Coastguard Worker 	/* 4. Check packet length */
496*bd1f8aebSAndroid Build Coastguard Worker 	if (sizeof(*a) + 2*4 + 2*a->ar_hln > n) {
497*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "truncated rarp request; len=%d", n);
498*bd1f8aebSAndroid Build Coastguard Worker 		return;
499*bd1f8aebSAndroid Build Coastguard Worker 	}
500*bd1f8aebSAndroid Build Coastguard Worker 	/* 5. Silly check: if this guy set different source
501*bd1f8aebSAndroid Build Coastguard Worker 	      addresses in MAC header and in ARP, he is insane
502*bd1f8aebSAndroid Build Coastguard Worker 	 */
503*bd1f8aebSAndroid Build Coastguard Worker 	if (memcmp(sll.sll_addr, a+1, sll.sll_halen)) {
504*bd1f8aebSAndroid Build Coastguard Worker 		syslog(LOG_ERR, "this guy set different his lladdrs in arp and header");
505*bd1f8aebSAndroid Build Coastguard Worker 		return;
506*bd1f8aebSAndroid Build Coastguard Worker 	}
507*bd1f8aebSAndroid Build Coastguard Worker 	/* End of sanity checks */
508*bd1f8aebSAndroid Build Coastguard Worker 
509*bd1f8aebSAndroid Build Coastguard Worker 	/* Lookup requested target in our database */
510*bd1f8aebSAndroid Build Coastguard Worker 	rmap = rarp_lookup(sll.sll_ifindex, sll.sll_hatype,
511*bd1f8aebSAndroid Build Coastguard Worker 			   sll.sll_halen, (unsigned char*)(a+1) + sll.sll_halen + 4);
512*bd1f8aebSAndroid Build Coastguard Worker 	if (rmap == NULL)
513*bd1f8aebSAndroid Build Coastguard Worker 		return;
514*bd1f8aebSAndroid Build Coastguard Worker 
515*bd1f8aebSAndroid Build Coastguard Worker 	/* Prepare reply. It is almost ready, we only
516*bd1f8aebSAndroid Build Coastguard Worker 	   replace ARP packet type, put our lladdr and
517*bd1f8aebSAndroid Build Coastguard Worker 	   IP address to source fileds,
518*bd1f8aebSAndroid Build Coastguard Worker 	   and fill target IP address.
519*bd1f8aebSAndroid Build Coastguard Worker 	 */
520*bd1f8aebSAndroid Build Coastguard Worker 	a->ar_op = htons(ARPOP_RREPLY);
521*bd1f8aebSAndroid Build Coastguard Worker 	ptr = (unsigned char*)(a+1);
522*bd1f8aebSAndroid Build Coastguard Worker 	if (put_mylladdr(&ptr, sll.sll_ifindex, rmap->lladdr_len))
523*bd1f8aebSAndroid Build Coastguard Worker 		return;
524*bd1f8aebSAndroid Build Coastguard Worker 	if (put_myipaddr(&ptr, sll.sll_ifindex, rmap->ipaddr))
525*bd1f8aebSAndroid Build Coastguard Worker 		return;
526*bd1f8aebSAndroid Build Coastguard Worker 	/* It is already filled */
527*bd1f8aebSAndroid Build Coastguard Worker 	ptr += rmap->lladdr_len;
528*bd1f8aebSAndroid Build Coastguard Worker 	memcpy(ptr, &rmap->ipaddr, 4);
529*bd1f8aebSAndroid Build Coastguard Worker 	ptr += 4;
530*bd1f8aebSAndroid Build Coastguard Worker 
531*bd1f8aebSAndroid Build Coastguard Worker 	/* Update our ARP cache. Probably, this guy
532*bd1f8aebSAndroid Build Coastguard Worker 	   will not able to make ARP (if it is broken)
533*bd1f8aebSAndroid Build Coastguard Worker 	 */
534*bd1f8aebSAndroid Build Coastguard Worker 	arp_advise(sll.sll_ifindex, rmap->lladdr, rmap->lladdr_len, rmap->ipaddr);
535*bd1f8aebSAndroid Build Coastguard Worker 
536*bd1f8aebSAndroid Build Coastguard Worker 	/* Sendto is blocking, but with 5sec timeout */
537*bd1f8aebSAndroid Build Coastguard Worker 	alarm(5);
538*bd1f8aebSAndroid Build Coastguard Worker 	sendto(fd, buf, ptr - buf, 0, (struct sockaddr*)&sll, sizeof(sll));
539*bd1f8aebSAndroid Build Coastguard Worker 	alarm(0);
540*bd1f8aebSAndroid Build Coastguard Worker }
541*bd1f8aebSAndroid Build Coastguard Worker 
catch_signal(int sig,void (* handler)(int))542*bd1f8aebSAndroid Build Coastguard Worker void catch_signal(int sig, void (*handler)(int))
543*bd1f8aebSAndroid Build Coastguard Worker {
544*bd1f8aebSAndroid Build Coastguard Worker 	struct sigaction sa;
545*bd1f8aebSAndroid Build Coastguard Worker 
546*bd1f8aebSAndroid Build Coastguard Worker 	memset(&sa, 0, sizeof(sa));
547*bd1f8aebSAndroid Build Coastguard Worker 	sa.sa_handler = handler;
548*bd1f8aebSAndroid Build Coastguard Worker #ifdef SA_INTERRUPT
549*bd1f8aebSAndroid Build Coastguard Worker 	sa.sa_flags = SA_INTERRUPT;
550*bd1f8aebSAndroid Build Coastguard Worker #endif
551*bd1f8aebSAndroid Build Coastguard Worker 	sigaction(sig, &sa, NULL);
552*bd1f8aebSAndroid Build Coastguard Worker }
553*bd1f8aebSAndroid Build Coastguard Worker 
sig_alarm(int signo)554*bd1f8aebSAndroid Build Coastguard Worker void sig_alarm(int signo)
555*bd1f8aebSAndroid Build Coastguard Worker {
556*bd1f8aebSAndroid Build Coastguard Worker }
557*bd1f8aebSAndroid Build Coastguard Worker 
sig_hup(int signo)558*bd1f8aebSAndroid Build Coastguard Worker void sig_hup(int signo)
559*bd1f8aebSAndroid Build Coastguard Worker {
560*bd1f8aebSAndroid Build Coastguard Worker 	do_reload = 1;
561*bd1f8aebSAndroid Build Coastguard Worker }
562*bd1f8aebSAndroid Build Coastguard Worker 
main(int argc,char ** argv)563*bd1f8aebSAndroid Build Coastguard Worker int main(int argc, char **argv)
564*bd1f8aebSAndroid Build Coastguard Worker {
565*bd1f8aebSAndroid Build Coastguard Worker 	struct pollfd pset[2];
566*bd1f8aebSAndroid Build Coastguard Worker 	int psize;
567*bd1f8aebSAndroid Build Coastguard Worker 	int opt;
568*bd1f8aebSAndroid Build Coastguard Worker 
569*bd1f8aebSAndroid Build Coastguard Worker 
570*bd1f8aebSAndroid Build Coastguard Worker 	opterr = 0;
571*bd1f8aebSAndroid Build Coastguard Worker 	while ((opt = getopt(argc, argv, "aAb:dvoe")) != EOF) {
572*bd1f8aebSAndroid Build Coastguard Worker 		switch (opt) {
573*bd1f8aebSAndroid Build Coastguard Worker 		case 'a':
574*bd1f8aebSAndroid Build Coastguard Worker 			++all_ifaces;
575*bd1f8aebSAndroid Build Coastguard Worker 			break;
576*bd1f8aebSAndroid Build Coastguard Worker 
577*bd1f8aebSAndroid Build Coastguard Worker 		case 'A':
578*bd1f8aebSAndroid Build Coastguard Worker 			++listen_arp;
579*bd1f8aebSAndroid Build Coastguard Worker 			break;
580*bd1f8aebSAndroid Build Coastguard Worker 
581*bd1f8aebSAndroid Build Coastguard Worker 		case 'd':
582*bd1f8aebSAndroid Build Coastguard Worker 			++debug;
583*bd1f8aebSAndroid Build Coastguard Worker 			break;
584*bd1f8aebSAndroid Build Coastguard Worker 
585*bd1f8aebSAndroid Build Coastguard Worker 		case 'v':
586*bd1f8aebSAndroid Build Coastguard Worker 			++verbose;
587*bd1f8aebSAndroid Build Coastguard Worker 			break;
588*bd1f8aebSAndroid Build Coastguard Worker 
589*bd1f8aebSAndroid Build Coastguard Worker 		case 'o':
590*bd1f8aebSAndroid Build Coastguard Worker 			++allow_offlink;
591*bd1f8aebSAndroid Build Coastguard Worker 			break;
592*bd1f8aebSAndroid Build Coastguard Worker 
593*bd1f8aebSAndroid Build Coastguard Worker 		case 'e':
594*bd1f8aebSAndroid Build Coastguard Worker 			++only_ethers;
595*bd1f8aebSAndroid Build Coastguard Worker 			break;
596*bd1f8aebSAndroid Build Coastguard Worker 
597*bd1f8aebSAndroid Build Coastguard Worker 		case 'b':
598*bd1f8aebSAndroid Build Coastguard Worker 			tftp_dir = optarg;
599*bd1f8aebSAndroid Build Coastguard Worker 			break;
600*bd1f8aebSAndroid Build Coastguard Worker 
601*bd1f8aebSAndroid Build Coastguard Worker 		default:
602*bd1f8aebSAndroid Build Coastguard Worker 			usage();
603*bd1f8aebSAndroid Build Coastguard Worker 		}
604*bd1f8aebSAndroid Build Coastguard Worker 	}
605*bd1f8aebSAndroid Build Coastguard Worker 	if (argc > optind) {
606*bd1f8aebSAndroid Build Coastguard Worker 		if (argc > optind+1)
607*bd1f8aebSAndroid Build Coastguard Worker 			usage();
608*bd1f8aebSAndroid Build Coastguard Worker 		ifname = argv[optind];
609*bd1f8aebSAndroid Build Coastguard Worker 	}
610*bd1f8aebSAndroid Build Coastguard Worker 
611*bd1f8aebSAndroid Build Coastguard Worker 	psize = 1;
612*bd1f8aebSAndroid Build Coastguard Worker 	pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
613*bd1f8aebSAndroid Build Coastguard Worker 
614*bd1f8aebSAndroid Build Coastguard Worker 	if (ifname) {
615*bd1f8aebSAndroid Build Coastguard Worker 		struct ifreq ifr;
616*bd1f8aebSAndroid Build Coastguard Worker 		memset(&ifr, 0, sizeof(ifr));
617*bd1f8aebSAndroid Build Coastguard Worker 		strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
618*bd1f8aebSAndroid Build Coastguard Worker 		if (ioctl(pset[0].fd, SIOCGIFINDEX, &ifr)) {
619*bd1f8aebSAndroid Build Coastguard Worker 			perror("ioctl(SIOCGIFINDEX)");
620*bd1f8aebSAndroid Build Coastguard Worker 			usage();
621*bd1f8aebSAndroid Build Coastguard Worker 		}
622*bd1f8aebSAndroid Build Coastguard Worker 		ifidx = ifr.ifr_ifindex;
623*bd1f8aebSAndroid Build Coastguard Worker 	}
624*bd1f8aebSAndroid Build Coastguard Worker 
625*bd1f8aebSAndroid Build Coastguard Worker 	pset[1].fd = -1;
626*bd1f8aebSAndroid Build Coastguard Worker 	if (listen_arp) {
627*bd1f8aebSAndroid Build Coastguard Worker 		pset[1].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
628*bd1f8aebSAndroid Build Coastguard Worker 		if (pset[1].fd >= 0) {
629*bd1f8aebSAndroid Build Coastguard Worker 			load_arp_bpflet(pset[1].fd);
630*bd1f8aebSAndroid Build Coastguard Worker 			psize = 1;
631*bd1f8aebSAndroid Build Coastguard Worker 		}
632*bd1f8aebSAndroid Build Coastguard Worker 	}
633*bd1f8aebSAndroid Build Coastguard Worker 
634*bd1f8aebSAndroid Build Coastguard Worker 	if (pset[1].fd >= 0) {
635*bd1f8aebSAndroid Build Coastguard Worker 		struct sockaddr_ll sll;
636*bd1f8aebSAndroid Build Coastguard Worker 		memset(&sll, 0, sizeof(sll));
637*bd1f8aebSAndroid Build Coastguard Worker 		sll.sll_family = AF_PACKET;
638*bd1f8aebSAndroid Build Coastguard Worker 		sll.sll_protocol = htons(ETH_P_ARP);
639*bd1f8aebSAndroid Build Coastguard Worker 		sll.sll_ifindex = all_ifaces ? 0 : ifidx;
640*bd1f8aebSAndroid Build Coastguard Worker 		if (bind(pset[1].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
641*bd1f8aebSAndroid Build Coastguard Worker 			close(pset[1].fd);
642*bd1f8aebSAndroid Build Coastguard Worker 			pset[1].fd = -1;
643*bd1f8aebSAndroid Build Coastguard Worker 			psize = 1;
644*bd1f8aebSAndroid Build Coastguard Worker 		}
645*bd1f8aebSAndroid Build Coastguard Worker 	}
646*bd1f8aebSAndroid Build Coastguard Worker 	if (pset[0].fd >= 0) {
647*bd1f8aebSAndroid Build Coastguard Worker 		struct sockaddr_ll sll;
648*bd1f8aebSAndroid Build Coastguard Worker 		memset(&sll, 0, sizeof(sll));
649*bd1f8aebSAndroid Build Coastguard Worker 		sll.sll_family = AF_PACKET;
650*bd1f8aebSAndroid Build Coastguard Worker 		sll.sll_protocol = htons(ETH_P_RARP);
651*bd1f8aebSAndroid Build Coastguard Worker 		sll.sll_ifindex = all_ifaces ? 0 : ifidx;
652*bd1f8aebSAndroid Build Coastguard Worker 		if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
653*bd1f8aebSAndroid Build Coastguard Worker 			close(pset[0].fd);
654*bd1f8aebSAndroid Build Coastguard Worker 			pset[0].fd = -1;
655*bd1f8aebSAndroid Build Coastguard Worker 		}
656*bd1f8aebSAndroid Build Coastguard Worker 	}
657*bd1f8aebSAndroid Build Coastguard Worker 	if (pset[0].fd < 0) {
658*bd1f8aebSAndroid Build Coastguard Worker 		pset[0] = pset[1];
659*bd1f8aebSAndroid Build Coastguard Worker 		psize--;
660*bd1f8aebSAndroid Build Coastguard Worker 	}
661*bd1f8aebSAndroid Build Coastguard Worker 	if (psize == 0) {
662*bd1f8aebSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to bind any socket. Aborting.\n");
663*bd1f8aebSAndroid Build Coastguard Worker 		exit(1);
664*bd1f8aebSAndroid Build Coastguard Worker 	}
665*bd1f8aebSAndroid Build Coastguard Worker 
666*bd1f8aebSAndroid Build Coastguard Worker 	if (!debug) {
667*bd1f8aebSAndroid Build Coastguard Worker 		int fd;
668*bd1f8aebSAndroid Build Coastguard Worker 		pid_t pid = fork();
669*bd1f8aebSAndroid Build Coastguard Worker 
670*bd1f8aebSAndroid Build Coastguard Worker 		if (pid > 0)
671*bd1f8aebSAndroid Build Coastguard Worker 			exit(0);
672*bd1f8aebSAndroid Build Coastguard Worker 		else if (pid == -1) {
673*bd1f8aebSAndroid Build Coastguard Worker 			perror("rarpd: fork");
674*bd1f8aebSAndroid Build Coastguard Worker 			exit(1);
675*bd1f8aebSAndroid Build Coastguard Worker 		}
676*bd1f8aebSAndroid Build Coastguard Worker 
677*bd1f8aebSAndroid Build Coastguard Worker 		if (chdir("/") < 0) {
678*bd1f8aebSAndroid Build Coastguard Worker 			perror("rarpd: chdir");
679*bd1f8aebSAndroid Build Coastguard Worker 			exit(1);
680*bd1f8aebSAndroid Build Coastguard Worker 		}
681*bd1f8aebSAndroid Build Coastguard Worker 
682*bd1f8aebSAndroid Build Coastguard Worker 		fd = open("/dev/null", O_RDWR);
683*bd1f8aebSAndroid Build Coastguard Worker 		if (fd >= 0) {
684*bd1f8aebSAndroid Build Coastguard Worker 			dup2(fd, 0);
685*bd1f8aebSAndroid Build Coastguard Worker 			dup2(fd, 1);
686*bd1f8aebSAndroid Build Coastguard Worker 			dup2(fd, 2);
687*bd1f8aebSAndroid Build Coastguard Worker 			if (fd > 2)
688*bd1f8aebSAndroid Build Coastguard Worker 				close(fd);
689*bd1f8aebSAndroid Build Coastguard Worker 		}
690*bd1f8aebSAndroid Build Coastguard Worker 		setsid();
691*bd1f8aebSAndroid Build Coastguard Worker 	}
692*bd1f8aebSAndroid Build Coastguard Worker 
693*bd1f8aebSAndroid Build Coastguard Worker 	openlog("rarpd", LOG_PID | LOG_CONS, LOG_DAEMON);
694*bd1f8aebSAndroid Build Coastguard Worker 	catch_signal(SIGALRM, sig_alarm);
695*bd1f8aebSAndroid Build Coastguard Worker 	catch_signal(SIGHUP, sig_hup);
696*bd1f8aebSAndroid Build Coastguard Worker 
697*bd1f8aebSAndroid Build Coastguard Worker 	for (;;) {
698*bd1f8aebSAndroid Build Coastguard Worker 		int i;
699*bd1f8aebSAndroid Build Coastguard Worker 
700*bd1f8aebSAndroid Build Coastguard Worker 		if (do_reload) {
701*bd1f8aebSAndroid Build Coastguard Worker 			configure();
702*bd1f8aebSAndroid Build Coastguard Worker 			do_reload = 0;
703*bd1f8aebSAndroid Build Coastguard Worker 		}
704*bd1f8aebSAndroid Build Coastguard Worker 
705*bd1f8aebSAndroid Build Coastguard Worker #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
706*bd1f8aebSAndroid Build Coastguard Worker 		pset[0].events = EVENTS;
707*bd1f8aebSAndroid Build Coastguard Worker 		pset[0].revents = 0;
708*bd1f8aebSAndroid Build Coastguard Worker 		pset[1].events = EVENTS;
709*bd1f8aebSAndroid Build Coastguard Worker 		pset[1].revents = 0;
710*bd1f8aebSAndroid Build Coastguard Worker 
711*bd1f8aebSAndroid Build Coastguard Worker 		i = poll(pset, psize, -1);
712*bd1f8aebSAndroid Build Coastguard Worker 		if (i <= 0) {
713*bd1f8aebSAndroid Build Coastguard Worker 			if (errno != EINTR && i<0) {
714*bd1f8aebSAndroid Build Coastguard Worker 				syslog(LOG_ERR, "poll returned some crap: %m\n");
715*bd1f8aebSAndroid Build Coastguard Worker 				sleep(10);
716*bd1f8aebSAndroid Build Coastguard Worker 			}
717*bd1f8aebSAndroid Build Coastguard Worker 			continue;
718*bd1f8aebSAndroid Build Coastguard Worker 		}
719*bd1f8aebSAndroid Build Coastguard Worker 		for (i=0; i<psize; i++) {
720*bd1f8aebSAndroid Build Coastguard Worker 			if (pset[i].revents&EVENTS)
721*bd1f8aebSAndroid Build Coastguard Worker 				serve_it(pset[i].fd);
722*bd1f8aebSAndroid Build Coastguard Worker 		}
723*bd1f8aebSAndroid Build Coastguard Worker 	}
724*bd1f8aebSAndroid Build Coastguard Worker }
725