/*
 *	Copyright (c) 1998 JSC Rinet, Novosibirsk, Russia
 *
 * Redistribution and use in source forms, with and without modification,
 * are permitted provided that this entire comment appears intact.
 * Redistribution in binary form may occur without any restrictions.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
 */

/* getarptab.c -- translate MAC addresses to IP addresses using ARP table */

#ifdef	HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef	HAVE_RTF_LLINFO		/* BSD systems */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>

#ifdef	ETHER_ADDR_LEN
#define	MAC_ADDR_LEN	ETHER_ADDR_LEN
#else
#define	MAC_ADDR_LEN	6
#endif

u_char *
getarptab(ep)
	u_char *ep;
{
	int mib[6];
	size_t needed;
	char *lim, *buf, *next;
	struct rt_msghdr *rtm;
	static struct sockaddr_inarp *sin;
	struct sockaddr_dl *sdl;

	mib[0] = CTL_NET;
	mib[1] = PF_ROUTE;
	mib[2] = 0;
	mib[3] = AF_INET;
	mib[4] = NET_RT_FLAGS;
	mib[5] = RTF_LLINFO;
	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
		error(1, "getarptab: sysctl");
	if ((buf = (char *)malloc(needed)) == NULL)
		error(1, "getarptab: malloc");
	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
		error(1, "getarptab: sysctl");
	lim = buf + needed;
	for (next = buf; next < lim; next += rtm->rtm_msglen) {
		rtm = (struct rt_msghdr *)next;
		sin = (struct sockaddr_inarp *)(rtm + 1);
		sdl = (struct sockaddr_dl *)(sin + 1);
		if (sdl->sdl_alen &&
		    !memcmp(ep, (u_char *)LLADDR(sdl), MAC_ADDR_LEN)) {
			free(buf);
			return ((u_char *)&sin->sin_addr);
		}
	}
	free(buf);
	return (u_char *)0;
}

#elif	HAVE_PROC_NET_ARP	/* Linux systems */

#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

u_char *
getarptab(ep)
	u_char *ep;
{
	FILE *fp;
	char *req, *ip, *mac, buf[100];
	static struct in_addr addr;

	if ((fp = fopen("/proc/net/arp", "r")) != NULL) {
		req = (char *)entoa(ep);
		while (fgets(buf, sizeof(buf), fp) != NULL) {
			buf[sizeof(buf)-1] = '\0';
			if ((ip = strtok(buf, " \t")) == NULL)
				continue;
			while ((mac = strtok(NULL, " \t")) != NULL) {
				if (!strcasecmp(req, mac)) {
					if (inet_aton(ip, &addr)) {
						(void) fclose(fp);
						return ((u_char *)&addr);
					}
					break;
				}
			}
		}
		(void) fclose(fp);
	}
	return (u_char *)0;
}

#else	/* XXX. Get ARP table not implemented yet for SYSV systems */

u_char *
getarptab(ep)
	u_char *ep;
{
	return (u_char *)0;
}

#endif


syntax highlighted by Code2HTML, v. 0.9.1