Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4042990
  • 博文数量: 536
  • 博客积分: 10470
  • 博客等级: 上将
  • 技术积分: 4825
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-26 14:08
文章分类

全部博文(536)

文章存档

2024年(3)

2021年(1)

2019年(1)

2017年(1)

2016年(2)

2013年(2)

2012年(10)

2011年(43)

2010年(10)

2009年(17)

2008年(121)

2007年(252)

2006年(73)

分类:

2007-08-23 16:25:19

learn IEEE802.3 TCP/IP UDP protocol format

compile method:
$gcc -Wall -o sniffer sniffer.c

run with root user for test:
$./sinffer

Test environment:
$gcc -v
gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)

code filename: sniffer.c
----------

#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, &ethreq);
  ethreq.ifr_flags |= IFF_PROMISC;
  ioctl(sd, SIOCSIFFLAGS, &ethreq);

  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);
}

阅读(2665) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~