/* 
 * Network accounting
 * process.c - process packets
 * (C) 1994, 1995 Ulrich Callmeier
 *
 * modified April/98 by Tom Brown - tbrown@baremetal.com 
 *  added hash table to speed up register_packet
 */

#include <sys/time.h>
#include <sys/wait.h>
#include "netacct.h"

#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <utmp.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

#ifdef REMAP_MASQUERADE
#include <net/ip_masq.h>
#define PROC_MASQ_FILENAME "/proc/net/ip_masquerade"
#endif

char *rcs_revision_process_c = "$Revision: 1.8 $";

volatile int running;
struct statistics *packets;

#ifndef HASH_SIZE
#define HASH_SIZE 4096
#endif
#define HASH(s,d) ((s &0xfff)^(d &0xfff))


static struct ipdata *plist[HASH_SIZE]; /* data being collected */
static struct ipdata *olist[HASH_SIZE]; /* data being written */
unsigned long int plistsize;
unsigned long int olistsize;
static volatile sig_atomic_t lck;
static volatile sig_atomic_t writing;
static volatile sig_atomic_t dumping;
volatile pid_t writepid;
volatile pid_t dumppid;

volatile int may_write;

int err_delay, max_err_delay;

volatile time_t now;

/* statistics */
unsigned int list_compares, list_lookups;

#ifdef REMAP_MASQUERADE
void remap_masq(struct ipdata *p)
{
    FILE *fd;
    char buf[257];
    char *protocol;
    char searchtext[20];
    int plen;

    if(p->proto == 6)
	protocol = "TCP";
    else if(p->proto == 17) 
	protocol = "UDP";
    else if(p->proto == 1)
	protocol = "ICMP";
    else
	return;

    plen = strlen(protocol);
    sprintf(searchtext, "%08lX:%04X %04X",ntohl(p->dst), 
	p->dstport, p->srcport);
    if((fd=fopen(PROC_MASQ_FILENAME,"r")) == NULL)
	return;

    while(fgets(buf,257,fd)) {
	  if((strncmp(protocol,buf,plen) == 0) &&
	  (strncmp(searchtext, buf+plen+15, 18) == 0)) {
	    p->msqsrc = htonl(strtoul(buf+plen+1, NULL, 16));
	    p->msqport = strtoul(buf+plen+10, NULL, 16);
	    break;
	}
    }
    fclose(fd);
    return;
}
#endif

void reopen_socket(void)
{
    int save1, save2;
    
    /* critical section */
    save1 = may_write;
    may_write = 0;
    save2 = lck;
    lck = 1;
    /* end */
    
    exit_capture();
    init_capture();

    lck = save2;
    may_write = save1;
}


void do_acct()
{
  int i;

  packets = malloc(sizeof(struct statistics));

  if(!packets)
    {
      syslog(LOG_ERR,"out of memory");
      daemon_stop(0);
    }
  
  packets->ignored = packets->netignored = packets->ip = packets->local = 0;
  packets->ip_icmp = packets->ip_tcp = packets->ip_udp = packets->ip_other = 0;
  packets->notdev = packets->unenc = 0;

  for (i =0; i < HASH_SIZE; i++) {
     olist[i] = plist[i] = NULL;
     /*  olist = plist = NULL; */
  }
  olistsize = plistsize = 0;
  lck = writing = dumping = 0;

  max_err_delay = cfg -> err_delay;
  err_delay = 0;

  list_lookups = list_compares = 0;

  may_write = 1;

  now = time(NULL);

  alarm(1);
  running=1;

  packet_loop();

}

#define DISABLED(n) (cfg->disabled & BITMASK(n))

void register_packet(unsigned long int src,unsigned long int dst, unsigned char proto, unsigned short srcport, unsigned short dstport, int size, char *devname, char *user)
{
  int hash_val = HASH(src,dst);

  if(lck==0)
    {
      struct ipdata *p;
      DEBUG(DBG_ANNOYING, sprintf(dbg, "lck = 1\n"));
      lck = 1;
      p = plist[ hash_val ];
      list_lookups++;
      while(p)
	{
	  list_compares++;
	  if( (DISABLED(DIS_PROTO) || (p->proto == proto)) 
           && ( DISABLED(DIS_SRC) || (p->src == src)) 
           && (DISABLED(DIS_DST) || (p->dst == dst)) 
           &&  (DISABLED(DIS_SRCPORT) || (p->srcport == srcport)) 
           && (DISABLED(DIS_DSTPORT) || (p->dstport == dstport)) 
           && (strcmp(p->devname, devname)==0))
	    {
	      p->bytes +=size;
	      p->when = now;
	      p->count++;
	      lck = 0;
	      DEBUG(DBG_ANNOYING, sprintf(dbg, "lck = 0\n"));
	      return;
	    }
	  p = p->next;
	}
      p = malloc(sizeof(struct ipdata));
      if(p == NULL)
	{
	  packets -> dropped++;
	  lck = 0;
	  DEBUG(DBG_ERR, sprintf(dbg, "out of memory\n"));
	  DEBUG(DBG_ANNOYING, sprintf(dbg, "lck = 0\n"));
	  return;
	}
      plistsize++;
      p -> src = src;
      p -> dst = dst;
      p -> proto = proto;
      p -> srcport = srcport;
      p -> dstport = dstport;
#ifdef REMAP_MASQUERADE
      p -> msqsrc = 0;
      p -> msqport = 0;
      if((src == cfg->masqif) && 
	 (srcport >= PORT_MASQ_BEGIN) &&
	 (srcport <= PORT_MASQ_END)) {
	    remap_masq(p);
      }
#endif
      p -> bytes = size;
      p -> count = 1;
      p -> devname = strdup(devname);
      if (user)
	p -> user = strdup(user);
      else
	p -> user = NULL;
      p -> next = plist[ hash_val ];
      p -> when = now;
      
#ifdef TCP_USER_INFO
      /* NEW !!! get user for tcp only */
      if((proto == IP_TCP) && (p->user == 0) && (get_tcp_info(p, &uid)==1))
	{
	  char tmp[16];
	  sprintf(tmp, "<%d>", uid);
	  p -> user = strdup(tmp);
	}
#endif
      
      plist[ hash_val ] = p;
      lck = 0;
      DEBUG(DBG_ANNOYING, sprintf(dbg, "lck = 0\n"));
    }
  else
    {
      packets->dropped++;
    }
}

int do_write_list(FILE *f, struct ipdata *list[])
{
    struct ipdata *p;
    int i;
#ifdef HUMAN_READABLE_TIME
    struct tm *tm1;
    time_t tmm;
#endif

    for( i=0; i < HASH_SIZE; i++) {
        p = list[i];

    while(p)
	{
#ifdef HUMAN_READABLE_TIME
	  /* by Vlad Seriakov */
	  time(&tmm);
	  tm1 = localtime(&tmm); 
	  if(fprintf(f, "%02d/%02d/%02d %02d:%02d:%02d",tm1->tm_year,tm1->tm_mon+1,tm1->tm_mday,
		     tm1->tm_hour,tm1->tm_min,tm1->tm_sec)<0) return 1;
#else
	  if(fprintf(f, "%lu",time(0))<0) return 1;
#endif	
    
	    if(!DISABLED(DIS_PROTO)) if(fprintf(f, "\t%d",p->proto)<0) return 1;

#ifdef REMAP_MASQUERADE
	    if(p->msqport == 0) {
#endif
	      if(!DISABLED(DIS_SRC)) if(fprintf(f, "\t%s",intoa(p->src))<0) return 1;

	      if(!DISABLED(DIS_SRCPORT)) if(fprintf(f, "\t%d",p->srcport)<0) return 1;
#ifdef REMAP_MASQUERADE
	    }
	    else {
	      if(!DISABLED(DIS_SRC)) if(fprintf(f, "\t%s",intoa(p->msqsrc))<0) return 1;

	      if(!DISABLED(DIS_SRCPORT)) if(fprintf(f, "\t%d",p->msqport)<0) return 1;
	    }		
#endif

	    if(!DISABLED(DIS_DST)) if(fprintf(f, "\t%s",intoa(p->dst))<0) return 1;

	    if(!DISABLED(DIS_DSTPORT)) if(fprintf(f, "\t%d",p->dstport)<0) return 1;

	    if(!DISABLED(DIS_COUNT)) if(fprintf(f, "\t%u",p->count)<0) return 1;

	    if(!DISABLED(DIS_BYTES)) if(fprintf(f, "\t%lu",p->bytes)<0) return 1;

	    if(!DISABLED(DIS_DEV)) if(fprintf(f, "\t%s",p->devname)<0) return 1;

	    if(!DISABLED(DIS_USER)) if(fprintf(f, "\t%s",p->user?p->user:"unknown")<0) return 1;

	    if(fprintf(f, "\n")<0) return 1;
   
	    p = p->next;
	}
    }

    if(fclose(f)<0)
	{
	    return 1;
	}

    return 0;
}

static int pfd1[2], pfd2[2];

void TELL_WAIT_INIT(void)
{
  if(pipe(pfd1) < 0 || pipe(pfd2) < 0)
    {
      syslog(LOG_ERR, "pipe error: %s", strerror(errno));
      DEBUG(DBG_ERR, sprintf(dbg,"pipe error: %s\n", strerror(errno)));
    }
}

void TELL_WAIT_EXIT(void)
{
  if(close(pfd1[0])!=0)
    {
      syslog(LOG_ERR, "pipe close error: %s", strerror(errno));
      DEBUG(DBG_ERR, sprintf(dbg,"pipe close error: %s\n", strerror(errno)));
    }

  if(close(pfd1[1])!=0)
    {
      syslog(LOG_ERR, "pipe close error: %s", strerror(errno));
      DEBUG(DBG_ERR, sprintf(dbg,"pipe close error: %s\n", strerror(errno)));
    }

  if(close(pfd2[0])!=0)
    {
      syslog(LOG_ERR, "pipe close error: %s", strerror(errno));
      DEBUG(DBG_ERR, sprintf(dbg,"pipe close error: %s\n", strerror(errno)));
    }

  if(close(pfd2[1])!=0)
    {
      syslog(LOG_ERR, "pipe close error: %s", strerror(errno));
      DEBUG(DBG_ERR, sprintf(dbg,"pipe close error: %s\n", strerror(errno)));
    }
}

void TELL_PARENT(void)
{
  if(write(pfd2[1], "c", 1) != 1)
    {
      syslog(LOG_ERR, "write error: %s", strerror(errno));
      DEBUG(DBG_ERR, sprintf(dbg,"write error: %s\n", strerror(errno)));
    }
}

void WAIT_PARENT(void)
{
  char c; int n;

 again:

  if((n = read(pfd1[0], &c, 1)) != 1)
    {
      if((n == -1) && (errno == EINTR)) goto again;
      syslog(LOG_ERR, "read error: %s", strerror(errno));
      DEBUG(DBG_ERR, sprintf(dbg,"read error: %s\n", strerror(errno)));
    }
  if(c!='p')
    {
      syslog(LOG_ERR, "WAIT_PARENT: incorrect data");
      DEBUG(DBG_ERR, sprintf(dbg,"WAIT_PARENT: incorrect data\n"));
    }
}  

void TELL_CHILD(void)
{
  if(write(pfd1[1], "p", 1) != 1)
    {
      syslog(LOG_ERR, "write error: %s", strerror(errno));
      DEBUG(DBG_ERR, sprintf(dbg,"write error: %s\n", strerror(errno)));
    }
}

void WAIT_CHILD(void)
{
  char c; int n;

 again:

  if((n = read(pfd2[0], &c, 1)) != 1)
    {
      if((n == -1) && (errno == EINTR)) goto again;
      syslog(LOG_ERR, "read error: %s", strerror(errno));
      DEBUG(DBG_ERR, sprintf(dbg,"read error: %s\n", strerror(errno)));
    }
  if(c!='c')
    {
      syslog(LOG_ERR, "WAIT_CHILD: incorrect data");
      DEBUG(DBG_ERR, sprintf(dbg,"WAIT_CHILD: incorrect data\n"));
    }
}  

/* write and clear olist */
void write_list(void)
{
    FILE *f;
    char tmpn[255];
    int i;

    while( (writepid = fork()) < 0) sleep(1);
    if (writepid!=0) return;

    /* Here goes the child */

    TELL_PARENT();
    WAIT_PARENT();

    DEBUG(DBG_STATE, sprintf(dbg, "write child: synchronized with parent\n"));

    sprintf(tmpn, "/tmp/nacctd.write.%d", (int) getpid());
    creat(tmpn, S_IRUSR);

    openlog("nacctd (write)", 0, LOG_DAEMON);

    DEBUG(DBG_STATE, sprintf(dbg, "* write process %d forked\n", (int) getpid()));

    f = fopen(cfg->filename, "a");
    if(f==NULL)
	{
	    unlink(tmpn);
	    syslog(LOG_ERR, "error opening file %s: %m\n",cfg->filename);
	    exit(1);
	}

    if(do_write_list(f, olist) != 0)
	{
	    unlink(tmpn);
	    syslog(LOG_ERR, "error writing to file %s: %m\n", cfg->filename);
	    exit(1);
	}

    /* memory leak? TAB */
    for (i=0; i < HASH_SIZE; i++) 
       olist[i] = NULL;

    unlink(tmpn);

    DEBUG(DBG_STATE, sprintf(dbg, "* write finished, count = %ld\n", olistsize));

    exit(0);
}

void dump_curr_list(void)
{
    FILE *f;
    char tmpn[255];
    int i;

    while( (dumppid = fork()) < 0) sleep(1);
    if (dumppid!=0) return;

    TELL_PARENT();
    WAIT_PARENT();

    DEBUG(DBG_STATE, sprintf(dbg, "dump child: synchronized with parent\n"));

    /* Here goes the child */

    sprintf(tmpn, "/tmp/nacctd.dump.%d", (int) getpid());
    creat(tmpn, S_IRUSR);

    openlog("nacctd (dump)", 0, LOG_DAEMON);

    DEBUG(DBG_STATE, sprintf(dbg, "* dump process %d forked\n", (int) getpid()));

    if(plistsize == 0)
	{
	    unlink(tmpn);
	    unlink(cfg->dumpname);
	    DEBUG(DBG_STATE, sprintf(dbg, "* dump finished, dump empty\n"));
	    exit(0);
	}

    f = fopen(cfg->dumpname, "w");
    if(f==NULL)
	{
	    unlink(tmpn);
	    syslog(LOG_ERR, "error opening file %s: %m\n",cfg->dumpname);
	    exit(1);
	}

    if(do_write_list(f, plist) != 0)
	{
	    unlink(tmpn);
	    syslog(LOG_ERR, "error writing to file %s: %m\n", cfg->dumpname);
	    exit(1);
	}

    for (i=0; i < HASH_SIZE; i++) 
       plist[i] = NULL;

    unlink(tmpn);

    DEBUG(DBG_STATE, sprintf(dbg, "* dump finished, count = %ld\n", plistsize));

    exit(0);
}


void child_finished(int sig)
{
    int status;
    pid_t pid;

    DEBUG((DBG_SIGNAL | DBG_STATE), sprintf(dbg, "-> got signal %d, handling\n", sig));

    while((pid = waitpid((pid_t) -1, &status, WNOHANG)) != 0)
	{
	  DEBUG(DBG_SIGNAL, sprintf(dbg, "  waitpid returned %d, status = %d, errno = %d\n", pid, status, errno));
	     
	  if(pid == -1)
	    {
	      if(errno == ECHILD)
		break; /* no child processes */
	      DEBUG(DBG_SIGNAL, sprintf(dbg, "waitpid: signaled error: %s\n", strerror(errno)));
	    }
	      
	  if((pid == writepid) || (pid == dumppid))
	    {
	      if(WIFEXITED(status))
		{
		  if(WEXITSTATUS(status)==0)
		    {
		      if(pid == writepid)
			{
			  writing = 0;
			  DEBUG((DBG_SIGNAL | DBG_STATE), sprintf(dbg, "  set writing to 0\n"));
			}
		      else
			{
			  dumping = 0;
			  DEBUG((DBG_SIGNAL | DBG_STATE), sprintf(dbg, "  set dumping to 0\n"));
			}
		    }
		  else
		    {
		      syslog(LOG_ERR, 
			     "child %d exited with error status %d.\n",
			     pid, WEXITSTATUS(status));
		      if(pid == writepid)
			{
			  err_delay = max_err_delay;
			  writing = 0;
			  DEBUG((DBG_SIGNAL | DBG_STATE), sprintf(dbg, "  set writing to 0, setting err_delay\n"));
			}
		      else
			{
			  dumping = 0;
			  DEBUG((DBG_SIGNAL | DBG_STATE), sprintf(dbg, "  set dumping to 0, ignored error condition\n"));
			}
		      
		    }
		}
	      else
		{
		  syslog(LOG_ERR,
			 "Huh? Child %d terminated or stopped by signal (%m)\n",
			 pid);
		  if(pid == writepid)
		    {
		      writing = 0;
		      DEBUG((DBG_SIGNAL | DBG_STATE), sprintf(dbg, "  set writing to 0, ignored return code\n"));
		    }
		  else
		    {
		      dumping = 0;
		      DEBUG((DBG_SIGNAL | DBG_STATE), sprintf(dbg, "  set dumping to 0, ignored return code\n"));
		    }
		}
	    }
	  else
	    {
	      syslog(LOG_ERR, "Huh? Child (%d) returned, but not the one we expected (%d, %d)!\n", (int) pid, writepid, dumppid);
	      DEBUG(DBG_STATE, sprintf(dbg, "  unexpected child %d signaled return (writepid = %d, dumppid = %d\n",(int) pid, writepid, dumppid));

	    }
	  DEBUG(DBG_STATE, sprintf(dbg, "  child %d signaled return\n",(int) pid));
	}
    DEBUG((DBG_SIGNAL | DBG_STATE), sprintf(dbg, "<- got signal %d, done handling\n", sig));
}

void alarm_handler(int sig)
{
    static time_t last_check = 0;
    static time_t next_write_log = 0;

    DEBUG( ((sig == SIGALRM) ? DBG_ANNOYING : (DBG_SIGNAL | DBG_STATE)), sprintf(dbg, "got signal %d, handling\n", sig));

    now++;

    if((now - last_check) > 60)
	{
	    time_t nnow;
	    
	    nnow = time(NULL);
	    if(nnow!=now)
		{
		    if((abs(nnow - now) > 2))
			{
			    DEBUG(DBG_MISC, sprintf(dbg, "internal clock corrected (off by %d seconds)\n",(int) (nnow-now)));
			}
		    now = nnow;
		}
	    last_check = now;
	}

    if(now >= next_write_log)
	{
	    write_log(0);
	    next_write_log = now + cfg -> flush;
	}

    alarm(1);
}

void write_log(int force)
{
  struct ipdata *p, *q;
  static struct ipdata *tlist; /* temp */
  int i;

  DEBUG(DBG_STATE, sprintf(dbg, "write_log called\n"));

  if(err_delay!=0)
    {
      err_delay--;
      syslog(LOG_INFO,"flushing delayed due to error\n");
      DEBUG(DBG_STATE, sprintf(dbg, "flushing delayed due to error\n"));
    }
  else if((writing == 0) && (lck == 0) && (may_write == 1)) /* delay if another write cycle is still in progress */
    {
      DEBUG(DBG_STATISTICS, sprintf(dbg, "ignored: %ld netignored: %ld local:%ld ip:%ld unenc:%ld notdev:%ld dropped:%ld\n", 
				    packets->ignored, packets->netignored, packets->local, packets->ip, 
				    packets->unenc, packets->notdev, packets->dropped));
      DEBUG(DBG_STATISTICS, sprintf(dbg, "udp: %ld tcp:%ld icmp:%ld other:%ld\n", 
				    packets->ip_udp, packets->ip_tcp, packets->ip_icmp, 
				    packets->ip_other));
      if(list_lookups != 0)
	{
	  DEBUG(DBG_STATISTICS, sprintf(dbg, "lookups:%d compares:%d compares/lookup:%f\n",
					list_lookups, list_compares, 
					((float) list_compares / (float) list_lookups)));
	}
      DEBUG(DBG_STATE, sprintf(dbg, "lck = 1\n"));
      lck = 1; /* can't update the list now */
      
      DEBUG(DBG_MISC, sprintf(dbg, "Total of %ld entries\n", plistsize));
      
      /* We build two lists:
	 1) olist, which will be written out
	 2) tlist, which will be the new plist (just for this hash row)
	 */
      
      olistsize = 0;
      plistsize = 0;

      for (i = 0; i < HASH_SIZE; i++) {
	 p = plist[i];
	 tlist = NULL;
	 olist[i] = NULL;
	 
	 while(p)
	   {
	     q = p->next;
	     if(((now - p->when) > cfg->fdelay) || force)
	       {
		 p->next = olist[i];
		 olist[i] = p;
		 olistsize++;
	       }
	     else
	       {
		 p->next = tlist;
		 tlist = p;
		 plistsize++;
	       }
	     p = q;
	   }
	 plist[i] = tlist;
      }
      
      if(dumping == 0)
	{
	  dumping = 1;

	  TELL_WAIT_INIT();

	  dump_curr_list();

	  TELL_CHILD();
	  WAIT_CHILD();
	  
	  DEBUG(DBG_STATE, sprintf(dbg, "parent: synchronized with dump child\n"));
	  
	  TELL_WAIT_EXIT();

	  DEBUG(DBG_STATE, sprintf(dbg, "dumppid is %d\n", (int) dumppid));
	}
      
      writing = 1; /* no further writing 'til this is finished */
      
      lck = 0;
      DEBUG(DBG_STATE, sprintf(dbg, "lck = 0\n"));
      
      DEBUG(DBG_MISC, sprintf(dbg, "Split into %ld [hold] and %ld [write] = %ld [total] entries\n", plistsize, olistsize, plistsize + olistsize));
      
      TELL_WAIT_INIT();

      write_list(); /* this forks off a child to do the actual writing */
      
      TELL_CHILD();
      WAIT_CHILD();

      DEBUG(DBG_STATE, sprintf(dbg, "parent: synchronized with write child\n"));
      
      TELL_WAIT_EXIT();

      DEBUG(DBG_STATE, sprintf(dbg, "writepid is %d\n", (int) writepid));
      
      for (i=0; i < HASH_SIZE; i++) {
	 p = olist[i];
	 while(p)
	   {
	     olist[i] = p->next;
	     free(p->devname);
	     if (p->user)
		 free(p->user);
	     free(p);
	     p=olist[i];
	   }
      }
        
      
      DEBUG(DBG_STATE, sprintf(dbg, "done freeing\n"));
    }
  else
    {
      DEBUG(DBG_STATE, sprintf(dbg, "flushing delayed (writing == %d, lck == %d, may_write == %d)\n",writing,lck,may_write));
    }
}

void signal_debug(int sig)
{
  DEBUG(DBG_SIGNAL, sprintf(dbg, "got signal %d, handling\n", sig));
    
  if(sig==SIGUSR1)
    {
      debug_level++;
    }
  else if(sig==SIGUSR2)
    {
      syslog(LOG_DEBUG, "turning off debugging\n");
      debug_level = 0;
    }
  else if(sig==SIGWINCH)
    {
      syslog(LOG_DEBUG,"nacctd, revisions:\n%s\n%s\n%s\n%s\n", 
	     rcs_revision_main_c, rcs_revision_process_c,
	     rcs_revision_config_c, rcs_revision_daemon_c);
    }
  else if(sig==SIGTSTP)
    {
      DEBUG(DBG_STATE, sprintf(dbg, "received SIGTSTP\n"));
      may_write = 0;
    }
  else if(sig==SIGCONT)
    {
      DEBUG(DBG_STATE, sprintf(dbg, "received SIGCONT\n"));
      may_write = 1;
    }
  else if(sig==SIGIOT)
    {
      DEBUG(DBG_STATE, sprintf(dbg, "reopening socket\n"));
      reopen_socket();
    }
  else if(sig == SIGHUP)
  {
      struct ipnetwork *ip,*ip_next;
      struct promisc_device *pr,*pr_next;
      struct headerdat *h,*h_next;
      struct mon_host_struct *mh,*mh_next;
      DEBUG(DBG_STATE, sprintf(dbg, "received SIGHUP, rereading config\n"));
      exit_capture();
      if(cfg) {
	free(cfg->filename);
	free(cfg->dumpname);
	free(cfg->debugname);
	for(ip=cfg->ignorenet;ip;ip=ip_next) {
	    ip_next = ip->next;
	    free(ip);
	}
	for(ip=cfg->dontignore;ip;ip=ip_next) {
	    ip_next = ip->next;
	    free(ip);
	}
	for(ip=cfg->excludenamelookup;ip;ip=ip_next) {
	    ip_next = ip->next;
	    free(ip);
	}
	for(pr=cfg->promisc;pr;pr=pr_next) {
	    pr_next = pr->next;
	    free(pr);
	}
	for(pr=cfg->notdev;pr;pr=pr_next) {
	    pr_next = pr->next;
	    free(pr);
	}
	for(pr=cfg->iflist;pr;pr=pr_next) {
	    pr_next = pr->next;
	    free(pr);
	}
	for(h=cfg->headers;h;h=h_next) {
	    h_next = h->next;
	    free(h);
	}
	for(mh=cfg->hostlist;mh;mh=mh_next) {
	    mh_next = mh->next;
	    free(mh);
	}
	free(cfg);
      }
      cfg = read_config(fname);
      init_capture();
  }
  else
    {
      DEBUG(DBG_SIGNAL, sprintf(dbg, "signal_debug received signal %d, this can't happen\n", sig));
      syslog(LOG_INFO,"signal_debug received signal %d, this can't happen\n", sig);
    }
}

void signal_ignore(int sig)
{
  DEBUG(DBG_SIGNAL, sprintf(dbg, "got signal %d, ignoring\n", sig));
}



