#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdint.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#define SNIF_BUFFER_SIZE 8192
struct recv_packet
{
struct ether_header *ethdr; /* IEEE802.3 Ethernet header */
struct iphdr *iphdr; /* IP packet header */
struct udphdr *udphdr; /* UDP packet header */
struct tcphdr *tcphdr; /* TCP packet header */
uint8_t *data; /* pointer to data */
uint32_t len; /* data length */
};
/**
* print ip packet information
*/
static void print_eth_header(struct ether_header *etp);
static void print_ip_header(struct iphdr *ip);
static void print_udp_header(struct udphdr *up);
static void print_tcp_header(struct tcphdr *up);
static void print_data(uint8_t *p, uint32_t len);
static int is_filter(struct recv_packet *rcv);
/**
* CTRL + C for exit
*/
static int isc;
static void exit_while(int signo)
{
isc = 0;
}
int main(int argc, char **argv)
{
int sd, rlen;
unsigned char buf[SNIF_BUFFER_SIZE], *p, *pe;
struct ifreq ethreq;
struct recv_packet rcv;
/* Ctrl+C */
signal(SIGINT, exit_while);
if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
{
fprintf(stderr, "socket create error: %s\n", strerror(errno));
goto err_1;
}
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
ioctl(sd, SIOCGIFFLAGS, ðreq);
ethreq.ifr_flags |= IFF_PROMISC;
ioctl(sd, SIOCSIFFLAGS, ðreq);
p = buf;
rcv.ethdr = (struct ether_header *)p;
p += sizeof(struct ether_header);
rcv.iphdr = (struct iphdr *)p;
p += sizeof(struct iphdr);
rcv.udphdr = (struct udphdr *)p;
rcv.tcphdr = (struct tcphdr *)p;
isc = 1;
while (isc)
{
rlen = recvfrom(sd, buf, SNIF_BUFFER_SIZE, 0, NULL, NULL);
if (rlen < 42)
{
fprintf(stderr, "Recv incomplete header information. \n");
continue;
}
/* pointer to data end */
pe = buf + rlen;
if (is_filter(&rcv) == 1)
continue;
print_eth_header(rcv.ethdr);
print_ip_header(rcv.iphdr);
switch (rcv.iphdr->protocol)
{
case IPPROTO_UDP:
print_udp_header(rcv.udphdr);
rcv.data = (uint8_t *)rcv.udphdr + sizeof(struct udphdr);
break;
case IPPROTO_TCP:
print_tcp_header(rcv.tcphdr);
rcv.data = (uint8_t *)rcv.tcphdr + sizeof(struct tcphdr);
break;
}
rcv.len = pe - rcv.data;
print_data(rcv.data, rcv.len);
printf("\n");
}
close(sd);
return (0);
err_1:
return (-1);
}
static int is_filter(struct recv_packet *rcv)
{
uint32_t saddr, daddr;
#if 0
uint32_t spip;
#endif
saddr = ntohl(rcv->iphdr->saddr);
daddr = ntohl(rcv->iphdr->daddr);
#if 0
/* set your sniffer IP */
spip = ntohl(inet_addr("192.168.1.84"));
#endif
/* filter the loopback packet */
if (saddr == INADDR_LOOPBACK || daddr == INADDR_LOOPBACK)
return (1);
#if 0
if (saddr == spip || daddr == spip)
return (0);
else
return (1);
#endif
return (0);
}
/**
* IEEE 802.3
*/
static void print_eth_header(struct ether_header *etp)
{
#define _XFF(t) ((t)&0xFF)
#define SNIF_ADDR_MAC(p) \
_XFF((p)[0]),_XFF((p)[1]),_XFF((p)[2]),_XFF((p)[3]),_XFF((p)[4]),_XFF((p)[5])
/* dest mac addr [6] | src mac addr [6] | type [2]
* | ip data packet
*/
printf("MAC: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X ==> %.2X:%.2X:%.2X:%.2X:%.2X:%.2X "
, SNIF_ADDR_MAC(etp->ether_shost)
, SNIF_ADDR_MAC(etp->ether_dhost));
printf("type.");
switch (ntohs(etp->ether_type))
{
case ETHERTYPE_PUP: printf("Xerox PUP "); break;
case ETHERTYPE_IP: printf("IP "); break;
case ETHERTYPE_ARP: printf("ARP "); break;
case ETHERTYPE_REVARP: printf("RARP "); break;
default: printf("Unkown type "); break;
}
printf("\n");
}
/**
* IP data packet header
*/
static void print_ip_header(struct iphdr *ip)
{
struct in_addr saddr, daddr;
char sip[24], dip[24];
/* ver 4bit | header length 4bits | TOS 8bits | total length 16 bits
* flags identification 16bits | flags 3bits | offset 13bits
* TTL 8 bits | protocol type 8bits | checksum 16bits
* src ip address 32bits
* dest ip address 32bits
* options values
*
* tcp/udp data packet
*/
saddr.s_addr = ip->saddr;
strcpy(sip, inet_ntoa(saddr));
daddr.s_addr = ip->daddr;
strcpy(dip, inet_ntoa(daddr));
printf("IP %s ==> %s \n", sip, dip);
printf("IP Packet: ver.%d header-length.%d TOS.%04X total-len.%d TTL.%d \n"
"id.%d offset.%d checksum.%d "
, ip->version, ip->ihl, ip->tos, ntohs(ip->tot_len), ip->ttl
, ntohs(ip->id), ntohs(ip->frag_off), ntohs(ip->check)
);
printf("protocol.");
switch (ip->protocol)
{
case IPPROTO_ICMP: printf("ICMP "); break;
case IPPROTO_IGMP: printf("IGMP "); break;
case IPPROTO_IPIP: printf("IPIP "); break;
case IPPROTO_RAW: printf("RAW "); break;
case IPPROTO_TCP: printf("TCP "); break;
case IPPROTO_UDP: printf("UDP "); break;
default:
printf("Unkown protocol type.%d ", ip->protocol);
}
printf("\n");
}
/**
* UDP data packet header
*/
static void print_udp_header(struct udphdr *up)
{
printf("UDP src-port.%d dest-port.%d len.%d checksum.%d "
, ntohs(up->source), ntohs(up->dest)
, ntohs(up->len), ntohs(up->check));
printf("\n");
}
/**
* TCP data packet header
*/
static void print_tcp_header(struct tcphdr *tp)
{
printf("TCP src-port.%d dest-port.%d seq.%u ack_seq.%u \n"
"windows.%d checksum.%d pointer.%d "
, ntohs(tp->source), ntohs(tp->dest)
, ntohl(tp->seq), ntohl(tp->ack_seq)
, ntohs(tp->window), ntohs(tp->check), ntohs(tp->urg_ptr));
if (tp->syn) printf("syn ");
if (tp->rst) printf("rst ");
if (tp->ack) printf("ack ");
if (tp->psh) printf("psh ");
if (tp->fin) printf("fin ");
if (tp->urg) printf("urg ");
printf("\n");
}
/**
* dump data information
*/
static void print_data(uint8_t *p, uint32_t len)
{
int i, nlen, j;
int flg, ll;
char cch[62];
printf("data.%p data-len.%d \n", p, len);
nlen = ll = 20;
for (i = j = 0; i < len; i++, j++)
{
printf("%02X", p[i]);
if ((i+1) % 4 == 0)
{
flg = 1;
printf(" ");
}
else
flg = 0;
cch[j] = (isprint(p[i])) ? p[i] : '.';
if (j >= nlen && flg == 1)
{
ll = j;
cch[j+1] = '\0';
printf(" %s\n", cch);
j = -1;
}
}
cch[j] = '\0';
for (; j <= ll; j++)
{
printf(" ");
if ((j+1) % 4 == 0) printf(" ");
}
printf(" %s\n", cch);
}
|