fbmuck-6.05/auto/
fbmuck-6.05/contrib/jresolver/
fbmuck-6.05/contrib/jresolver/org/
fbmuck-6.05/contrib/jresolver/org/fuzzball/
fbmuck-6.05/docs/devel/
fbmuck-6.05/game/
fbmuck-6.05/game/logs/
fbmuck-6.05/game/muf/
fbmuck-6.05/scripts/
fbmuck-6.05/src_docs/
#include "copyright.h"
#include "config.h"

#ifdef SOLARIS
#  ifndef _POSIX_SOURCE
#    define _POSIX_SOURCE		/* Solaris needs this */
#  endif
#endif

#include <sys/socket.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <string.h>

#ifdef USE_IPV6
# ifdef HAVE_NETINET6_IN6_H
#  include <netinet6/in6.h>
# elif defined(HAVE_LINUX_IN6_H)
#  include <linux/in6.h>
# elif defined(HAVE_IN6_H)
#  include <in6.h>
# endif
#endif

/*
 * SunOS can't include signal.h and sys/signal.h, stupid broken OS.
 */
#if defined(HAVE_SYS_SIGNAL_H) && !defined(SUN_OS)
# include <sys/signal.h>
#endif



/* number of hostnames cached in an LRU queue */
#define HOST_CACHE_SIZE 8192

/* Time before retrying to resolve a previously unresolved IP address. */
/* 1800 seconds == 30 minutes */
#define EXPIRE_TIME 1800

/* Time before the resolver gives up on a identd lookup.  Prevents hangs. */
#define IDENTD_TIMEOUT 60


int
notify(int player, const char* msg)
{
	return printf("%s\n", msg);
}

#ifdef USE_IPV6
const char *addrout(struct in6_addr *, unsigned short, unsigned short);
#else
const char *addrout(long, unsigned short, unsigned short);
#endif

#define MALLOC(result, type, number) do {   \
                                       if (!((result) = (type *) malloc ((number) * sizeof (type)))) \
                                       abort();                             \
                                     } while (0)

#define FREE(x) (free((void *) x))


struct hostcache {
#ifdef USE_IPV6
	struct in6_addr ipnum;
#else
	long ipnum;
#endif
	char name[128];
	time_t time;
	struct hostcache *next;
	struct hostcache **prev;
} *hostcache_list = 0;


#ifdef USE_IPV6
int
ipcmp(struct in6_addr *a, struct in6_addr *b)
{
	int i = 128;
	char *A = (char *) a;
	char *B = (char *) b;

	while (i) {
		i--;
		if (*A++ != *B++)
			break;
	}
	return i;
}
#endif

void
#ifdef USE_IPV6
hostdel(struct in6_addr *ip)
#else
hostdel(long ip)
#endif
{
	struct hostcache *ptr;

	for (ptr = hostcache_list; ptr; ptr = ptr->next) {
#ifdef USE_IPV6
		if (!ipcmp(&(ptr->ipnum), ip)) {
#else
		if (ptr->ipnum == ip) {
#endif
			if (ptr->next) {
				ptr->next->prev = ptr->prev;
			}
			*ptr->prev = ptr->next;
			FREE(ptr);
			return;
		}
	}
}

const char *
#ifdef USE_IPV6
hostfetch(struct in6_addr *ip)
#else
hostfetch(long ip)
#endif
{
	struct hostcache *ptr;

	for (ptr = hostcache_list; ptr; ptr = ptr->next) {
#ifdef USE_IPV6
		if (!ipcmp(&(ptr->ipnum), ip)) {
#else
		if (ptr->ipnum == ip) {
#endif
			if (time(NULL) - ptr->time > EXPIRE_TIME) {
				hostdel(ip);
				return NULL;
			}
			if (ptr != hostcache_list) {
				*ptr->prev = ptr->next;
				if (ptr->next) {
					ptr->next->prev = ptr->prev;
				}
				ptr->next = hostcache_list;
				if (ptr->next) {
					ptr->next->prev = &ptr->next;
				}
				ptr->prev = &hostcache_list;
				hostcache_list = ptr;
			}
			return (ptr->name);
		}
	}
	return NULL;
}

void
hostprune(void)
{
	struct hostcache *ptr;
	struct hostcache *tmp;
	int i = HOST_CACHE_SIZE;

	ptr = hostcache_list;
	while (i-- && ptr) {
		ptr = ptr->next;
	}
	if (i < 0 && ptr) {
		*ptr->prev = NULL;
		while (ptr) {
			tmp = ptr->next;
			FREE(ptr);
			ptr = tmp;
		}
	}
}

void
#ifdef USE_IPV6
hostadd(struct in6_addr *ip, const char *name)
#else
hostadd(long ip, const char *name)
#endif
{
	struct hostcache *ptr;

	MALLOC(ptr, struct hostcache, 1);

	ptr->next = hostcache_list;
	if (ptr->next) {
		ptr->next->prev = &ptr->next;
	}
	ptr->prev = &hostcache_list;
	hostcache_list = ptr;
#ifdef USE_IPV6
	memcpy(&(ptr->ipnum), ip, sizeof(struct in6_addr));
#else
	ptr->ipnum = ip;
#endif
	ptr->time = 0;
	strcpy(ptr->name, name);
	hostprune();
}


void
#ifdef USE_IPV6
hostadd_timestamp(struct in6_addr *ip, const char *name)
#else
hostadd_timestamp(long ip, const char *name)
#endif
{
	hostadd(ip, name);
	hostcache_list->time = time(NULL);
}








void set_signals(void);

#ifdef _POSIX_VERSION
void our_signal(int signo, void (*sighandler) (int));
#else
# define our_signal(s,f) signal((s),(f))
#endif

/*
 * our_signal(signo, sighandler)
 *
 * signo      - Signal #, see defines in signal.h
 * sighandler - The handler function desired.
 *
 * Calls sigaction() to set a signal, if we are posix.
 */
#ifdef _POSIX_VERSION
void
our_signal(int signo, void (*sighandler) (int))
{
	struct sigaction act, oact;

	act.sa_handler = sighandler;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;

	/* Restart long system calls if a signal is caught. */
#ifdef SA_RESTART
	act.sa_flags |= SA_RESTART;
#endif

	/* Make it so */
	sigaction(signo, &act, &oact);
}

#endif							/* _POSIX_VERSION */

/*
 * set_signals()
 * set_sigs_intern(bail)
 *
 * Traps a bunch of signals and reroutes them to various
 * handlers. Mostly bailout.
 *
 * If called from bailout, then reset all to default.
 *
 * Called from main() and bailout()
 */

void
set_signals(void)
{
	/* we don't care about SIGPIPE, we notice it in select() and write() */
	our_signal(SIGPIPE, SIG_IGN);

	/* didn't manage to lose that control tty, did we? Ignore it anyway. */
	our_signal(SIGHUP, SIG_IGN);
}






void
make_nonblocking(int s)
{
#if !defined(O_NONBLOCK) || defined(ULTRIX)	/* POSIX ME HARDER */
# ifdef FNDELAY					/* SUN OS */
#  define O_NONBLOCK FNDELAY
# else
#  ifdef O_NDELAY				/* SyseVil */
#   define O_NONBLOCK O_NDELAY
#  endif						/* O_NDELAY */
# endif							/* FNDELAY */
#endif

	if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
		perror("make_nonblocking: fcntl");
		abort();
	}
}


const char *
#ifdef USE_IPV6
get_username(struct in6_addr *a, int prt, int myprt)
#else
get_username(long a, int prt, int myprt)
#endif
{
	int fd, len, result;
	char *ptr, *ptr2;
	static char buf[1024];
	int lasterr;
	int timeout = IDENTD_TIMEOUT;

#ifdef USE_IPV6
	struct sockaddr_in6 addr;

	if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
#else
	struct sockaddr_in addr;

	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
#endif

		perror("resolver ident socket");
		return (0);
	}

	make_nonblocking(fd);

	len = sizeof(addr);
#ifdef USE_IPV6
	addr.sin6_family = AF_INET6;
	memcpy(&addr.sin6_addr.s6_addr, a, sizeof(struct in6_addr));

	addr.sin6_port = htons((short) 113);
#else
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = a;
	addr.sin_port = htons((short) 113);
#endif

	do {
		result = connect(fd, (struct sockaddr *) &addr, len);
		lasterr = errno;
		if (result < 0) {
			if (!timeout--)
				break;
			sleep(1);
		}
	} while (result < 0 && lasterr == EINPROGRESS);
	if (result < 0 && lasterr != EISCONN) {
		goto bad;
	}

	snprintf(buf, sizeof(buf), "%d,%d\n", prt, myprt);
	do {
		result = write(fd, buf, strlen(buf));
		lasterr = errno;
		if (result < 0) {
			if (!timeout--)
				break;
			sleep(1);
		}
	} while (result < 0 && lasterr == EAGAIN);
	if (result < 0)
		goto bad2;

	do {
		result = read(fd, buf, sizeof(buf));
		lasterr = errno;
		if (result < 0) {
			if (!timeout--)
				break;
			sleep(1);
		}
	} while (result < 0 && lasterr == EAGAIN);
	if (result < 0)
		goto bad2;

	ptr = index(buf, ':');
	if (!ptr)
		goto bad2;
	ptr++;
	if (*ptr)
		ptr++;
	if (strncmp(ptr, "USERID", 6))
		goto bad2;

	ptr = index(ptr, ':');
	if (!ptr)
		goto bad2;
	ptr = index(ptr + 1, ':');
	if (!ptr)
		goto bad2;
	ptr++;
	/* if (*ptr) ptr++; */

	shutdown(fd, 2);
	close(fd);
	if ((ptr2 = index(ptr, '\r')))
		*ptr2 = '\0';
	if (!*ptr)
		return (0);
	return ptr;

  bad2:
	shutdown(fd, 2);

  bad:
	close(fd);
	return (0);
}


/*  addrout -- Translate address 'a' from int to text.          */
const char *
#ifdef USE_IPV6
addrout(struct in6_addr *a, unsigned short prt, unsigned short myprt)
#else
addrout(long a, unsigned short prt, unsigned short myprt)
#endif
{
	static char buf[128];
	char tmpbuf[128];
	const char *ptr, *ptr2;
	struct hostent *he;

#ifdef USE_IPV6
	struct in6_addr addr;
	memcpy(&addr.s6_addr, a, sizeof(struct in6_addr));

	ptr = hostfetch(a);
#else
	struct in_addr addr;

	addr.s_addr = a;
	ptr = hostfetch(ntohl(a));
#endif

	if (ptr) {
		ptr2 = get_username(a, prt, myprt);
		if (ptr2) {
			snprintf(buf, sizeof(buf), "%s(%s)", ptr, ptr2);
		} else {
			snprintf(buf, sizeof(buf), "%s(%d)", ptr, prt);
		}
		return buf;
	}
#ifdef USE_IPV6
	he = gethostbyaddr(((char *) &addr), sizeof(addr), AF_INET6);
#else
	he = gethostbyaddr(((char *) &addr), sizeof(addr), AF_INET);
#endif

	if (he) {
		strcpy(tmpbuf, he->h_name);
#ifdef USE_IPV6
		hostadd(a, tmpbuf);
#else
		hostadd(ntohl(a), tmpbuf);
#endif
		ptr = get_username(a, prt, myprt);
		if (ptr) {
			snprintf(buf, sizeof(buf), "%s(%s)", tmpbuf, ptr);
		} else {
			snprintf(buf, sizeof(buf), "%s(%d)", tmpbuf, prt);
		}
		return buf;
	}
#ifdef USE_IPV6
	inet_ntop(AF_INET6, a, tmpbuf, 128);
	hostadd_timestamp(a, tmpbuf);
	ptr = get_username(a, prt, myprt);
#else

	a = ntohl(a);
	snprintf(tmpbuf, sizeof(tmpbuf), "%ld.%ld.%ld.%ld",
			(a >> 24) & 0xff, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff);
	hostadd_timestamp(a, tmpbuf);
	ptr = get_username(htonl(a), prt, myprt);
#endif

	if (ptr) {
		snprintf(buf, sizeof(buf), "%s(%s)", tmpbuf, ptr);
	} else {
		snprintf(buf, sizeof(buf), "%s(%d)", tmpbuf, prt);
	}
	return buf;
}


#define erreturn { \
                     return 0; \
		 }


int
do_resolve(void)
{
	int ip1, ip2, ip3, ip4;
	int prt, myprt;
	int doagain;
	char *result;
	const char *ptr;
	char buf[1024];

#ifdef USE_IPV6
	char ipv6addr[128];
	struct in6_addr fullip;
	char *bufptr;
#else
	long fullip;
#endif

	ip1 = ip2 = ip3 = ip4 = prt = myprt = -1;
	do {
		doagain = 0;
		*buf = '\0';
		result = fgets(buf, sizeof(buf), stdin);
		if (!result) {
			if (errno == EAGAIN) {
				doagain = 1;
				sleep(1);
			} else {
				if (feof(stdin))
					erreturn;
				perror("fgets");
				erreturn;
			}
		}
	} while (doagain || !strcmp(buf, "\n"));

#ifdef USE_IPV6
	bufptr = strchr(buf, '(');
	if (!bufptr)
		erreturn;
	sscanf(bufptr, "(%d)%d", &prt, &myprt);
	*bufptr = '\0';
	if (myprt > 65535 || myprt < 0)
		erreturn;
	if (inet_pton(AF_INET6, buf, &fullip) <= 0)
		erreturn;
	ptr = addrout(&fullip, prt, myprt);
	printf("%s(%d)|%s\n", buf, prt, ptr);
#else
	sscanf(buf, "%d.%d.%d.%d(%d)%d", &ip1, &ip2, &ip3, &ip4, &prt, &myprt);
	if (ip1 < 0 || ip2 < 0 || ip3 < 0 || ip4 < 0 || prt < 0)
		erreturn;
	if (ip1 > 255 || ip2 > 255 || ip3 > 255 || ip4 > 255 || prt > 65535)
		erreturn;
	if (myprt > 65535 || myprt < 0)
		erreturn;

	fullip = (ip1 << 24) | (ip2 << 16) | (ip3 << 8) | ip4;
	fullip = htonl(fullip);

	ptr = addrout(fullip, prt, myprt);
	printf("%d.%d.%d.%d(%d):%s\n", ip1, ip2, ip3, ip4, prt, ptr);
#endif
	fflush(stdout);
	return 1;
}




int
main(int argc, char **argv)
{
	if (argc > 1) {
		fprintf(stderr, "Usage: %s\n", *argv);
		exit(1);
		return 1;
	}

	/* remember to ignore certain signals */
	set_signals();

	/* go do it */
	while (do_resolve()) ;
	fprintf(stderr, "Resolver exited.\n");

	exit(0);
	return 0;
}