
/* Copyright (C) Gerhard Fuernkranz 1992 */

#include "matcher.h"

static unsigned short default_prog[] = { (unsigned short) UACCEPT };

static unsigned short *global_pc = default_prog;

static void
set_pc(unsigned short *pc)
{
	global_pc = pc;
}

static int
matcher (unsigned long src, unsigned long dst,
	 unsigned short sport, unsigned short dport,
	 unsigned short proto)
{
  unsigned short *pc = global_pc;
  unsigned short *ps;
  unsigned long *pl;
  char truth = 0;
  unsigned short n;

  if ((OPCODE)(*pc) == UACCEPT)
    return;

  for (;;)
    {
      switch ((OPCODE) (*pc++))
	{
	case UACCEPT:
	  return 1;
	case UDENY:
	default:
	  printf("ipacl: 0x%x 0x%x %d %d %d\n", src, dst, sport, dport, proto);
	  printf("ipacl: deny\n");
	  return 0;

	case TACCEPT:
	  if (truth)
	    return 1;
	  break;
	case FACCEPT:
	  if (!truth)
	    return 1;
	  break;
	case TDENY:
	  if (truth)
	    {
	      printf("ipacl: 0x%x 0x%x %d %d %d\n", src, dst, sport, dport, proto);
	      printf("ipacl: deny\n");
	      return 0;
	    }
	  break;
	case FDENY:
	  if (!truth)
	    {
	      printf("ipacl: 0x%x 0x%x %d %d %d\n", src, dst, sport, dport, proto);
	      printf("ipacl: deny\n");
	      return 0;
	    }
	  break;
	case TJMP:
	  if (truth)
	    pc = pc + *(short *) pc;
	  else
	    pc++;
	  break;
	case FJMP:
	  if (!truth)
	    pc = pc + *(short *) pc;
	  else
	    pc++;
	  break;
	case JMP:
	  pc = pc + *(short *) pc;
	  break;

	  /* source address comparison */

	case SAEQ:
	  pl = (unsigned long *) pc;
	  truth = ((src ^ pl[0]) & pl[1]) == 0;
	  pc = (unsigned short *) (pl + 2);
	  break;
	case SANE:
	  pl = (unsigned long *) pc;
	  truth = ((src ^ pl[0]) & pl[1]) != 0;
	  pc = (unsigned short *) (pl + 2);
	  break;
	case SAIN:
	  pl = (unsigned long *) (pc + *(short *) pc);
	  pc++;
	  n = *pc++;
	  while (n != 0 && ((src ^ pl[0]) & pl[1]) != 0)
	    {
	      pl += 2;
	      n--;
	    }
	  truth = (n != 0);
	  break;
	case SANIN:
	  pl = (unsigned long *) (pc + *(short *) pc);
	  pc++;
	  n = *pc++;
	  while (n != 0 && ((src ^ pl[0]) & pl[1]) != 0)
	    {
	      pl += 2;
	      n--;
	    }
	  truth = (n == 0);
	  break;

	  /* destination address comparison */

	case DAEQ:
	  pl = (unsigned long *) pc;
	  truth = ((dst ^ pl[0]) & pl[1]) == 0;
	  pc = (unsigned short *) (pl + 2);
	  break;
	case DANE:
	  pl = (unsigned long *) pc;
	  truth = ((dst ^ pl[0]) & pl[1]) != 0;
	  pc = (unsigned short *) (pl + 2);
	  break;
	case DAIN:
	  pl = (unsigned long *) (pc + *(short *) pc);
	  pc++;
	  n = *pc++;
	  while (n != 0 && ((dst ^ pl[0]) & pl[1]) != 0)
	    {
	      pl += 2;
	      n--;
	    }
	  truth = (n != 0);
	  break;
	case DANIN:
	  pl = (unsigned long *) (pc + *(short *) pc);
	  pc++;
	  n = *pc++;
	  while (n != 0 && ((dst ^ pl[0]) & pl[1]) != 0)
	    {
	      pl += 2;
	      n--;
	    }
	  truth = (n == 0);
	  break;

	  /* source port comparison */

	case SPEQ:
	  truth = (proto == pc[0] && sport == pc[1]);
	  pc += 2;
	  break;
	case SPNE:
	  truth = (proto != pc[0] || sport != pc[1]);
	  pc += 2;
	  break;
	case SPLT:
	  truth = (proto == pc[0] && sport < pc[1]);
	  pc += 2;
	  break;
	case SPGT:
	  truth = (proto == pc[0] && sport > pc[1]);
	  pc += 2;
	  break;
	case SPLE:
	  truth = (proto == pc[0] && sport <= pc[1]);
	  pc += 2;
	  break;
	case SPGE:
	  truth = (proto == pc[0] && sport >= pc[1]);
	  pc += 2;
	  break;
	case SPIN:
	  ps = pc + *(short *) pc;
	  pc++;
	  n = *pc++;
	  while (n != 0 && (proto != ps[0] || sport != ps[1]))
	    {
	      ps += 2;
	      n--;
	    }
	  truth = (n != 0);
	  break;
	case SPNIN:
	  ps = pc + *(short *) pc;
	  pc++;
	  n = *pc++;
	  while (n != 0 && (proto != ps[0] || sport != ps[1]))
	    {
	      ps += 2;
	      n--;
	    }
	  truth = (n == 0);
	  break;

	  /* destination port comparison */

	case DPEQ:
	  truth = (proto == pc[0] && dport == pc[1]);
	  pc += 2;
	  break;
	case DPNE:
	  truth = (proto != pc[0] || dport != pc[1]);
	  pc += 2;
	  break;
	case DPLT:
	  truth = (proto == pc[0] && dport < pc[1]);
	  pc += 2;
	  break;
	case DPGT:
	  truth = (proto == pc[0] && dport > pc[1]);
	  pc += 2;
	  break;
	case DPLE:
	  truth = (proto == pc[0] && dport <= pc[1]);
	  pc += 2;
	  break;
	case DPGE:
	  truth = (proto == pc[0] && dport >= pc[1]);
	  pc += 2;
	  break;
	case DPIN:
	  ps = pc + *(short *) pc;
	  pc++;
	  n = *pc++;
	  while (n != 0 && (proto != ps[0] || dport != ps[1]))
	    {
	      ps += 2;
	      n--;
	    }
	  truth = (n != 0);
	  break;
	case DPNIN:
	  ps = pc + *(short *) pc;
	  pc++;
	  n = *pc++;
	  while (n != 0 && (proto != ps[0] || dport != ps[1]))
	    {
	      ps += 2;
	      n--;
	    }
	  truth = (n == 0);
	  break;
	}
    }
}
