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