/* 

passlogd - passive syslog capture daemon
copyright (c) 2005 - christian void <cvoid@morphine.com>

file: passlog.c

history: 

07jun01 cvoid: added -S syslog-like output option.
05jun01 cvoid: added -p and -e options for otto.
04jun01 cvoid: added syslogging stuff.
03jun01 cvoid: broke into multiple source files.
03jun01 cvoid: added logfile and getopt code.
01jun01 cvoid: created from angst source.
 
*/

#include <stdio.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include "passlog.h"

u_char buffer[BUFSIZE];		/* to store the data of a connection */
pcap_t *pd;			/* packet capture descriptor */
u_int hdrlen;			/* encapsulation header length */
pcap_handler callback; 
int debug = 0;                  /* global flags */
int vflag = 0; 
int sflag = 0; 
int rflag = 0; 
int fflag = 0;
int dflag = 0;                  /* display flag for output formatting */
int conflag = 1;

char logfile[MAXPATH];        /* log file */
int logfd;

/* MAIN */
int main(int argc, char *argv[])
{
  int c;
  char logfile[MAXPATH];        /* log file */
  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 */
  char *errstr;
  int port = 514;
  char filterstr[64];
  char ignorestr[16];
  char devstr[16];
  int ignore;

  /* default values */
	memset(devstr,0,sizeof(devstr));
	char *a="any";
	strncpy(devstr,a,strlen(a));

  while ((c = getopt(argc, argv, "hsrdi:p:e:f::S")) != EOF)
    {
      switch (c)
        {
	case 'h':
	  printf("passlogd %s - passive syslog capture daemon\n", VERSION);
	  printf("copyright (c) 2005 - christian void <cvoid@morphine.com>\n\n");
	  printf("usage: passlogd [-hvsr][-f<filename>]\n");
	  printf("  -h            display this message\n");
	  printf("  -s            log captured messages to local syslog\n");
	  printf("  -r            reverse lookup ip addresses\n");
	  printf("  -d            debug mode\n");
	  printf("  -i<ipaddr>    ignore packets from <ipaddr>\n");
	  printf("  -p<port>      listen for syslog packets to <port> (default: 514)\n");
	  printf("  -e<interface> set the interface to listen on\n");
	  printf("  -f<filename>  log to <filename> (default: /var/log/passlog)\n");
	  printf("  -S            use syslog format in logfile\n\n");
	  printf("by default, passlogd logs all messages to stdio without performing\n");
	  printf("reverse lookups. packets captured and logged via syslog locally are\n");
	  printf("reported using the captured facility and loglevel. messages captured\n");
	  printf("to a logfile are written wholesale.\n");
	  exit(0);

	case 's':
	  sflag = 1;
	  conflag = 0;
	  break;

	case 'r':
	  rflag = 1;
	  break;
	 
	case 'i':
	  ignore = 1;
	  if (strlen(optarg) < sizeof(ignorestr)){
	    strncpy(ignorestr, optarg, strlen(optarg));
	  }
	  else {
	    printf("invalid ip address\n");
	  exit(-1);
	  }
	  break;

	case 'd':
	  debug = 1;
	  break;
	  
	case 'e':
	  if(strlen(optarg) < sizeof(devstr)){
			memset(devstr,0,sizeof(devstr));
	    strncpy(devstr, optarg, strlen(optarg));
	  }
	  else {
	    printf("invalid device\n");
	    exit(-1);
	  }
	  break;

	case 'p':
	  /* set the port in the filter program */
	  port = atoi(optarg);
	  break;

	case 'f':
	  fflag = 1;
	  conflag = 0;
	  memset(logfile, 0, MAXPATH);
	  if(optarg){
	    if(strlen(optarg) < MAXPATH){
	      strncpy(logfile, optarg, strlen(optarg));
	    }
	    else {
	      printf("invalid filename\n");
	      exit(-1);
	    }
	  }
	  else { /* no filename specified, use default */
	    strncpy(&logfile, "/var/log/passlog", 16);
	  }
	  break; 

	case 'S':
	  dflag = 1;
	  break;

	default:
	  /* by default we log to stdio */
	  printf("logging to console...\n");
        }
    }

  if(debug){
    /* dump command line paramaters */
    printf("vflag: %d\n", vflag);
    printf("sflag: %d\n", sflag);
    printf("rflag: %d\n", rflag);
    printf("fflag: %d\n", fflag);
    if(fflag){  
      printf("file: %s\n", logfile);
    }
  }

  /* log our impending startup via syslog */
  openlog("passlogd", 0, LOG_DAEMON);
  syslog(LOG_INFO, "starting...");
  syslog(LOG_INFO, "listening for syslog packets sent to port %d on any host", port);
  if(ignore)
    syslog(LOG_INFO, "ignoring messages from %s", ignorestr);
  closelog();
  
  init_buf(buffer, sizeof(buffer));
  
  /* set the callback function */
  callback = (pcap_handler)sl_parse;
  
	if((pd = pcap_open_live(devstr, SNAPLEN, promisc_flag, TIMEOUT, errbuf)) == NULL){
      printf("pcap_open_live error: %s\n", errbuf);
      printf("most likely, you are not root...\n");
      exit(-1);
    }
 
  /* determine link layer type */
  if((datalink = pcap_datalink(pd)) < 0)
    printf("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(devstr, &localnet, &netmask, errbuf)) < 0){
      localnet = netmask = 0;
      printf("pcap_lookupnet error: %s\n", errbuf);
    }

  /* setup out filter */
  if (ignore) {
    sprintf(filterstr, FILTERNOT, port, ignorestr);
  }
  else {
    sprintf(filterstr, FILTER, port);
  }

  if((pcap_compile(pd, &filter, filterstr, 1, netmask)) < 0)
    printf("pcap_compile error: %s\n", pcap_geterr(pd));

  /* set the filter program */
  if((pcap_setfilter(pd, &filter)) < 0)
    printf("pcap_setfilter error: %s\n", pcap_geterr(pd));

  /* open our logfile if neccessary */
  if(fflag){
    logfd = open(logfile, O_WRONLY|O_APPEND|O_CREAT);
    if(debug){	
    	errstr = (char *) strerror(errno);
    	printf("open return %d: %s\n", logfd, errstr);
    	}
  }

  /* set up our signal handler - we respond to SIGTERM and cleanly */
  /* close our logfile (if logging to a file) and all that other */
  /* good stuff */
  signal(SIGTERM, sighandle);
  
  /* collect and process packets infinite loop */
  if((pcap_loop(pd, -1, callback, NULL)))
    printf("pcap_loop error: %s\n", pcap_geterr(pd));
  
  return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1