blob: b740e87932247fa4fe251829d321c5e661f97f14 [file] [log] [blame]
Lorenzo Colitti313379e2013-07-11 01:07:11 +09001/*
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}