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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
20 #include <arpa/inet.h>
21 #include <sys/ioctl.h>
23 #include <sys/errno.h>
24 #include <sys/fcntl.h>
25 #include <sys/socket.h>
26 #include <sys/signal.h>
28 #include <linux/if_arp.h>
29 #include <netinet/in.h>
30 #include <linux/if_packet.h>
31 #include <linux/filter.h>
43 char *tftp_dir = "/etc/tftpboot";
45 extern int ether_ntohost(char *name, unsigned char *ea);
46 void usage(void) __attribute__((noreturn));
53 unsigned char lladdr[16];
55 struct ifaddr *ifa_list;
68 struct rarp_map *next;
73 unsigned char lladdr[16];
79 fprintf(stderr, "Usage: rarpd [ -dveaA ] [ -b tftpdir ] [ interface]\n");
90 struct ifreq *ifrp, *ifend;
94 struct ifreq ibuf[256];
96 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
97 syslog(LOG_ERR, "socket: %m");
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");
110 while ((ifl = ifl_list) != NULL) {
111 while ((ifa = ifl->ifa_list) != NULL) {
112 ifl->ifa_list = ifa->next;
115 ifl_list = ifl->next;
119 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
120 for (ifrp = ibuf; ifrp < ifend; ifrp++) {
125 if (ifrp->ifr_addr.sa_family != AF_INET)
127 addr = ((struct sockaddr_in*)&ifrp->ifr_addr)->sin_addr.s_addr;
130 if (ioctl(fd, SIOCGIFINDEX, ifrp)) {
131 syslog(LOG_ERR, "ioctl(SIOCGIFNAME): %m");
134 if (ifidx && ifrp->ifr_ifindex != ifidx)
136 for (ifl = ifl_list; ifl; ifl = ifl->next)
137 if (ifl->index == ifrp->ifr_ifindex)
141 int index = ifrp->ifr_ifindex;
143 if (ioctl(fd, SIOCGIFHWADDR, ifrp)) {
144 syslog(LOG_ERR, "ioctl(SIOCGIFHWADDR): %m");
148 ifl = (struct iflink*)malloc(sizeof(*ifl));
151 memset(ifl, 0, sizeof(*ifl));
152 ifl->next = ifl_list;
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, ':');
162 syslog(LOG_INFO, "link %s", ifl->name);
164 if (ioctl(fd, SIOCGIFNETMASK, ifrp)) {
165 syslog(LOG_ERR, "ioctl(SIOCGIFMASK): %m");
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");
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 &&
181 if (mask == 0 || prefix == 0)
183 ifa = (struct ifaddr*)malloc(sizeof(*ifa));
184 memset(ifa, 0, sizeof(*ifa));
186 ifa->prefix = prefix;
188 ifa->next = ifl->ifa_list;
194 for (i=32; i>=0; i--) {
195 if (htonl(m) == mask)
199 if (addr == prefix) {
200 syslog(LOG_INFO, " addr %s/%d on %s\n",
201 inet_ntoa(*(struct in_addr*)&addr), i, ifl->name);
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);
219 int bootable(__u32 addr)
225 sprintf(name, "%08X", (__u32)ntohl(addr));
226 d = opendir(tftp_dir);
228 syslog(LOG_ERR, "opendir: %m");
231 while ((dent = readdir(d)) != NULL) {
232 if (strncmp(dent->d_name, name, 8) == 0)
239 struct ifaddr *select_ipaddr(int ifindex, __u32 *sel_addr, __u32 **alist)
247 for (ifl=ifl_list; ifl; ifl=ifl->next)
248 if (ifl->index == ifindex)
250 if (ifl == NULL && !retry) {
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)) {
266 if (ifa == NULL && retry==0) {
272 if (i==1 && allow_offlink) {
273 *sel_addr = *(alist[0]);
274 return ifl->ifa_list;
276 syslog(LOG_ERR, "Off-link request on %s", ifl->name);
280 struct rarp_map *rarp_lookup(int ifindex, int hatype,
281 int halen, unsigned char *lladdr)
285 for (r=rarp_db; r; r=r->next) {
286 if (r->arp_type != hatype && r->arp_type != -1)
288 if (r->lladdr_len != halen)
290 if (r->ifindex != ifindex && r->ifindex != 0)
292 if (memcmp(r->lladdr, lladdr, halen) == 0)
297 if (hatype == ARPHRD_ETHER && halen == 6) {
301 static struct rarp_map emap = {
308 if (ether_ntohost(ename, lladdr) != 0 ||
309 (hp = gethostbyname(ename)) == NULL) {
311 syslog(LOG_INFO, "not found in /etc/ethers");
314 if (hp->h_addrtype != AF_INET) {
315 syslog(LOG_ERR, "no IP address");
318 ifa = select_ipaddr(ifindex, &emap.ipaddr, (__u32 **)hp->h_addr_list);
320 memcpy(emap.lladdr, lladdr, 6);
321 if (only_ethers || bootable(emap.ipaddr))
324 syslog(LOG_INFO, "not bootable");
331 static int load_arp_bpflet(int fd)
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),
339 static struct sock_fprog filter = {
340 sizeof insns / sizeof(insns[0]),
344 return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
347 int put_mylladdr(unsigned char **ptr_p, int ifindex, int alen)
351 for (ifl=ifl_list; ifl; ifl = ifl->next)
352 if (ifl->index == ifindex)
358 memcpy(*ptr_p, ifl->lladdr, alen);
363 int put_myipaddr(unsigned char **ptr_p, int ifindex, __u32 hisipaddr)
369 for (ifl=ifl_list; ifl; ifl = ifl->next)
370 if (ifl->index == ifindex)
376 for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) {
377 if (!((ifa->prefix^hisipaddr)&ifa->mask)) {
382 memcpy(*ptr_p, &laddr, 4);
387 void arp_advise(int ifindex, unsigned char *lladdr, int lllen, __u32 ipaddr)
391 struct sockaddr_in *sin;
394 for (ifl=ifl_list; ifl; ifl = ifl->next)
395 if (ifl->index == ifindex)
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);
411 if (ioctl(fd, SIOCSARP, &req))
412 syslog(LOG_ERR, "SIOCSARP: %m");
416 void serve_it(int fd)
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;
426 n = recvfrom(fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sll, &sll_len);
428 if (errno != EINTR && errno != EAGAIN)
429 syslog(LOG_ERR, "recvfrom: %m");
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)
439 if (ifidx && sll.sll_ifindex != ifidx)
443 syslog(LOG_ERR, "truncated arp packet; len=%d", n);
447 /* Accept only RARP requests */
448 if (a->ar_op != htons(ARPOP_RREQUEST))
455 for (i=0; i<sll.sll_halen; i++) {
457 sprintf(ptr, ":%02x", sll.sll_addr[i]);
460 sprintf(ptr, "%02x", sll.sll_addr[i]);
463 syslog(LOG_INFO, "RARP request from %s on if%d", tmpbuf, sll.sll_ifindex);
468 /* 1. IP only -> pln==4 */
469 if (a->ar_pln != 4) {
470 syslog(LOG_ERR, "interesting rarp_req plen=%d", a->ar_pln);
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));
478 /* 3. ARP types must match */
479 if (htons(sll.sll_hatype) != a->ar_hrd) {
480 switch (sll.sll_hatype) {
482 if (a->ar_hrd == htons(ARPHRD_ETHER) ||
483 a->ar_hrd == htons(ARPHRD_IEEE802))
486 syslog(LOG_ERR, "rarp htype mismatch");
490 /* 3. LL address lengths must be equal */
491 if (a->ar_hln != sll.sll_halen) {
492 syslog(LOG_ERR, "rarp hlen mismatch");
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);
500 /* 5. Silly check: if this guy set different source
501 addresses in MAC header and in ARP, he is insane
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");
507 /* End of sanity checks */
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);
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.
520 a->ar_op = htons(ARPOP_RREPLY);
521 ptr = (unsigned char*)(a+1);
522 if (put_mylladdr(&ptr, sll.sll_ifindex, rmap->lladdr_len))
524 if (put_myipaddr(&ptr, sll.sll_ifindex, rmap->ipaddr))
526 /* It is already filled */
527 ptr += rmap->lladdr_len;
528 memcpy(ptr, &rmap->ipaddr, 4);
531 /* Update our ARP cache. Probably, this guy
532 will not able to make ARP (if it is broken)
534 arp_advise(sll.sll_ifindex, rmap->lladdr, rmap->lladdr_len, rmap->ipaddr);
536 /* Sendto is blocking, but with 5sec timeout */
538 sendto(fd, buf, ptr - buf, 0, (struct sockaddr*)&sll, sizeof(sll));
542 void catch_signal(int sig, void (*handler)(int))
546 memset(&sa, 0, sizeof(sa));
547 sa.sa_handler = handler;
549 sa.sa_flags = SA_INTERRUPT;
551 sigaction(sig, &sa, NULL);
554 void sig_alarm(int signo)
558 void sig_hup(int signo)
563 int main(int argc, char **argv)
565 struct pollfd pset[2];
571 while ((opt = getopt(argc, argv, "aAb:dvoe")) != EOF) {
608 ifname = argv[optind];
612 pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
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)");
622 ifidx = ifr.ifr_ifindex;
627 pset[1].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
628 if (pset[1].fd >= 0) {
629 load_arp_bpflet(pset[1].fd);
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) {
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) {
657 if (pset[0].fd < 0) {
662 fprintf(stderr, "failed to bind any socket. Aborting.\n");
672 else if (pid == -1) {
673 perror("rarpd: fork");
678 fd = open("/dev/null", O_RDWR);
689 openlog("rarpd", LOG_PID | LOG_CONS, LOG_DAEMON);
690 catch_signal(SIGALRM, sig_alarm);
691 catch_signal(SIGHUP, sig_hup);
701 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
702 pset[0].events = EVENTS;
704 pset[1].events = EVENTS;
707 i = poll(pset, psize, -1);
709 if (errno != EINTR && i<0) {
710 syslog(LOG_ERR, "poll returned some crap: %m\n");
715 for (i=0; i<psize; i++) {
716 if (pset[i].revents&EVENTS)
717 serve_it(pset[i].fd);