#ifndef lint
static char *RCSid = "$Header: /usr/src/ecn/getethers/RCS/main.c,v 1.4 92/05/08 14:15:59 davy Exp $";
#endif
/*
 * getethers - get hostname/ethernet address information for all hosts on
 *	       an ethernet.
 *
 * David A. Curry
 * Purdue University
 * Engineering Computer Network
 * davy@ecn.purdue.edu
 * November, 1991
 *
 * $Log:	main.c,v $
 * Revision 1.4  92/05/08  14:15:59  davy
 * Made portable to 4.3BSD, from Peter Shipley (shipley@tfs.com).
 * 
 * Revision 1.3  92/05/08  13:06:38  davy
 * Added vendor name printing from Peter Shipley (shipley@tfs.com).
 * 
 * Revision 1.2  92/05/08  09:27:48  davy
 * Added changes to dump Sniffer format files from Ric Anderson,
 * ric@cs.arizona.edu.
 * 
 * Revision 1.1  91/11/27  10:56:32  davy
 * Initial revision
 * 
 */
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include "defs.h"

char	*pname;
int	analyzer_type,
	verbose,
	writefile,
	large_subnets;

HostInfo	DefHosts[MAXHOST],
		*hosts = DefHosts;
unsigned long	HostCount = MAXHOST;
unsigned long	CurrentSize = MAXHOST;

main(argc, argv)
char **argv;
int argc;
{
	char		*p;
	FILE		*fp;
	char		*vname;
	u_long		network;
	struct hostent	*hp;
	struct in_addr	addr;
	char		hname[64], fname[BUFSIZ];
	char		*get_arp(), *strip_domain();
	int		lna, nets = 0;

	pname = *argv;
	analyzer_type = verbose = writefile = 0;

	if (argc < 2)
		usage();

	/*
	 * Get our hostname.
	 */
	if (gethostname(hname, sizeof(hname)) < 0) {
		error("gethostname");
		exit(1);
	}

	/*
	 * Process arguments.
	 */
	while (--argc) {
		/*
		 * Option.
		 */
		if (**++argv == '-') {
			switch (*++*argv) {
			case 'L':			/* Large subnet	*/
				large_subnets = 1;
				break;
			case 'e':			/* excelan	*/
				analyzer_type = EXCELAN;
				break;
			case 's':			/* sniffer	*/
				analyzer_type = SNIFFER;
				break;
			case 'v':			/* verbose	*/
				verbose = 1;
				writefile = 0;
				break;
			case 'w':			/* write files	*/
				writefile = 1;
				verbose = 0;
				break;
			default:
				usage();
				break;
			}

			continue;
		}

		nets++;

		/*
		 * Do *something*.
		 */
		/* if (!verbose && !writefile)
			verbose = 1; */

		/*
		 * Just so they know.
		 */
		if (writefile && !analyzer_type) {
			fprintf(stderr,
				"%s: -w with no format; excelan format assumed.\n",
				pname);
			analyzer_type = EXCELAN;
		}

		/*
		 * Convert the given network address to an internet
		 * address.
		 */
		network = inet_network(*argv);
		addr = inet_makeaddr(network, 0);
		bzero(hosts, HostCount * sizeof(*hosts));

		/*
		 * Find the ethernet interface that's on that network.
		 */
		if ((lna = check_if(addr)) < 0) {
			fprintf(stderr, "%s: this host is not on the %s net.\n",
				pname, inet_ntoa(addr));
			continue;
		}

		/*
		 * Save our hostname.  check_if() filled in our
		 * internet address and ethernet address.
		 */

		if (!hosts[lna].hl_name || !hosts[lna].hl_name[0]) {
		    hosts[lna].hl_name = strdup (hname);
		}

		/* hosts[lna].hl_name = strip_domain(hname); */

		if (verbose)
			printf("%s:\n    ", *argv);

		/*
		 * For each host...
		 */
		for (lna = MINADDR; lna <= (HostCount-1); lna++) {
			if ((verbose == 1) && ((lna % 16) == 0)) {
				printf("%d...", lna);
				fflush(stdout);
			}

			/*
			 * Skip our entry; we did it already.
			 */
			if (hosts[lna].hl_name) {
				continue;
			}

			/*
			 * Build the internet address.
			 */

			addr = inet_makeaddr(network, lna);

			/*
			 * Ping it, and if it's up...
			 */

			if (ping(addr, lna)) {
				/*
				 * Get the hostname.
				 */
				hp = gethostbyaddr(&addr.s_addr,
						   sizeof(addr.s_addr),
						   AF_INET);
				/*
				 * Save the hostname.
				 */

				if (hp != NULL) {
					hosts[lna].hl_name =
						strdup (hp->h_name);
				    /*
				     *	hosts[lna].hl_name =
				     *		strip_domain(hp->h_name);
				     */
				}
				else
					hosts[lna].hl_name = strdup("???");

				/*
				 * Save the internet address and get the
				 * ethernet address from the arp table.
				 */
				hosts[lna].hl_inet = strdup(inet_ntoa(addr));
				hosts[lna].hl_ether = get_arp(addr, &vname);
				hosts[lna].hl_vname = vname;
			}
		}


		/*
		 * If we need to write files, create the file for this
		 * network.
		 */
		if (writefile) {
			p = strrchr(*argv, '.') + 1;
			sprintf(fname, "%snet.nam", p);

			if ((fp = fopen(fname, "w")) == NULL) {
				error(fname);
				exit(1);
			}

			switch (analyzer_type) {
			case EXCELAN:
				excelan_header(fp);
				break;
			case SNIFFER:
				sniffer_header(fp);
				break;
			}
		}
		else {
			printf("\n    Hostname       Internet Addr   ");
			printf("  Ethernet Addr    Vendor Name\n");
			printf("--------------------------");
			printf("--------------------------");
			printf("--------------------------\n");
		}

		/*
		 * Write or print each entry.
		 */
		for (lna = MINADDR; lna <= (HostCount-1); lna++) {
			if (hosts[lna].hl_name == NULL)
				continue;

			if (writefile) {
				switch (analyzer_type) {
				case EXCELAN:
					excelan_entry(&hosts[lna], fp);
					break;
				case SNIFFER:
					sniffer_entry(&hosts[lna], fp);
					break;
				}
			}
			else {
			    /*
			     *	printf("%-16.16s  %-15.15s  %-17.17s  %s\n",
			     */				
				printf("%-16s  %-15.15s  %-17.17s  %s\n",
				       hosts[lna].hl_name, hosts[lna].hl_inet,
				       hosts[lna].hl_ether,
				       hosts[lna].hl_vname);
			}

			free(hosts[lna].hl_name);
			free(hosts[lna].hl_inet);
			free(hosts[lna].hl_ether);
		}

		/*
		 * Write a footer and close the file.
		 */
		if (writefile) {
			switch (analyzer_type) {
			case EXCELAN:
				excelan_footer(fp);
				break;
			case SNIFFER:
				sniffer_footer(fp);
				break;
			}

			fclose(fp);
		}
	}

	if (!nets) {
	    usage ();
	}
	exit(0);
}

/*
 * strip_domain - strip the domain name
 */
char *
strip_domain(name)
char *name;
{
	char *index();
	register char *p;

	if ((p = index(name, '.')) != NULL)
		*p = '\0';

	return(strdup(name));
}

#ifdef NEED_ENTOA

#define ETHER_INDEX(i, j)   (unsigned int)(i->ether_addr_octet[(j)])

char *
ether_ntoa(ea)
struct ether_addr *ea;
{
	static char s[20];

	s[0] = 0;
	(void) sprintf(s, "%x:%x:%x:%x:%x:%x",
		       ETHER_INDEX(ea,0), ETHER_INDEX(ea,1), ETHER_INDEX(ea,2),
		       ETHER_INDEX(ea,3), ETHER_INDEX(ea,4), ETHER_INDEX(ea,5));
	return (s);
}

struct ether_addr *
ether_aton(s)
char *s;
{
	int i;
	unsigned int t[6];
	static struct ether_addr ep;

	bzero(&ep, sizeof (struct ether_addr));

	i = sscanf(s, " %x:%x:%x:%x:%x:%x",
		   &t[0], &t[1], &t[2], &t[3], &t[4], &t[5]);

	if (i != 6)
		return ((struct ether_addr *)NULL);

	for (i = 0; i < 6; i++)
		ep.ether_addr_octet[i] = t[i];

	return (&ep);
}
#endif

#ifdef NEED_STRDUP
char *
strdup(s)
char *s;
{
	char *p;
	char *malloc();

	if ((p = malloc(strlen(s)+1)) == NULL) {
		fprintf(stderr, "%s: out of memory.\n", pname);
		exit(1);
	}

	strcpy(p, s);
	return(p);
}
#endif

/*
 * error - perror with program name.
 */
error(s)
char *s;
{
	fprintf(stderr, "%s: ", pname);
	perror(s);
}

usage()
{
    fprintf (stderr,
	     "Usage: %s [-v] [-w [-e|-s]] network [network...]\n%s\n%s\n",
	     pname,
	     "\tClass C nets assumed but can automatically adjust to smaller",
	     "\taccording to the netmasks obtained from the interfaces."
    );
    exit(1);
}
