/******************************************************************************
*                                                                             *
*   Copyright 2005 University of Cambridge Computer Laboratory.               *
*                                                                             *
*   This file is part of Nprobe.                                              *
*                                                                             *
*   Nprobe is free software; you can redistribute it and/or modify            *
*   it under the terms of the GNU General Public License as published by      *
*   the Free Software Foundation; either version 2 of the License, or         *
*   (at your option) any later version.                                       *
*                                                                             *
*   Nprobe is distributed in the hope that it will be useful,                 *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
*   GNU General Public License for more details.                              *
*                                                                             *
*   You should have received a copy of the GNU General Public License         *
*   along with Nprobe; if not, write to the Free Software                     *
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
*                                                                             *
******************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <linux/limits.h>
#include <sys/time.h>
#include <assert.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "http_errdefs.h"
#include "basic_defs.h"
#include "list.h"
#include "counters.h"
#include "np_file.h"
#include "flows.h"
#include "cfilter.h"

void 
_filter_help()
{
  printf("\ncfilter: pre-defined connection filters:\n\n");
  printf(" #  Filter\n");
  printf(" _  ______\n");

  printf(" 1 Server port 80\n");
  printf(" 2 Server port 8080\n");
  printf(" 3 Server port 8008\n");
  printf("10 Server wwwcache.cam.ac.uk\n");
  printf("11 Not server wwwcache.cam.ac.uk\n");
  printf("12 Client wwwcache.cam.ac.uk\n");
  printf("13 Not client wwwcache.cam.ac.uk\n");
  printf("15 Server www.cam.ac.uk\n");
  printf("16 Server www.cl.cam.ac.uk\n");
  printf("17 Non-local client\n");
  printf("18 Non-local server\n");
  printf("19 Non-local server and client not local cache\n");
  printf("20 Server news.bbc.co.uk\n");
  printf("30 Client snapper.cl.cam.ac.uk\n");
  printf("31 Client repton.cl.cam.ac.uk\n");
  printf("32 Client chuckie.cl.cam.ac.uk\n");
  printf("33 Not clients chuckie.cl.cam.ac.uk or snapper.cl.cam.ac.uk\n");
  printf("34 Server news.bbc.co.uk and not clients chuckie.cl.cam.ac.uk or snapper.cl.cam.ac.uk\n");
  printf("50 Not client wwwcache.cam.ac.uk and not server x.guardian.co.uk\n");
  printf("60 Server gibbs.dcs.gla.ac.uk\n");
}

unsigned long 
_inet_addr(char *cp)
{
  struct in_addr addr;

  if (inet_aton(cp, &addr) == 0)
    {
      fprintf(stderr, "local_inet_addr: invalid address %s\n", cp);
      exit (1);
    }

  return *((unsigned long *)&addr);
}

int 
is_net(unsigned long addr, char *netspec)
{
  char *ap = netspec;
  unsigned long net = 0x0, mask = 0x0;
  unsigned char *net8 = (unsigned char *)&net, *mask8 = (unsigned char *)&mask;
  int fi = 0;

  while (fi < 3)
    {
      if (*ap == '.')
        {
          ap++;
          continue;
        }
      else if (*ap == 'x')
        {
          mask8[fi++] = 0x00;
          ap++;
        }
      else 
        {
          mask8[fi] = 0xff;
          net8[fi++] = strtoul(ap, &ap, 0) & 0xff;
        }
    }
  
  if (fi != 3)
    {
      printf("bad net filter\n");
      exit (1);
    }
  else
    {
      mask8[3] = 0x00;
    }

  //printf("addr %x net %x mask %x\n", addr, net, mask);

  
  return ((addr & mask) == net);
}

int is_local_net(unsigned long addr)
{
  return (
	  /* local Class Bs */
	  is_net(addr, "128.232.x.x") /* cl.cam.ac.uk */
	  || is_net(addr, "129.169.x.x") /* eng.cam.uk */
	  || is_net(addr, "131.111.x.x") /* cam.ac.uk */
	  || is_net(addr, "158.124.x.x") /* orl2 */
	  || is_net(addr, "193.60.x.x")	/* c01camacuk a class B or several class Cs ? */
	  /* local Class Cs */
	  || is_net(addr, "192.5.239.x") /* orl */
	  || is_net(addr, "192.18.195.x") /* mrc apu */
	  || is_net(addr, "192.153.213")	/* gw */
	  || is_net(addr, "192.31.62.x") /* sri - out of use? */
	  || is_net(addr, "192.84.5.x") /* mrc bsu */
	  || is_net(addr, "193.60.80.x") /* C00 cam.ac.uk - sparte? */
	  );
}

int is_camcs_cache(unsigned long addr)
{

  return (is_net(addr, "131.111.8.x") 
	  && (is_net(addr, "x.x.x.96")
	      || is_net(addr, "x.x.x.97")
	      || is_net(addr, "x.x.x.98")
	      || is_net(addr, "x.x.x.99")
	      || is_net(addr, "x.x.x.100")
	      || is_net(addr, "x.x.x.101")
	      || is_net(addr, "x.x.x.102")
	      || is_net(addr, "x.x.x.103")
	      || is_net(addr, "x.x.x.1")
	      || is_net(addr, "x.x.x.36")
	      )
	  );
  
}

int is_guardian(unsigned long addr)
{
  return is_net(addr, "195.153.x.x");
}


	  



int _pass(flow_inner_t *f, int fspec)
{

  switch (fspec)
    {
    case 0:
      return 1;
      break;
    case 1:
      if (ntohs(f->dstport) == 80)
	return 1;
      break;
    case 2:
      if (ntohs(f->dstport) == 8080)
	return 1;
      break;
    case 3:
      if (ntohs(f->dstport) == 8008)
	return 1;
      break;
    case 10:
      /* server wwwcache.cam.ac.uk */
      return is_camcs_cache(f->dstaddr);
      break;
    case 11:
      /* not server wwwcache.cam.ac.uk */
      return !is_camcs_cache(f->dstaddr);
      break;
    case 12:
      /* client wwwcache.cam.ac.uk */
      return is_camcs_cache(f->srcaddr);
      break;
    case 13:
      /* not client wwwcache.cam.ac.uk */
      return !is_camcs_cache(f->srcaddr);
      break;
    case 15:
      /* Server www.cam.ac.uk */
      if (f->dstaddr == _inet_addr("131.111.8.46"))
	return 1;
      break;
    case 16:
      /* Server www.cl.cam.ac.uk */
      if (f->dstaddr == _inet_addr("128.232.0.20"))
	return 1;
      break;
    case 17:
      /* Not local client */
      return !(is_local_net(f->srcaddr));
      break;
    case 18:
      /* Not local server */
      return !(is_local_net(f->dstaddr));
      break;
    case 19:
      /* Not local server and client not local cache*/
      return !(is_local_net(f->dstaddr)) && !(f->srcaddr == _inet_addr("131.111.8.68"));
      break;
      /* Server news.bbc.co.uk */
    case 20:
      if (f->dstaddr ==  _inet_addr("212.58.226.40"))
	return 1;
      break;
      /* Client snapper.cl.cam.ac.uk */
    case 30:
      if (f->srcaddr ==  _inet_addr("128.232.8.80"))
	return 1;
      break;
      /* Client repton.cl.cam.ac.uk */
    case 31:
      if (f->srcaddr ==  _inet_addr("128.232.8.58"))
	return 1;
      break;
      /* Client chuckie.cl.cam.ac.uk */
    case 32:
      if (f->srcaddr ==  _inet_addr("128.232.8.59"))
	return 1;
      break;
      /* Not clients chuckie.cl.cam.ac.uk or snapper.cl.cam.ac.uk */
    case 33:
      if (f->srcaddr ==  _inet_addr("128.232.8.59")
	  || f->srcaddr ==  _inet_addr("128.232.8.80"))
	return 0;
      else
	return 1;
      break;
      /* Not clients chuckie.cl.cam.ac.uk or snapper.cl.cam.ac.uk 
       and server news.bbc.co.uk */
    case 34:
      if (!(f->dstaddr ==  _inet_addr("212.58.226.40"))
	  || (f->srcaddr ==  _inet_addr("128.232.8.59")
	  || f->srcaddr ==  _inet_addr("128.232.8.80")))
	return 0;
      else
	return 1;
      break;
      /* Not client wwwcache.cam.ac.uk and not server x.guardian.co.uk */
    case 50:
      return !(is_camcs_cache(f->srcaddr) || is_guardian(f->dstaddr));
	      break;
      /* Server gibbs.dcs.gla.ac.uk */
    case 60:
      if (f->dstaddr ==  _inet_addr("130.209.240.168"))
	return 1;
      break;
    default:
      fprintf(stderr, "cfilter.c:pass() - unknown filter spec %d\n", fspec);
      exit (1);
      break;

    }

  return 0;
}
