/*
     etherscan - A real time network security monitor
     Copyright (C) 1993 Douglas Lee Schales, David K. Hess, David R. Safford

     Please see the file `RESTRICTIONS' for the complete copyright notice.

pktfilt.c - 05/23/93

*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef SUNOS4
#include <net/nit_pf.h>
#include <net/packetfilt.h>
#endif

#ifdef SOLARIS
#include <sys/pfmod.h>
#endif

#include <netinet/in.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <sys/stropts.h>
#include <netdb.h>
#include <netinet/in.h>

#define offsetof(T, m) ((size_t)&(((T *)0)->m))

/*
  Rename some of the packet filter operators so that
   the names reflect what they actually do
*/

/* Short circuit if equal and keep packet */
#define ENF_CEQ ENF_COR
/* Short circuit if not equal and keep packet */
#define ENF_CNE ENF_CNAND
/* Short circuit if equal and reject packet */
#define ENF_RCEQ ENF_NOR
/* Short circuit if not equal and reject packet */
#define ENF_RCNE ENF_CAND

void
pktfilt(int fd, char **ports, int udpmon)
{
#ifdef SOLARIS
     struct strioctl ioc;
#endif
     struct packetfilt pf;
     u_short *ptr;
     struct servent *se;

     pf.Pf_Priority = 0;
     ptr = pf.Pf_Filter;
     *ptr++ = ENF_PUSHWORD + 6;
     *ptr++ = ENF_PUSHLIT|ENF_RCNE;
     *ptr++ = htons(ETHERTYPE_IP);
     if(udpmon){
	  *ptr++ = ENF_PUSHWORD + 11;
	  *ptr++ = ENF_PUSHLIT|ENF_AND;
	  *ptr++ = 0x00ff;
	  *ptr++ = ENF_PUSHLIT|ENF_CEQ;
	  *ptr++ = IPPROTO_UDP;
     }
     *ptr++ = ENF_PUSHWORD + 11;
     *ptr++ = ENF_PUSHLIT|ENF_AND;
     *ptr++ = 0x00ff;
     *ptr++ = ENF_PUSHLIT|ENF_RCNE;
     *ptr++ = IPPROTO_TCP;
     for(;*ports;ports++){
	  char *portp = *ports;
	  int srcport = 0;
	  if(*portp == '+'){
	       portp++;
	       srcport++;
	  }
	  *ptr++ = ENF_PUSHWORD + 18;
	  *ptr++ = ENF_PUSHLIT|ENF_CEQ;
	  if(isnumstr(portp)){
	       *ptr++ = htons((unsigned short)atoi(portp));
	       printf("Added %d\n", atoi(portp));
	       if(srcport){
		    *ptr++ = ENF_PUSHWORD + 17;
		    *ptr++ = ENF_PUSHLIT|ENF_CEQ;
		    *ptr++ = htons((unsigned short)atoi(portp));
		    printf("Added src=%d\n", atoi(portp));
	       }
	  }
	  else {
	       if(se = getservbyname(portp, "tcp")){
		    *ptr++ = se->s_port;
		    printf("Added %s\n", portp);
		    if(srcport){
			 *ptr++ = ENF_PUSHWORD + 17;
			 *ptr++ = ENF_PUSHLIT|ENF_CEQ;
			 *ptr++ = se->s_port;
			 printf("Added src=%s\n", portp);
		    }
	       }
	       else {
		    fprintf(stderr, "Unknown service %s\n", portp);
		    exit(1);
	       }
	  }
     }
     fflush(stdout);
     *ptr++ = ENF_PUSHZERO;

     pf.Pf_FilterLen = ptr - &pf.Pf_Filter[0];

#ifdef SUNOS4
     if(ioctl(fd, NIOCSETF, &pf) == -1)
	  perror("pf setf");
#endif

#ifdef SOLARIS
     ioc.ic_cmd = PFIOCSETF;
     ioc.ic_timout = -1;
     ioc.ic_len = sizeof(struct packetfilt);
     ioc.ic_dp = (char *)&pf;
     if(ioctl(fd, I_STR, &ioc) == 01)
	  perror("pfmod setf");
#endif
}

     
