/* snooper.c
*
* Copyright (c) 2000 Sean Walton and Macmillan Publishers. Use may be in
* whole or in part in accordance to the General Public License (GPL).
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*****************************************************************************/
/*** snooper.c ***/
/*** ***/
/*** This program captures *all* packets that the network interface sees. ***/
/*** Be very careful with this tool, because you may see all lot of info. ***/
/*** Also, it uses the deprecated SOCK_PACKET socket type. The newer and ***/
/*** preferred method is with PF_PACKET. ***/
/*****************************************************************************/
#include <stdio.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#define IP_SIZE 4
#define ETH_SIZE 6
typedef enum { eETH_ADDR, eIP_ADDR } EAddress;
typedef unsigned char uchar;
/*--------------------------------------------------------------------*/
/* Ethernet Frame */
/* */
/* This structure defines the fields within the ethernet frame. Since */
/* this programs gets the lowest-level packet, fragmented packets are */
/* not reassembled. The first few fields contain the MAC addresses */
/* of the source and destination. Note that this structure is set for */
/* little-endian format. */
/*--------------------------------------------------------------------*/
struct ip_packet {
struct {
uchar dst_eth[ETH_SIZE];
uchar src_eth[ETH_SIZE];
uchar __unknwn[2];
} hw_header; /* hardware header */
uint header_len:4; /* header length in words in 32bit words */
uint version:4; /* 4-bit version */
uint serve_type:8; /* how to service packet */
uint packet_len:16; /* total size of packet in bytes */
uint ID:16; /* fragment ID */
uint frag_offset:13; /* to help reassembly */
uint more_frags:1; /* flag for "more frags to follow" */
uint dont_frag:1; /* flag to permit fragmentation */
uint __reserved:1; /* always zero */
uint time_to_live:8; /* maximum router hop count */
uint protocol:8; /* ICMP, UDP, TCP */
uint hdr_chksum:16; /* ones-comp. checksum of header */
uchar IPv4_src[IP_SIZE]; /* IP address of originator */
uchar IPv4_dst[IP_SIZE]; /* IP address of destination */
uchar options[0]; /* up to 40 bytes */
uchar data[0]; /* message data up to 64KB */
};
/*--------------------------------------------------------------------*/
/* dump */
/* */
/* Dump a block of data in hex & ascii. */
/*--------------------------------------------------------------------*/
void dump(void* b, int len)
{ unsigned char *buf = b;
int i, cnt=0;
char str[17];
memset(str, 0, 17);
for ( i = 0; i < len; i++ )
{
if ( cnt % 16 == 0 )
{
printf(" %s\n%04X: ", str, cnt);
memset(str, 0, 17);
}
if ( buf[cnt] < ' ' || buf[cnt] >= 127 )
str[cnt%16] = '.';
else
str[cnt%16] = buf[cnt];
printf("%02X ", buf[cnt++]);
}
printf(" %*s\n\n", 16+(16-len%16)*2, str);
}
/*--------------------------------------------------------------------*/
/* PrintAddr */
/* */
/* Print the different types of address (MAC or IP). */
/*--------------------------------------------------------------------*/
void PrintAddr(char* msg, uchar *addr, EAddress is_ip)
{ int i;
static struct {
int len;
char *fmt;
char delim;
} addr_fmt[] = {{ETH_SIZE, "%x", ':'}, {IP_SIZE, "%d", '.'}};
printf("%s", msg);
for ( i = 0; i < addr_fmt[is_ip].len; i++ )
{
printf(addr_fmt[is_ip].fmt, addr[i]);
if ( i < addr_fmt[is_ip].len-1 )
putchar(addr_fmt[is_ip].delim);
}
}
/*--------------------------------------------------------------------*/
/* GetProtocol */
/* */
/* Convert the protocol value into the alphabetic representation. */
/*--------------------------------------------------------------------*/
char* GetProtocol(int value)
{
switch (value)
{
case IPPROTO_IP: return "IP";
case IPPROTO_ICMP: return "ICMP";
case IPPROTO_IGMP: return "IGMP";
case IPPROTO_IPIP: return "IPIP";
case IPPROTO_TCP: return "TCP";
case IPPROTO_EGP: return "EGP";
case IPPROTO_PUP: return "PUP";
case IPPROTO_UDP: return "UDP";
case IPPROTO_IDP: return "IDP";
case IPPROTO_RSVP: return "RSVP";
case IPPROTO_GRE: return "GRE";
case IPPROTO_IPV6: return "IPV6/4";
case IPPROTO_PIM: return "PIM";
case IPPROTO_RAW: return "RAW";
default: return "???";
}
}
/*--------------------------------------------------------------------*/
/* DumpPacket */
/* */
/* Display the read packet with data and fields. */
/*--------------------------------------------------------------------*/
void DumpPacket(char *buffer, int len)
{ struct ip_packet *ip=(void*)buffer;
printf("-------------------------------------------------\n");
dump(buffer, len);
PrintAddr("Destination EtherID=", ip->hw_header.dst_eth, eETH_ADDR);
PrintAddr(", Source EtherID=", ip->hw_header.src_eth, eETH_ADDR);
printf("\nIPv%d: header-len=%d, type=%d, packet-size=%d, ID=%d\n",
ip->version, ip->header_len*4, ip->serve_type,
ntohs(ip->packet_len), ntohs(ip->ID));
printf("frag=%c, more=%c, offset=%d, TTL=%d, protocol=%s\n",
(ip->dont_frag? 'N': 'Y'),
(ip->more_frags? 'N': 'Y'),
ip->frag_offset,
ip->time_to_live, GetProtocol(ip->protocol));
printf("checksum=%d, ", ntohs(ip->hdr_chksum));
PrintAddr("source=", ip->IPv4_src, eIP_ADDR);
PrintAddr(", destination=", ip->IPv4_dst, eIP_ADDR);
printf("\n");
fflush(stdout);
}
void PANIC(char *msg);
#define PANIC(msg) {perror(msg);exit(0);}
/*--------------------------------------------------------------------*/
/* main */
/* */
/* Open socket. Repeatedly read and display records. */
/*--------------------------------------------------------------------*/
int main()
{ int sd, bytes_read;
char data[1024];
sd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
if ( sd < 0 )
PANIC("Snooper socket");
do
{
bytes_read = recvfrom(sd, data, sizeof(data), 0, 0, 0);
if ( bytes_read > 0 )
DumpPacket(data, bytes_read);
}
while ( bytes_read > 0 );
return 0;
}