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