/* angst - main.c
 * by Patroklos Argyroudis <argp@bsd.gr>
 *
 * Main control of the program.
 *
 * $Id: main.c,v 1.20 2001/02/06 19:17:54 argp Exp $
 */ 

#include "angst.h"

static char version[] = "0.4b";

int
main(int argc, char *argv[])
{
 int c;
 int datalink = 0;		/* link layer type */
 int promisc_flag = 1;		/* default to set promiscuous mode */
 int flood_flag = 0;		/* default to passive sniffing */
 int f_flag = 1;		/* enable IP forwarding flag */
 int e_flag = 0;		/* user supplied filter expression flag */
 char expr[BUFSIZE];		/* user supplied filter expression buffer */
 char filter_expr[BUFSIZE];	/* final filter expression */ 
 bpf_u_int32 localnet, netmask;	/* network number, associated netmask */
 struct bpf_program filter;	/* filter program */
 char errbuf[PCAP_ERRBUF_SIZE];	/* libpcap error handling buffer */

 /* default values */
 device = NULL;
 arp_flag = 0;
 resolve_flag = LIBNET_DONT_RESOLVE;	/* don't resolve IP addresses */
 seconds = 0;
 pktcount = MACPKTS;			/* flood MACPKTS number of packets */
 logfile = LOGFILE;
 head = NULL;
 tail = NULL;

 opterr = 0;	/* don't let getopt() write to stderr */
 while((c = getopt(argc, argv, "ade:fhprvc:i:l:s:")) != EOF)
 {
  switch(c)
  {
   case 'a':
	arp_flag = 1;
	break;
   case 'd':
   	f_flag = 0;
   	break;
   case 'e':
   	e_flag = 1;
   	strlcpy(expr, build_expression(optarg), sizeof(expr));
   	fprintf(stderr, "warning: the filter expression is %s\n", expr);
   	break;
   case 'f':
   	flood_flag = 1;
   	break;
   case 'h':
	usage(argv[0]);
	exit(EXIT_SUCCESS);
   case 'p':
	promisc_flag = 0;
	break;
   case 'r':
	resolve_flag = LIBNET_RESOLVE;
	break;
   case 'v':
   	display_version(version);
	exit(EXIT_SUCCESS);
   case 'c':
	pktcount = atoi(optarg);
	break;
   case 'i':
	device = optarg;
	break;
   case 'l':
	logfile = optarg;
	break;
   case 's':
	seconds = atoi(optarg);
	break;
   default:
	usage(argv[0]);
	exit(EXIT_SUCCESS);
  }
 } /* while */
 
 /* maybe in the next version */
 if(flood_flag == 1 && arp_flag == 1)
  xprintf("error: you cannot use both active sniffing methods simultaneously\n");

 if(arp_flag == 1)
 {
#ifdef LINUX
  if(f_flag == 1)
   linux_enable_ip_forwarding();
#else /* {Free,Net,Open}BSD */
  if(f_flag == 1)
   bsd_enable_ip_forwarding();
#endif /* LINUX */
 }
 
 if(arp_flag == 1 && f_flag == 0)
  fprintf(stderr, "warning: in order for the man-in-the-middle ARP method to work, IP forwarding must be enabled on the local host, I trust you enabled it yourself\n");
 
 if(arp_flag == 0 && flood_flag == 0)
  fprintf(stderr, "warning: no active sniffing method was specified\n");
  
 init_buf(buffer, sizeof(buffer));

 /* set the callback function */
 callback = (pcap_handler)dissect;

 /* choose packet capturing device */
 if(device == NULL)
 {
  if((device = pcap_lookupdev(errbuf)) == NULL)
   xprintf("pcap_lookupdev error: %s\n", errbuf);
 }

#ifdef DEBUG
 fprintf(stderr, "device: %s\n", device);
#endif /* DEBUG */

 /* open the device */
 if((pd = pcap_open_live(device, SNAPLEN, promisc_flag, TIMEOUT, errbuf)) == NULL)
  xprintf("pcap_open_live error: %s\n", errbuf);

 /* determine link layer type */
 if((datalink = pcap_datalink(pd)) < 0)
  xprintf("pcap_datalink error: %s\n", pcap_geterr(pd));

 /* determine the header length of the link layer encapsulation */
 hdrlen = find_header_length(datalink);

 /* get network address and subnet mask */
 if((pcap_lookupnet(device, &localnet, &netmask, errbuf)) < 0)
 {
  localnet = netmask = 0;
  xprintf("pcap_lookupnet error: %s\n", errbuf);
 }
 
 if(e_flag == 1)
  strlcpy(filter_expr, expr, sizeof(filter_expr));
 else
  strlcpy(filter_expr, FILTER, sizeof(filter_expr));

 /* compile the filter program */
 if((pcap_compile(pd, &filter, filter_expr, 1, netmask)) < 0)
  xprintf("pcap_compile error: %s\n", pcap_geterr(pd));

 /* set the filter program */
 if((pcap_setfilter(pd, &filter)) < 0)
  xprintf("pcap_setfilter error: %s\n", pcap_geterr(pd));
 
 /* catch some signals in order to keep things tidy */
 if((signal(SIGTERM, catcher)) == SIG_ERR)
  xprintf("signal error\n");

 if((signal(SIGINT, catcher)) == SIG_ERR)
  xprintf("signal error\n");

 if((signal(SIGQUIT, catcher)) == SIG_ERR)
  xprintf("signal error\n");

 /* become a daemon */
 if((daemonize(".")) == -1)
  xprintf("fork error\n");

 /* setup the fake ARP replies active sniffing method */
 if(arp_flag == 1)
 {
  if(seconds == 0)
   seconds = WAKETIME;
   
  if((signal(SIGALRM, sig_arp)) == SIG_ERR)
   xprintf("signal error\n");
  
  /* send them for the first time */
  sig_arp(SIGALRM);
 }
 
 /* setup the flooder, for active sniffing */
 if(flood_flag == 1)
 {
  if(seconds == 0)
   seconds = WAKETIME;
   
  if((signal(SIGALRM, sig_flood)) == SIG_ERR)
   xprintf("signal error\n");

  /* flood for the first time */
  sig_flood(SIGALRM);
 }

 /* open the log file in append mode */
 if((fp = fopen(logfile, "a+")) == NULL)
  xprintf("fopen error: %s\n", strerror(errno));

 /* change the mode of the log file */
 if((chmod(logfile, (S_IRUSR | S_IWUSR))) == -1)
  xprintf("chmod error: %s\n", strerror(errno));

 /* collect and process packets infinite loop */
 if((pcap_loop(pd, -1, callback, NULL)))
  xprintf("pcap_loop error: %s\n", pcap_geterr(pd));

 /* this should not be reached */
 if((fflush(fp)) == EOF)
  xprintf("fflush error: %s\n", strerror(errno));
 if((fclose(fp)) == EOF)
  xprintf("fclose error: %s\n", strerror(errno));
 pcap_close(pd);
 return(EXIT_SUCCESS);
}

/* EOF */
