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