Blame rarpd.c

Packit Service 6f2e62
/*
Packit Service 6f2e62
 * rarpd.c	RARP daemon.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 *		This program is free software; you can redistribute it and/or
Packit Service 6f2e62
 *		modify it under the terms of the GNU General Public License
Packit Service 6f2e62
 *		as published by the Free Software Foundation; either version
Packit Service 6f2e62
 *		2 of the License, or (at your option) any later version.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
Packit Service 6f2e62
 */
Packit Service 6f2e62
Packit Service 6f2e62
#include <stdio.h>
Packit Service 6f2e62
#include <syslog.h>
Packit Service 6f2e62
#include <dirent.h>
Packit Service 6f2e62
#include <malloc.h>
Packit Service 6f2e62
#include <string.h>
Packit Service 6f2e62
#include <unistd.h>
Packit Service 6f2e62
#include <stdlib.h>
Packit Service 6f2e62
#include <netdb.h>
Packit Service 6f2e62
#include <errno.h>
Packit Service 6f2e62
#include <fcntl.h>
Packit Service 6f2e62
#include <signal.h>
Packit Service 6f2e62
#include <poll.h>
Packit Service 6f2e62
#include <arpa/inet.h>
Packit Service 6f2e62
#include <netinet/in.h>
Packit Service 6f2e62
#include <linux/if.h>
Packit Service 6f2e62
#include <linux/if_arp.h>
Packit Service 6f2e62
#include <linux/if_packet.h>
Packit Service 6f2e62
#include <linux/filter.h>
Packit Service 6f2e62
#include <sys/ioctl.h>
Packit Service 6f2e62
#include <sys/socket.h>
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
int do_reload = 1;
Packit Service 6f2e62
Packit Service 6f2e62
int debug;
Packit Service 6f2e62
int verbose;
Packit Service 6f2e62
int ifidx;
Packit Service 6f2e62
int allow_offlink;
Packit Service 6f2e62
int only_ethers;
Packit Service 6f2e62
int all_ifaces;
Packit Service 6f2e62
int listen_arp;
Packit Service 6f2e62
char *ifname;
Packit Service 6f2e62
char *tftp_dir = "/etc/tftpboot";
Packit Service 6f2e62
Packit Service 6f2e62
extern int ether_ntohost(char *name, unsigned char *ea);
Packit Service 6f2e62
void usage(void) __attribute__((noreturn));
Packit Service 6f2e62
Packit Service 6f2e62
struct iflink
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct iflink	*next;
Packit Service 6f2e62
	int	       	index;
Packit Service 6f2e62
	int		hatype;
Packit Service 6f2e62
	unsigned char	lladdr[16];
Packit Service 6f2e62
	char		name[IFNAMSIZ];
Packit Service 6f2e62
	struct ifaddr 	*ifa_list;
Packit Service 6f2e62
} *ifl_list;
Packit Service 6f2e62
Packit Service 6f2e62
struct ifaddr
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct ifaddr 	*next;
Packit Service 6f2e62
	__u32		prefix;
Packit Service 6f2e62
	__u32		mask;
Packit Service 6f2e62
	__u32		local;
Packit Service 6f2e62
};
Packit Service 6f2e62
Packit Service 6f2e62
struct rarp_map
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct rarp_map *next;
Packit Service 6f2e62
Packit Service 6f2e62
	int		ifindex;
Packit Service 6f2e62
	int		arp_type;
Packit Service 6f2e62
	int		lladdr_len;
Packit Service 6f2e62
	unsigned char	lladdr[16];
Packit Service 6f2e62
	__u32		ipaddr;
Packit Service 6f2e62
} *rarp_db;
Packit Service 6f2e62
Packit Service 6f2e62
void usage()
Packit Service 6f2e62
{
Packit Service 6f2e62
	fprintf(stderr, "Usage: rarpd [ -dveaA ] [ -b tftpdir ] [ interface]\n");
Packit Service 6f2e62
	exit(1);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void load_db(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void load_if(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int fd;
Packit Service 6f2e62
	struct ifreq *ifrp, *ifend;
Packit Service 6f2e62
	struct iflink *ifl;
Packit Service 6f2e62
	struct ifaddr *ifa;
Packit Service 6f2e62
	struct ifconf ifc;
Packit Service 6f2e62
	struct ifreq ibuf[256];
Packit Service 6f2e62
Packit Service 6f2e62
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Packit Service 6f2e62
		syslog(LOG_ERR, "socket: %m");
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	ifc.ifc_len = sizeof ibuf;
Packit Service 6f2e62
	ifc.ifc_buf = (char *)ibuf;
Packit Service 6f2e62
	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
Packit Service 6f2e62
	    ifc.ifc_len < (int)sizeof(struct ifreq)) {
Packit Service 6f2e62
		syslog(LOG_ERR, "SIOCGIFCONF: %m");
Packit Service 6f2e62
		close(fd);
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	while ((ifl = ifl_list) != NULL) {
Packit Service 6f2e62
		while ((ifa = ifl->ifa_list) != NULL) {
Packit Service 6f2e62
			ifl->ifa_list = ifa->next;
Packit Service 6f2e62
			free(ifa);
Packit Service 6f2e62
		}
Packit Service 6f2e62
		ifl_list = ifl->next;
Packit Service 6f2e62
		free(ifl);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
Packit Service 6f2e62
	for (ifrp = ibuf; ifrp < ifend; ifrp++) {
Packit Service 6f2e62
		__u32 addr;
Packit Service 6f2e62
		__u32 mask;
Packit Service 6f2e62
		__u32 prefix;
Packit Service 6f2e62
Packit Service 6f2e62
		if (ifrp->ifr_addr.sa_family != AF_INET)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		addr = ((struct sockaddr_in*)&ifrp->ifr_addr)->sin_addr.s_addr;
Packit Service 6f2e62
		if (addr == 0)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		if (ioctl(fd, SIOCGIFINDEX, ifrp)) {
Packit Service 6f2e62
			syslog(LOG_ERR, "ioctl(SIOCGIFNAME): %m");
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (ifidx && ifrp->ifr_ifindex != ifidx)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		for (ifl = ifl_list; ifl; ifl = ifl->next)
Packit Service 6f2e62
			if (ifl->index == ifrp->ifr_ifindex)
Packit Service 6f2e62
				break;
Packit Service 6f2e62
		if (ifl == NULL) {
Packit Service 6f2e62
			char *p;
Packit Service 6f2e62
			int index = ifrp->ifr_ifindex;
Packit Service 6f2e62
Packit Service 6f2e62
			if (ioctl(fd, SIOCGIFHWADDR, ifrp)) {
Packit Service 6f2e62
				syslog(LOG_ERR, "ioctl(SIOCGIFHWADDR): %m");
Packit Service 6f2e62
				continue;
Packit Service 6f2e62
			}
Packit Service 6f2e62
Packit Service 6f2e62
			ifl = (struct iflink*)malloc(sizeof(*ifl));
Packit Service 6f2e62
			if (ifl == NULL)
Packit Service 6f2e62
				continue;
Packit Service 6f2e62
			memset(ifl, 0, sizeof(*ifl));
Packit Service 6f2e62
			ifl->next = ifl_list;
Packit Service 6f2e62
			ifl_list = ifl;
Packit Service 6f2e62
			ifl->index = index;
Packit Service 6f2e62
			ifl->hatype = ifrp->ifr_hwaddr.sa_family;
Packit Service 6f2e62
			memcpy(ifl->lladdr, ifrp->ifr_hwaddr.sa_data, 14);
Packit Service 6f2e62
			strncpy(ifl->name, ifrp->ifr_name, IFNAMSIZ);
Packit Service 6f2e62
			p = strchr(ifl->name, ':');
Packit Service 6f2e62
			if (p)
Packit Service 6f2e62
				*p = 0;
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				syslog(LOG_INFO, "link %s", ifl->name);
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (ioctl(fd, SIOCGIFNETMASK, ifrp)) {
Packit Service 6f2e62
			syslog(LOG_ERR, "ioctl(SIOCGIFMASK): %m");
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		mask = ((struct sockaddr_in*)&ifrp->ifr_netmask)->sin_addr.s_addr;
Packit Service 6f2e62
		if (ioctl(fd, SIOCGIFDSTADDR, ifrp)) {
Packit Service 6f2e62
			syslog(LOG_ERR, "ioctl(SIOCGIFDSTADDR): %m");
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		prefix = ((struct sockaddr_in*)&ifrp->ifr_dstaddr)->sin_addr.s_addr;
Packit Service 6f2e62
		for (ifa = ifl->ifa_list; ifa; ifa = ifa->next) {
Packit Service 6f2e62
			if (ifa->local == addr &&
Packit Service 6f2e62
			    ifa->prefix == prefix &&
Packit Service 6f2e62
			    ifa->mask == mask)
Packit Service 6f2e62
				break;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (ifa == NULL) {
Packit Service 6f2e62
			if (mask == 0 || prefix == 0)
Packit Service 6f2e62
				continue;
Packit Service 6f2e62
			ifa = (struct ifaddr*)malloc(sizeof(*ifa));
Packit Service 6f2e62
			memset(ifa, 0, sizeof(*ifa));
Packit Service 6f2e62
			ifa->local = addr;
Packit Service 6f2e62
			ifa->prefix = prefix;
Packit Service 6f2e62
			ifa->mask = mask;
Packit Service 6f2e62
			ifa->next = ifl->ifa_list;
Packit Service 6f2e62
			ifl->ifa_list = ifa;
Packit Service 6f2e62
Packit Service 6f2e62
			if (verbose) {
Packit Service 6f2e62
				int i;
Packit Service 6f2e62
				__u32 m = ~0U;
Packit Service 6f2e62
				for (i=32; i>=0; i--) {
Packit Service 6f2e62
					if (htonl(m) == mask)
Packit Service 6f2e62
						break;
Packit Service 6f2e62
					m <<= 1;
Packit Service 6f2e62
				}
Packit Service 6f2e62
				if (addr == prefix) {
Packit Service 6f2e62
					syslog(LOG_INFO, "  addr %s/%d on %s\n",
Packit Service 6f2e62
					       inet_ntoa(*(struct in_addr*)&addr), i, ifl->name);
Packit Service 6f2e62
				} else {
Packit Service 6f2e62
					char tmpa[64];
Packit Service 6f2e62
					sprintf(tmpa, "%s", inet_ntoa(*(struct in_addr*)&addr));
Packit Service 6f2e62
					syslog(LOG_INFO, "  addr %s %s/%d on %s\n", tmpa,
Packit Service 6f2e62
					       inet_ntoa(*(struct in_addr*)&prefix), i, ifl->name);
Packit Service 6f2e62
				}
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void configure(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	load_if();
Packit Service 6f2e62
	load_db();
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int bootable(__u32 addr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct dirent *dent;
Packit Service 6f2e62
	DIR *d;
Packit Service 6f2e62
	char name[9];
Packit Service 6f2e62
Packit Service 6f2e62
	sprintf(name, "%08X", (__u32)ntohl(addr));
Packit Service 6f2e62
	d = opendir(tftp_dir);
Packit Service 6f2e62
	if (d == NULL) {
Packit Service 6f2e62
		syslog(LOG_ERR, "opendir: %m");
Packit Service 6f2e62
		return 0;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	while ((dent = readdir(d)) != NULL) {
Packit Service 6f2e62
		if (strncmp(dent->d_name, name, 8) == 0)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	closedir(d);
Packit Service 6f2e62
	return dent != NULL;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
struct ifaddr *select_ipaddr(int ifindex, __u32 *sel_addr, __u32 **alist)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct iflink *ifl;
Packit Service 6f2e62
	struct ifaddr *ifa;
Packit Service 6f2e62
	int retry = 0;
Packit Service 6f2e62
	int i;
Packit Service 6f2e62
Packit Service 6f2e62
retry:
Packit Service 6f2e62
	for (ifl=ifl_list; ifl; ifl=ifl->next)
Packit Service 6f2e62
		if (ifl->index == ifindex)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
	if (ifl == NULL && !retry) {
Packit Service 6f2e62
		retry++;
Packit Service 6f2e62
		load_if();
Packit Service 6f2e62
		goto retry;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (ifl == NULL)
Packit Service 6f2e62
		return NULL;
Packit Service 6f2e62
Packit Service 6f2e62
	for (i=0; alist[i]; i++) {
Packit Service 6f2e62
		__u32 addr = *(alist[i]);
Packit Service 6f2e62
		for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) {
Packit Service 6f2e62
			if (!((ifa->prefix^addr)&ifa->mask)) {
Packit Service 6f2e62
				*sel_addr = addr;
Packit Service 6f2e62
				return ifa;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (ifa == NULL && retry==0) {
Packit Service 6f2e62
			retry++;
Packit Service 6f2e62
			load_if();
Packit Service 6f2e62
			goto retry;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (i==1 && allow_offlink) {
Packit Service 6f2e62
		*sel_addr = *(alist[0]);
Packit Service 6f2e62
		return ifl->ifa_list;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	syslog(LOG_ERR, "Off-link request on %s", ifl->name);
Packit Service 6f2e62
	return NULL;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
struct rarp_map *rarp_lookup(int ifindex, int hatype,
Packit Service 6f2e62
			     int halen, unsigned char *lladdr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct rarp_map *r;
Packit Service 6f2e62
Packit Service 6f2e62
	for (r=rarp_db; r; r=r->next) {
Packit Service 6f2e62
		if (r->arp_type != hatype && r->arp_type != -1)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		if (r->lladdr_len != halen)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		if (r->ifindex != ifindex && r->ifindex != 0)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		if (memcmp(r->lladdr, lladdr, halen) == 0)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (r == NULL) {
Packit Service 6f2e62
		if (hatype == ARPHRD_ETHER && halen == 6) {
Packit Service 6f2e62
			struct ifaddr *ifa;
Packit Service 6f2e62
			struct hostent *hp;
Packit Service 6f2e62
			char ename[256];
Packit Service 6f2e62
			static struct rarp_map emap = {
Packit Service 6f2e62
				NULL,
Packit Service 6f2e62
				0,
Packit Service 6f2e62
				ARPHRD_ETHER,
Packit Service 6f2e62
				6,
Packit Service 6f2e62
			};
Packit Service 6f2e62
Packit Service 6f2e62
			if (ether_ntohost(ename, lladdr) != 0 ||
Packit Service 6f2e62
			    (hp = gethostbyname(ename)) == NULL) {
Packit Service 6f2e62
				if (verbose)
Packit Service 6f2e62
					syslog(LOG_INFO, "not found in /etc/ethers");
Packit Service 6f2e62
				return NULL;
Packit Service 6f2e62
			}
Packit Service 6f2e62
			if (hp->h_addrtype != AF_INET) {
Packit Service 6f2e62
				syslog(LOG_ERR, "no IP address");
Packit Service 6f2e62
				return NULL;
Packit Service 6f2e62
			}
Packit Service 6f2e62
			ifa = select_ipaddr(ifindex, &emap.ipaddr, (__u32 **)hp->h_addr_list);
Packit Service 6f2e62
			if (ifa) {
Packit Service 6f2e62
				memcpy(emap.lladdr, lladdr, 6);
Packit Service 6f2e62
				if (only_ethers || bootable(emap.ipaddr))
Packit Service 6f2e62
					return &emap;
Packit Service 6f2e62
				if (verbose)
Packit Service 6f2e62
					syslog(LOG_INFO, "not bootable");
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return r;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
static int load_arp_bpflet(int fd)
Packit Service 6f2e62
{
Packit Service 6f2e62
	static struct sock_filter insns[] = {
Packit Service 6f2e62
		BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
Packit Service 6f2e62
		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ARPOP_RREQUEST, 0, 1),
Packit Service 6f2e62
		BPF_STMT(BPF_RET|BPF_K, 1024),
Packit Service 6f2e62
		BPF_STMT(BPF_RET|BPF_K, 0),
Packit Service 6f2e62
	};
Packit Service 6f2e62
	static struct sock_fprog filter = {
Packit Service 6f2e62
		sizeof insns / sizeof(insns[0]),
Packit Service 6f2e62
		insns
Packit Service 6f2e62
	};
Packit Service 6f2e62
Packit Service 6f2e62
	return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int put_mylladdr(unsigned char **ptr_p, int ifindex, int alen)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct iflink *ifl;
Packit Service 6f2e62
Packit Service 6f2e62
	for (ifl=ifl_list; ifl; ifl = ifl->next)
Packit Service 6f2e62
		if (ifl->index == ifindex)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
	if (ifl==NULL)
Packit Service 6f2e62
		return -1;
Packit Service 6f2e62
Packit Service 6f2e62
	memcpy(*ptr_p, ifl->lladdr, alen);
Packit Service 6f2e62
	*ptr_p += alen;
Packit Service 6f2e62
	return 0;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int put_myipaddr(unsigned char **ptr_p, int ifindex, __u32 hisipaddr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	__u32 laddr = 0;
Packit Service 6f2e62
	struct iflink *ifl;
Packit Service 6f2e62
	struct ifaddr *ifa;
Packit Service 6f2e62
Packit Service 6f2e62
	for (ifl=ifl_list; ifl; ifl = ifl->next)
Packit Service 6f2e62
		if (ifl->index == ifindex)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
	if (ifl==NULL)
Packit Service 6f2e62
		return -1;
Packit Service 6f2e62
Packit Service 6f2e62
	for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) {
Packit Service 6f2e62
		if (!((ifa->prefix^hisipaddr)&ifa->mask)) {
Packit Service 6f2e62
			laddr = ifa->local;
Packit Service 6f2e62
			break;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	memcpy(*ptr_p, &laddr, 4);
Packit Service 6f2e62
	*ptr_p += 4;
Packit Service 6f2e62
	return 0;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void arp_advise(int ifindex, unsigned char *lladdr, int lllen, __u32 ipaddr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int fd;
Packit Service 6f2e62
	struct arpreq req;
Packit Service 6f2e62
	struct sockaddr_in *sin;
Packit Service 6f2e62
	struct iflink *ifl;
Packit Service 6f2e62
Packit Service 6f2e62
	for (ifl=ifl_list; ifl; ifl = ifl->next)
Packit Service 6f2e62
		if (ifl->index == ifindex)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
	if (ifl == NULL)
Packit Service 6f2e62
		return;
Packit Service 6f2e62
Packit Service 6f2e62
	fd = socket(AF_INET, SOCK_DGRAM, 0);
Packit Service 6f2e62
	memset(&req, 0, sizeof(req));
Packit Service 6f2e62
	req.arp_flags = ATF_COM;
Packit Service 6f2e62
	sin = (struct sockaddr_in *)&req.arp_pa;
Packit Service 6f2e62
	sin->sin_family = AF_INET;
Packit Service 6f2e62
	sin->sin_addr.s_addr = ipaddr;
Packit Service 6f2e62
	req.arp_ha.sa_family = ifl->hatype;
Packit Service 6f2e62
	memcpy(req.arp_ha.sa_data, lladdr, lllen);
Packit Service 6f2e62
	memcpy(req.arp_dev, ifl->name, IFNAMSIZ);
Packit Service 6f2e62
Packit Service 6f2e62
	if (ioctl(fd, SIOCSARP, &req))
Packit Service 6f2e62
		syslog(LOG_ERR, "SIOCSARP: %m");
Packit Service 6f2e62
	close(fd);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void serve_it(int fd)
Packit Service 6f2e62
{
Packit Service 6f2e62
	unsigned char buf[1024];
Packit Service 6f2e62
	struct sockaddr_ll sll;
Packit Service 6f2e62
	socklen_t sll_len = sizeof(sll);
Packit Service 6f2e62
	struct arphdr *a = (struct arphdr*)buf;
Packit Service 6f2e62
	struct rarp_map *rmap;
Packit Service 6f2e62
	unsigned char *ptr;
Packit Service 6f2e62
	int n;
Packit Service 6f2e62
Packit Service 6f2e62
	n = recvfrom(fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sll, &sll_len);
Packit Service 6f2e62
	if (n<0) {
Packit Service 6f2e62
		if (errno != EINTR && errno != EAGAIN)
Packit Service 6f2e62
			syslog(LOG_ERR, "recvfrom: %m");
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	/* Do not accept packets for other hosts and our own ones */
Packit Service 6f2e62
	if (sll.sll_pkttype != PACKET_BROADCAST &&
Packit Service 6f2e62
	    sll.sll_pkttype != PACKET_MULTICAST &&
Packit Service 6f2e62
	    sll.sll_pkttype != PACKET_HOST)
Packit Service 6f2e62
		return;
Packit Service 6f2e62
Packit Service 6f2e62
	if (ifidx && sll.sll_ifindex != ifidx)
Packit Service 6f2e62
		return;
Packit Service 6f2e62
Packit Service 6f2e62
	if (n
Packit Service 6f2e62
		syslog(LOG_ERR, "truncated arp packet; len=%d", n);
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	/* Accept only RARP requests */
Packit Service 6f2e62
	if (a->ar_op != htons(ARPOP_RREQUEST))
Packit Service 6f2e62
		return;
Packit Service 6f2e62
Packit Service 6f2e62
	if (verbose) {
Packit Service 6f2e62
		int i;
Packit Service 6f2e62
		char tmpbuf[16*3];
Packit Service 6f2e62
		char *ptr = tmpbuf;
Packit Service 6f2e62
		for (i=0; i
Packit Service 6f2e62
			if (i) {
Packit Service 6f2e62
				sprintf(ptr, ":%02x", sll.sll_addr[i]);
Packit Service 6f2e62
				ptr++;
Packit Service 6f2e62
			} else
Packit Service 6f2e62
				sprintf(ptr, "%02x", sll.sll_addr[i]);
Packit Service 6f2e62
			ptr += 2;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		syslog(LOG_INFO, "RARP request from %s on if%d", tmpbuf, sll.sll_ifindex);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	/* Sanity checks */
Packit Service 6f2e62
Packit Service 6f2e62
	/* 1. IP only -> pln==4 */
Packit Service 6f2e62
	if (a->ar_pln != 4) {
Packit Service 6f2e62
		syslog(LOG_ERR, "interesting rarp_req plen=%d", a->ar_pln);
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	/* 2. ARP protocol must be IP */
Packit Service 6f2e62
	if (a->ar_pro != htons(ETH_P_IP)) {
Packit Service 6f2e62
		syslog(LOG_ERR, "rarp protocol is not IP %04x", ntohs(a->ar_pro));
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	/* 3. ARP types must match */
Packit Service 6f2e62
	if (htons(sll.sll_hatype) != a->ar_hrd) {
Packit Service 6f2e62
		switch (sll.sll_hatype) {
Packit Service 6f2e62
		case ARPHRD_FDDI:
Packit Service 6f2e62
			if (a->ar_hrd == htons(ARPHRD_ETHER) ||
Packit Service 6f2e62
			    a->ar_hrd == htons(ARPHRD_IEEE802))
Packit Service 6f2e62
				break;
Packit Service 6f2e62
		default:
Packit Service 6f2e62
			syslog(LOG_ERR, "rarp htype mismatch");
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	/* 3. LL address lengths must be equal */
Packit Service 6f2e62
	if (a->ar_hln != sll.sll_halen) {
Packit Service 6f2e62
		syslog(LOG_ERR, "rarp hlen mismatch");
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	/* 4. Check packet length */
Packit Service 6f2e62
	if (sizeof(*a) + 2*4 + 2*a->ar_hln > n) {
Packit Service 6f2e62
		syslog(LOG_ERR, "truncated rarp request; len=%d", n);
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	/* 5. Silly check: if this guy set different source
Packit Service 6f2e62
	      addresses in MAC header and in ARP, he is insane
Packit Service 6f2e62
	 */
Packit Service 6f2e62
	if (memcmp(sll.sll_addr, a+1, sll.sll_halen)) {
Packit Service 6f2e62
		syslog(LOG_ERR, "this guy set different his lladdrs in arp and header");
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	/* End of sanity checks */
Packit Service 6f2e62
Packit Service 6f2e62
	/* Lookup requested target in our database */
Packit Service 6f2e62
	rmap = rarp_lookup(sll.sll_ifindex, sll.sll_hatype,
Packit Service 6f2e62
			   sll.sll_halen, (unsigned char*)(a+1) + sll.sll_halen + 4);
Packit Service 6f2e62
	if (rmap == NULL)
Packit Service 6f2e62
		return;
Packit Service 6f2e62
Packit Service 6f2e62
	/* Prepare reply. It is almost ready, we only
Packit Service 6f2e62
	   replace ARP packet type, put our lladdr and
Packit Service 6f2e62
	   IP address to source fileds,
Packit Service 6f2e62
	   and fill target IP address.
Packit Service 6f2e62
	 */
Packit Service 6f2e62
	a->ar_op = htons(ARPOP_RREPLY);
Packit Service 6f2e62
	ptr = (unsigned char*)(a+1);
Packit Service 6f2e62
	if (put_mylladdr(&ptr, sll.sll_ifindex, rmap->lladdr_len))
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	if (put_myipaddr(&ptr, sll.sll_ifindex, rmap->ipaddr))
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	/* It is already filled */
Packit Service 6f2e62
	ptr += rmap->lladdr_len;
Packit Service 6f2e62
	memcpy(ptr, &rmap->ipaddr, 4);
Packit Service 6f2e62
	ptr += 4;
Packit Service 6f2e62
Packit Service 6f2e62
	/* Update our ARP cache. Probably, this guy
Packit Service 6f2e62
	   will not able to make ARP (if it is broken)
Packit Service 6f2e62
	 */
Packit Service 6f2e62
	arp_advise(sll.sll_ifindex, rmap->lladdr, rmap->lladdr_len, rmap->ipaddr);
Packit Service 6f2e62
Packit Service 6f2e62
	/* Sendto is blocking, but with 5sec timeout */
Packit Service 6f2e62
	alarm(5);
Packit Service 6f2e62
	sendto(fd, buf, ptr - buf, 0, (struct sockaddr*)&sll, sizeof(sll));
Packit Service 6f2e62
	alarm(0);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void catch_signal(int sig, void (*handler)(int))
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct sigaction sa;
Packit Service 6f2e62
Packit Service 6f2e62
	memset(&sa, 0, sizeof(sa));
Packit Service 6f2e62
	sa.sa_handler = handler;
Packit Service 6f2e62
#ifdef SA_INTERRUPT
Packit Service 6f2e62
	sa.sa_flags = SA_INTERRUPT;
Packit Service 6f2e62
#endif
Packit Service 6f2e62
	sigaction(sig, &sa, NULL);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void sig_alarm(int signo)
Packit Service 6f2e62
{
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void sig_hup(int signo)
Packit Service 6f2e62
{
Packit Service 6f2e62
	do_reload = 1;
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int main(int argc, char **argv)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct pollfd pset[2];
Packit Service 6f2e62
	int psize;
Packit Service 6f2e62
	int opt;
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
	opterr = 0;
Packit Service 6f2e62
	while ((opt = getopt(argc, argv, "aAb:dvoe")) != EOF) {
Packit Service 6f2e62
		switch (opt) {
Packit Service 6f2e62
		case 'a':
Packit Service 6f2e62
			++all_ifaces;
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
		case 'A':
Packit Service 6f2e62
			++listen_arp;
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
		case 'd':
Packit Service 6f2e62
			++debug;
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
		case 'v':
Packit Service 6f2e62
			++verbose;
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
		case 'o':
Packit Service 6f2e62
			++allow_offlink;
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
		case 'e':
Packit Service 6f2e62
			++only_ethers;
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
		case 'b':
Packit Service 6f2e62
			tftp_dir = optarg;
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
		default:
Packit Service 6f2e62
			usage();
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (argc > optind) {
Packit Service 6f2e62
		if (argc > optind+1)
Packit Service 6f2e62
			usage();
Packit Service 6f2e62
		ifname = argv[optind];
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	psize = 1;
Packit Service 6f2e62
	pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
Packit Service 6f2e62
Packit Service 6f2e62
	if (ifname) {
Packit Service 6f2e62
		struct ifreq ifr;
Packit Service 6f2e62
		memset(&ifr, 0, sizeof(ifr));
Packit Service 6f2e62
		strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
Packit Service 6f2e62
		if (ioctl(pset[0].fd, SIOCGIFINDEX, &ifr)) {
Packit Service 6f2e62
			perror("ioctl(SIOCGIFINDEX)");
Packit Service 6f2e62
			usage();
Packit Service 6f2e62
		}
Packit Service 6f2e62
		ifidx = ifr.ifr_ifindex;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	pset[1].fd = -1;
Packit Service 6f2e62
	if (listen_arp) {
Packit Service 6f2e62
		pset[1].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
Packit Service 6f2e62
		if (pset[1].fd >= 0) {
Packit Service 6f2e62
			load_arp_bpflet(pset[1].fd);
Packit Service 6f2e62
			psize = 1;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (pset[1].fd >= 0) {
Packit Service 6f2e62
		struct sockaddr_ll sll;
Packit Service 6f2e62
		memset(&sll, 0, sizeof(sll));
Packit Service 6f2e62
		sll.sll_family = AF_PACKET;
Packit Service 6f2e62
		sll.sll_protocol = htons(ETH_P_ARP);
Packit Service 6f2e62
		sll.sll_ifindex = all_ifaces ? 0 : ifidx;
Packit Service 6f2e62
		if (bind(pset[1].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
Packit Service 6f2e62
			close(pset[1].fd);
Packit Service 6f2e62
			pset[1].fd = -1;
Packit Service 6f2e62
			psize = 1;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (pset[0].fd >= 0) {
Packit Service 6f2e62
		struct sockaddr_ll sll;
Packit Service 6f2e62
		memset(&sll, 0, sizeof(sll));
Packit Service 6f2e62
		sll.sll_family = AF_PACKET;
Packit Service 6f2e62
		sll.sll_protocol = htons(ETH_P_RARP);
Packit Service 6f2e62
		sll.sll_ifindex = all_ifaces ? 0 : ifidx;
Packit Service 6f2e62
		if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
Packit Service 6f2e62
			close(pset[0].fd);
Packit Service 6f2e62
			pset[0].fd = -1;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (pset[0].fd < 0) {
Packit Service 6f2e62
		pset[0] = pset[1];
Packit Service 6f2e62
		psize--;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (psize == 0) {
Packit Service 6f2e62
		fprintf(stderr, "failed to bind any socket. Aborting.\n");
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (!debug) {
Packit Service 6f2e62
		int fd;
Packit Service 6f2e62
		pid_t pid = fork();
Packit Service 6f2e62
Packit Service 6f2e62
		if (pid > 0)
Packit Service 6f2e62
			exit(0);
Packit Service 6f2e62
		else if (pid == -1) {
Packit Service 6f2e62
			perror("rarpd: fork");
Packit Service 6f2e62
			exit(1);
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		if (chdir("/") < 0) {
Packit Service 6f2e62
			perror("rarpd: chdir");
Packit Service 6f2e62
			exit(1);
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		fd = open("/dev/null", O_RDWR);
Packit Service 6f2e62
		if (fd >= 0) {
Packit Service 6f2e62
			dup2(fd, 0);
Packit Service 6f2e62
			dup2(fd, 1);
Packit Service 6f2e62
			dup2(fd, 2);
Packit Service 6f2e62
			if (fd > 2)
Packit Service 6f2e62
				close(fd);
Packit Service 6f2e62
		}
Packit Service 6f2e62
		setsid();
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	openlog("rarpd", LOG_PID | LOG_CONS, LOG_DAEMON);
Packit Service 6f2e62
	catch_signal(SIGALRM, sig_alarm);
Packit Service 6f2e62
	catch_signal(SIGHUP, sig_hup);
Packit Service 6f2e62
Packit Service 6f2e62
	for (;;) {
Packit Service 6f2e62
		int i;
Packit Service 6f2e62
Packit Service 6f2e62
		if (do_reload) {
Packit Service 6f2e62
			configure();
Packit Service 6f2e62
			do_reload = 0;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
#define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
Packit Service 6f2e62
		pset[0].events = EVENTS;
Packit Service 6f2e62
		pset[0].revents = 0;
Packit Service 6f2e62
		pset[1].events = EVENTS;
Packit Service 6f2e62
		pset[1].revents = 0;
Packit Service 6f2e62
Packit Service 6f2e62
		i = poll(pset, psize, -1);
Packit Service 6f2e62
		if (i <= 0) {
Packit Service 6f2e62
			if (errno != EINTR && i<0) {
Packit Service 6f2e62
				syslog(LOG_ERR, "poll returned some crap: %m\n");
Packit Service 6f2e62
				sleep(10);
Packit Service 6f2e62
			}
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		for (i=0; i
Packit Service 6f2e62
			if (pset[i].revents&EVENTS)
Packit Service 6f2e62
				serve_it(pset[i].fd);
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
}