Ditch the sysvinit stuff
[profile/ivi/iputils.git] / rarpd.c
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
33 int do_reload = 1;
34
35 int debug;
36 int verbose;
37 int ifidx;
38 int allow_offlink;
39 int only_ethers;
40 int all_ifaces;
41 int listen_arp;
42 char *ifname;
43 char *tftp_dir = "/etc/tftpboot";
44
45 extern int ether_ntohost(char *name, unsigned char *ea);
46 void usage(void) __attribute__((noreturn));
47
48 struct 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
58 struct ifaddr
59 {
60         struct ifaddr   *next;
61         __u32           prefix;
62         __u32           mask;
63         __u32           local;
64 };
65
66 struct 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
77 void usage()
78 {
79         fprintf(stderr, "Usage: rarpd [ -dveaA ] [ -b tftpdir ] [ interface]\n");
80         exit(1);
81 }
82
83 void load_db(void)
84 {
85 }
86
87 void 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
213 void configure(void)
214 {
215         load_if();
216         load_db();
217 }
218
219 int 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
239 struct 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
246 retry:
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
280 struct 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
331 static 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
347 int 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
363 int 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
387 void 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
416 void 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
542 void 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
554 void sig_alarm(int signo)
555 {
556 }
557
558 void sig_hup(int signo)
559 {
560         do_reload = 1;
561 }
562
563 int 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                 chdir("/");
678                 fd = open("/dev/null", O_RDWR);
679                 if (fd >= 0) {
680                         dup2(fd, 0);
681                         dup2(fd, 1);
682                         dup2(fd, 2);
683                         if (fd > 2)
684                                 close(fd);
685                 }
686                 setsid();
687         }
688
689         openlog("rarpd", LOG_PID | LOG_CONS, LOG_DAEMON);
690         catch_signal(SIGALRM, sig_alarm);
691         catch_signal(SIGHUP, sig_hup);
692
693         for (;;) {
694                 int i;
695
696                 if (do_reload) {
697                         configure();
698                         do_reload = 0;
699                 }
700
701 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
702                 pset[0].events = EVENTS;
703                 pset[0].revents = 0;
704                 pset[1].events = EVENTS;
705                 pset[1].revents = 0;
706
707                 i = poll(pset, psize, -1);
708                 if (i <= 0) {
709                         if (errno != EINTR && i<0) {
710                                 syslog(LOG_ERR, "poll returned some crap: %m\n");
711                                 sleep(10);
712                         }
713                         continue;
714                 }
715                 for (i=0; i<psize; i++) {
716                         if (pset[i].revents&EVENTS)
717                                 serve_it(pset[i].fd);
718                 }
719         }
720 }