网络嗅探器

该项目相关知识点已经放到“网络嗅探器”标签中

下面是相关头文件

/*
sniffer.h
*/
#ifndef __SNIFFER_H__
#define __SNIFFER_H__

typedef struct s_protocol
{
    int tcp;
    int udp;
    int icmp;
    int igmp;
    int others;
    int total;
}t_protocol;

typedef struct s_sinffer
{
    FILE *logfile;
    t_protocol *prot;
}t_sniffer;

void ProcessPacket(unsigned char *, int, t_sniffer *);
void print_ip_header(unsigned char *, int, t_sniffer *);
void print_tcp_packet(unsigned char *, int, t_sniffer *);
void print_udp_packet(unsigned char *, int, t_sniffer *);
void print_icmp_packet(unsigned char *, int, t_sniffer *);
void PrintData(unsigned char *, int, t_sniffer*);
void display_time_and_data();
void getting_started();
void signal_white_now(int);

#endif

输出颜色定义

/*
tool.h
*/
#ifndef __COLOR_H__
#define __COLOR_H__

#include<stdio.h>

#define CLEARSCREEN() printf("33[H33[2J")
#define INITCOLOR(color) printf("33[%sm",color)
#define RED_COLOR    "31"
#define GREEN_COLOR    "32"
#define YELLOW_COLOR    "33"
#define BLUE_COLOR    "34"
#define ZERO_COLOR    "0"

#endif

暂停或退出的信号处理

/*
tool.c
*/
#include<stdio.h>
#include<signal.h>

void signal_white_now(int signum)
{
    printf("Bye Bye !
");
}

数据包 分解打印

/*
show_data.c
*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netinet/ip_icmp.h>
#include<netinet/udp.h>
#include<netinet/tcp.h>
#include<netinet/ip.h>
#include<sys/socket.h>
#include<arpa/inet.h>

#include"sniffer.h"
#include"tools.h"

//将ip头部信息解析出来输出到文件中
void print_ip_header(unsigned char *buf,int size, t_sniffer *sniffer)
{
    unsigned short iphdrlen;
    struct iphdr *iph;
    struct sockaddr_in source;
    struct sockaddr_in dest;
    
    iph = (struct iphdr *)buf;
    iphdrlen = iph->ihl*4; //iph->ihl首部长度,乘以4是因为是以4字节为单位
    (void)iphdrlen;
    (void)size;
    memset(&source, 0, sizeof(source));
    source.sin_addr.s_addr = iph->saddr;
    
    memset(&dest, 0, sizeof(dest));
    dest.sin_addr.s_addr = iph->daddr;
    
    fprintf(sniffer->logfile,"
");
    fprintf(sniffer->logfile,"IP Header
");
    fprintf(sniffer->logfile,"    |-IP Version        :%d
",(unsigned int)iph->version);    
    fprintf(sniffer->logfile,"    |-IP Header Length    :%d DWORDS  or %d Bytes
",(unsigned int)iph->ihl,((unsigned int)(iph->ihl)) * 4);
    fprintf(sniffer->logfile,"    |-Type Of Service    :%d
",(unsigned int)iph->tos);    
    fprintf(sniffer->logfile,"    |-Identification    :%d
",ntohs(iph->id));
    fprintf(sniffer->logfile,"    |-TTL            :%d
",(unsigned int)iph->ttl);
    fprintf(sniffer->logfile,"    |-Protocol        :%d
",(unsigned int)iph->protocol);    
    fprintf(sniffer->logfile,"    |-Checksum        :%d
",ntohs(iph->check));    
    fprintf(sniffer->logfile,"    |-Source IP        :%s
",inet_ntoa(source.sin_addr));
    fprintf(sniffer->logfile,"    |-Destination IP    :%s
",inet_ntoa(dest.sin_addr));    
}

void print_tcp_packet(unsigned char *buf, int size , t_sniffer *sniffer)
{
    unsigned short iphdrlen;
    struct iphdr *iph;
    struct tcphdr *tcph;
    
    iph = (struct iphdr *)buf;
    iphdrlen = iph->ihl * 4;
    tcph = (struct tcphdr*)(buf + iphdrlen); //跳过ip头部,就是tcp数据内存。buf里存储就是ip头部字节数
    print_ip_header(buf, size, sniffer);        //传过去的size是整个接收数据的长度,但是使用时都截取了相应的长度
    
    fprintf(sniffer->logfile,"
");
    fprintf(sniffer->logfile,"TCP Header
");
    fprintf(sniffer->logfile,"    |-Source Port    :%u
",ntohs(tcph->source));
    fprintf(sniffer->logfile,"    |-Destination Port    :%u
",ntohs(tcph->dest));
    fprintf(sniffer->logfile,"    |-Sequence Number    :%u
",ntohl(tcph->dest));
    fprintf(sniffer->logfile,"    |-Acknowledge Number    :%u
",ntohl(tcph->dest));
    fprintf(sniffer->logfile,"    |-Header Length    :%d DWORDS  or %d Bytes
",(unsigned int)tcph->doff,((unsigned int)(tcph->doff)) * 4);    
    fprintf(sniffer->logfile,"    |-Urgent Flag        :%d
",(unsigned int)tcph->urg);    
    fprintf(sniffer->logfile,"    |-Acknowledgement Flag        :%d
",(unsigned int)tcph->ack);
    fprintf(sniffer->logfile,"    |-Push Flag        :%d
",(unsigned int)tcph->psh);
    fprintf(sniffer->logfile,"    |-Reset Flag        :%d
",(unsigned int)tcph->rst);
    fprintf(sniffer->logfile,"    |-Synchronise Flag    :%d
",(unsigned int)tcph->syn);
    fprintf(sniffer->logfile,"    |-Finish Flag        :%d
",(unsigned int)tcph->fin);
    fprintf(sniffer->logfile,"    |-Window        :%d
",ntohs(tcph->window));    
    fprintf(sniffer->logfile,"    |-Checksum        :%d
",ntohs(tcph->check));
    fprintf(sniffer->logfile,"    |-Urgent Pointer    :%d
",(tcph->urg_ptr));    
    fprintf(sniffer->logfile,"
");
    fprintf(sniffer->logfile,"            DATA Dump            
");    
    
    fprintf(sniffer->logfile,"IP Header
");
    PrintData(buf, iphdrlen, sniffer);        //将ip头部信息按照16进制的方式输入到日志中
    
    fprintf(sniffer->logfile,"TCP Header
");
    PrintData(buf+iphdrlen, tcph->doff*4, sniffer);
    
    fprintf(sniffer->logfile,"Data Payload
");    //将tcp数据报中的存储的内容按16进制输出到日志中
    PrintData(buf+iphdrlen+tcph->doff*4, (size - tcph->doff*4 - iph->ihl*4),sniffer);
    fprintf(sniffer->logfile,"################################################
");
}


void print_udp_packet(unsigned char *buf, int size, t_sniffer * sniffer)
{
    unsigned short iphdrlen;
    
    struct iphdr *iph;
    struct udphdr *udph;
    
    iph = (struct iphdr *)buf;
    iphdrlen = iph->ihl * 4;
    udph = (struct udphdr*)(buf + iphdrlen);
    fprintf(sniffer->logfile,"

************************UDP Packet********************
");
    
    print_ip_header(buf, size, sniffer);
    
    fprintf(sniffer->logfile,"
UDP Header
");
    fprintf(sniffer->logfile,"    |-Source Port        :%d
",ntohs(udph->source));
    fprintf(sniffer->logfile,"    |-Destination Port    :%d
",ntohs(udph->dest));
    fprintf(sniffer->logfile,"    |-UDP Length        :%d
",ntohs(udph->len));
    fprintf(sniffer->logfile,"    |-UDP Checksum    :%d
",ntohs(udph->check));
    
    fprintf(sniffer->logfile,"
");
    fprintf(sniffer->logfile,"IP Header
");
    PrintData(buf, iphdrlen, sniffer);
    
    fprintf(sniffer->logfile,"UDP Header
");
    PrintData(buf+iphdrlen,sizeof(udph), sniffer);
    
    fprintf(sniffer->logfile,"Data Payload
");
    PrintData(buf+iphdrlen+sizeof(udph), (size - sizeof(udph) - iph->ihl*4),sniffer);
    fprintf(sniffer->logfile,"################################################
");
}

void print_icmp_packet(unsigned char * buf, int size, t_sniffer * sniffer)
{
    unsigned short iphdrlen;
    struct iphdr *iph;
    struct icmphdr *icmph;
    
    iph = (struct iphdr *)buf;
    iphdrlen = iph->ihl * 4;
    icmph = (struct icmphdr *)(buf + iphdrlen);
    fprintf(sniffer->logfile,"

************************ICMP Packet********************
");
    print_ip_header(buf, size, sniffer);
    fprintf(sniffer->logfile,"
");
    fprintf(sniffer->logfile,"ICMP Header
");
    fprintf(sniffer->logfile,"    |-Type        :%d
",(unsigned int)icmph->type);
    
    if((unsigned int)(icmph->type) == 11)
    {
        fprintf(sniffer->logfile,"(TTL Expired)
");
    }
    else if((unsigned int)(icmph->type) == ICMP_ECHOREPLY)
    {
        fprintf(sniffer->logfile,"(ICMP Echo Reply)
");
    }
    fprintf(sniffer->logfile,"    |-Code        :%d
",(unsigned int)icmph->code);
    fprintf(sniffer->logfile,"    |-Checksum    :%d
",ntohs(icmph->checksum));
    fprintf(sniffer->logfile,"
");
    
    fprintf(sniffer->logfile,"IP Header
");
    PrintData(buf, iphdrlen, sniffer);
    
    fprintf(sniffer->logfile,"UDP Header
");
    PrintData(buf+iphdrlen,sizeof(icmph), sniffer);
    
    fprintf(sniffer->logfile,"Data Payload
");
    PrintData(buf+iphdrlen+sizeof(icmph), (size - sizeof(icmph) - iph->ihl*4),sniffer);
    fprintf(sniffer->logfile,"################################################
");
}
void PrintData(unsigned char * buf, int size, t_sniffer *sniffer)
{
#if 1
    int i;
    for(i = 0; i < size; i++)
    {
        if(i % 16 == 0)
        {
            fprintf(sniffer->logfile,"
");
        }

        
        fprintf(sniffer->logfile," %02X",(unsigned int)buf[i]);
        
        if(i == size - 1)
            fprintf(sniffer->logfile,"
");
    }
#else
 int i;

  for(i = 0 ; i < size ; i++)
    {
        if(i % 16 == 0)
        fprintf(sniffer->logfile, "
");
        fprintf(sniffer->logfile, " %02X",(unsigned int)buf[i]);
      
        if( i == size - 1)
            fprintf(sniffer->logfile, "
");
    }
#endif
}

主函数

/*
main.c
*/
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netinet/ip.h>
#include<sys/socket.h>
#include<sys/select.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/time.h>
#include<errno.h>

#include"sniffer.h"
#include"tools.h"
#define ETH_P_IP 0x0800

 int exec_cmd(char *buffer, int len)
{
    if(strncmp(buffer,"quit",4) == 0)
    {
        return 1;
    }
    return 0;
}

int command_interpreter(int sd)
{
    int len;
    char buf[512];

    len = read(0,buf,512);
    if(len > 0)
    {
        if(exec_cmd(buf,len) == 1)
        {
            return 1;
        }
    }        
    return 0;
}

void display_time_and_data()
{
    INITCOLOR(RED_COLOR);
    printf("[%s]",__DATE__);
    INITCOLOR(GREEN_COLOR);
    printf("[%s]  ", __TIME__);
    INITCOLOR(ZERO_COLOR);
}

void getting_started()
{
    CLEARSCREEN();
    display_time_and_data();
    printf("Getting started of NetWork sniffer

");
}    
int main()
{
    int sd;
    int res;
    int saddr_size;
    int data_size;
    struct sockaddr saddr;
    unsigned char *buffer;        //保存数据包中的数据
    t_sniffer sniffer;            //保存数据包的类型和日志文件等信息
    fd_set fd_read;

    buffer = malloc(sizeof(unsigned char *) * 65536);

    //创建日志文件
    sniffer.logfile = fopen("log.txt","w");
    fprintf(sniffer.logfile,"***LOGFILE(%s - %s)***
",__DATE__,__TIME__);
    if(sniffer.logfile == NULL)
    {
        perror("fopen(): ");
        return (EXIT_FAILURE);
    }

    sniffer.prot = malloc(sizeof(t_protocol *));

    //创建原始套接字,ETH_P_ALL表示侦听负载为IP数据报的以太网帧
    //返回一个int型数字作为文件描述符,用来表示创建成功的socket文件描述符
    sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
    if(sd < 0)
    {
        perror("socket() :");
        return (EXIT_FAILURE);
    }
    getting_started();
    signal(SIGINT, &signal_white_now);
    signal(SIGQUIT, &signal_white_now);

    while(1)
    {
        FD_ZERO(&fd_read);
        FD_SET(0,&fd_read);
        FD_SET(sd,&fd_read);

        //多路复用检测可读的套接字和标准输入
        res = select(sd+1,&fd_read,NULL,NULL,NULL);
        if(res < 0)
        {
            close(sd);
            if(errno != EINTR)
            {
                perror("select() ");
            }
            return (EXIT_FAILURE);
        }
        else
        {
            //如果是标准输入可读,进入命令行处理程序
            if(FD_ISSET(0,&fd_read))
            {
                if(command_interpreter(sd) == 1)    
                {
                    break;
                }
            }
            //如果是套接字可读,则读取以太网数据帧内容,并调用ProcessPacket函数解析数据包类型
            else if(FD_ISSET(sd,&fd_read))
            {
                //读取以太网数据帧的内容
                saddr_size = sizeof(saddr);
                data_size = recvfrom(sd,buffer,65536,0,&saddr,(socklen_t*)&saddr_size);
                if(data_size <= 0)
                {
                    close(sd);
                    perror("rcvfrom(): ");
                    return (EXIT_FAILURE);
                }

                ProcessPacket(buffer, data_size, &sniffer);
            }
        }
    }        
    close(sd);
    return (EXIT_SUCCESS);
}

void ProcessPacket(unsigned char * buffer,int size, t_sniffer *sniffer)
{
    //根据以太网帧结构,前6B是目的MAC地址,然后是6B的源MAC地址,接下来是2B的帧长度,然后是ip层数据作为负载
    buffer = buffer + 6 + 6 + 2;
    struct iphdr *iph = (struct iphdr*)buffer;

    ++sniffer->prot->total;

    //根据TCP/IP协议规定的IP数据包头部的protocol字段的值,判断上层数据包类型
    switch(iph->protocol)
    {
        //1 表示icmp协议
        case 1:
            ++sniffer->prot->icmp;
            print_icmp_packet(buffer,size,sniffer);
            break;
        //2表示igmp协议
        case 2:
            ++sniffer->prot->igmp;
            break;
        //6表示tcp协议
        case 6:
            ++sniffer->prot->tcp;
            print_tcp_packet(buffer,size,sniffer);
            break;
        //17表示udp协议
        case 17:
            ++sniffer->prot->udp;
            print_udp_packet(buffer,size,sniffer);
            break;
        default:
            ++sniffer->prot->others;
            break;
    }

    display_time_and_data();
    printf("TCP    :%d    UDP    :%d    ICMP  :%d    IGMP  :%d    others:%d    total:%d
",
            sniffer->prot->tcp,sniffer->prot->udp,
            sniffer->prot->icmp,sniffer->prot->igmp,
            sniffer->prot->others,sniffer->prot->total);

}

makefile

NAME    =    network_sniffer
SRCS    =    main.c    
            tools.c    
            show_data.c

OBJS    =    $(SRCS:.c=.o)
CC    =    gcc -o
CFLAGS    =    -W    -Wall
RM    =    rm -rf

$(NAME)    :    $(OBJS)
              $(CC)    $(NAME)    -I./    $(CFLAGS)    $(OBJS)

all    :    $(NAME)

clean    :
        $(RM)    $(OBJS)

fclean    :    clean
        $(RM)    $(NAME)

re    :    fclean all
原文地址:https://www.cnblogs.com/wanghao-boke/p/11670528.html