C語言實現Linux網路嗅探器

來源:互聯網
上載者:User

標籤:get   gnu   嗅探   lag   rebuild   stdio.h   讀取   port   ted   

C語言實現Linux網路嗅探器0x01 實驗簡介

網路嗅探器是攔截通過網路介面流入和流出的資料的程式。所以,如果你正在瀏覽的互連網,嗅探器以資料包的形式抓到它並且顯示。在本實驗中,我們用 C 語言實現了一個網路嗅探器。

0x02程式架構和功能描述

本程式使用c語言編程,實現linux環境下網路嗅探的功能,並實現對接收到的UDP資料報進行解析。

0x03程式碼

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_sniffer{    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_date();void getting_started();void signal_white_now(int);#endif

tools.h

#ifndef __COLOR_H__#define __COLOR_H__#include <stdio.h>#define CLEARSCREEN() printf("\033[H\033[2J")#define INITCOLOR(color) printf("\033[%sm", color)#define RED_COLOR "31"#define GREEN_COLOR "32"#define YELLOW_COLOR "33"#define BLUE_COLOR "34"#define ZERO_COLOR "0"#endif      

tools.c

#include    <signal.h>#include    <stdio.h>/* 訊號處理函數 */void signal_white_now(int signum){    printf("Bye Bye !\n");}

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;     (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,"\n");    fprintf(sniffer->logfile,"IP Header\n");    fprintf(sniffer->logfile,"   |-IP Version        : %d\n",(unsigned int)iph->version);    fprintf(sniffer->logfile,"   |-IP Header Length  : %d DWORDS or %d Bytes\n",(unsigned int)iph->ihl,((unsigned int)(iph->ihl))*4);    fprintf(sniffer->logfile,"   |-Type Of Service   : %d\n",(unsigned int)iph->tos);    fprintf(sniffer->logfile,"   |-IP Total Length   : %d  Bytes(size of Packet)\n",ntohs(iph->tot_len));    fprintf(sniffer->logfile,"   |-Identification    : %d\n",ntohs(iph->id));    fprintf(sniffer->logfile,"   |-TTL      : %d\n",(unsigned int)iph->ttl);    fprintf(sniffer->logfile,"   |-Protocol : %d\n",(unsigned int)iph->protocol);    fprintf(sniffer->logfile,"   |-Checksum : %d\n",ntohs(iph->check));    fprintf(sniffer->logfile,"   |-Source IP        : %s\n",inet_ntoa(source.sin_addr));    fprintf(sniffer->logfile,"   |-Destination IP   : %s\n",inet_ntoa(dest.sin_addr));}/* 寫 TCP 資料包到記錄檔 */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);    print_ip_header(buf, size, sniffer);        /* 把 tcp 頭資訊寫入記錄檔中 */    fprintf(sniffer->logfile,"\n");    fprintf(sniffer->logfile,"TCP Header\n");    fprintf(sniffer->logfile,"   |-Source Port      : %u\n",ntohs(tcph->source));    fprintf(sniffer->logfile,"   |-Destination Port : %u\n",ntohs(tcph->dest));    fprintf(sniffer->logfile,"   |-Sequence Number    : %u\n",ntohl(tcph->seq));    fprintf(sniffer->logfile,"   |-Acknowledge Number : %u\n",ntohl(tcph->ack_seq));    fprintf(sniffer->logfile,"   |-Header Length      : %d DWORDS or %d BYTES\n" ,(unsigned int)tcph->doff,(unsigned int)tcph->doff*4);    fprintf(sniffer->logfile,"   |-Urgent Flag          : %d\n",(unsigned int)tcph->urg);    fprintf(sniffer->logfile,"   |-Acknowledgement Flag : %d\n",(unsigned int)tcph->ack);    fprintf(sniffer->logfile,"   |-Push Flag            : %d\n",(unsigned int)tcph->psh);    fprintf(sniffer->logfile,"   |-Reset Flag           : %d\n",(unsigned int)tcph->rst);    fprintf(sniffer->logfile,"   |-Synchronise Flag     : %d\n",(unsigned int)tcph->syn);    fprintf(sniffer->logfile,"   |-Finish Flag          : %d\n",(unsigned int)tcph->fin);    fprintf(sniffer->logfile,"   |-Window         : %d\n",ntohs(tcph->window));    fprintf(sniffer->logfile,"   |-Checksum       : %d\n",ntohs(tcph->check));    fprintf(sniffer->logfile,"   |-Urgent Pointer : %d\n",tcph->urg_ptr);    fprintf(sniffer->logfile,"\n");    fprintf(sniffer->logfile,"                        DATA Dump                         ");    fprintf(sniffer->logfile,"\n");      fprintf(sniffer->logfile,"IP Header\n");    PrintData(buf, iphdrlen, sniffer);      fprintf(sniffer->logfile,"TCP Header\n");    PrintData(buf+iphdrlen, tcph->doff*4, sniffer);      fprintf(sniffer->logfile,"Data Payload\n");    /* 把使用者資料寫入記錄檔 */    PrintData(buf + iphdrlen + tcph->doff*4,        (size - tcph->doff*4-iph->ihl*4),        sniffer );      fprintf(sniffer->logfile,"\n###########################################################");}/* 寫 UDP 資料包到記錄檔 */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,"\n\n***********************UDP Packet*************************\n");      print_ip_header(buf, size, sniffer);        /* 把 udp 頭資訊寫入記錄檔中 */    fprintf(sniffer->logfile,"\nUDP Header\n");    fprintf(sniffer->logfile,"   |-Source Port      : %d\n" , ntohs(udph->source));    fprintf(sniffer->logfile,"   |-Destination Port : %d\n" , ntohs(udph->dest));    fprintf(sniffer->logfile,"   |-UDP Length       : %d\n" , ntohs(udph->len));    fprintf(sniffer->logfile,"   |-UDP Checksum     : %d\n" , ntohs(udph->check));      fprintf(sniffer->logfile,"\n");    fprintf(sniffer->logfile,"IP Header\n");    PrintData(buf , iphdrlen, sniffer);      fprintf(sniffer->logfile,"UDP Header\n");    PrintData(buf+iphdrlen, sizeof(udph), sniffer);      fprintf(sniffer->logfile,"Data Payload\n");    /* 把使用者資料寫入記錄檔 */    PrintData(buf + iphdrlen + sizeof udph,        (size - sizeof udph - iph->ihl * 4),        sniffer);      fprintf(sniffer->logfile,"\n###########################################################");}/* 寫 ICMP 資料包到記錄檔 */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);    /* 把 icmp 頭資訊寫入記錄檔中 */    fprintf(sniffer->logfile,"\n\n***********************ICMP Packet*************************\n");      print_ip_header(buf , size, sniffer);    fprintf(sniffer->logfile,"\n");    fprintf(sniffer->logfile,"ICMP Header\n");    fprintf(sniffer->logfile,"   |-Type : %d",(unsigned int)(icmph->type));      if((unsigned int)(icmph->type) == 11)     fprintf(sniffer->logfile,"  (TTL Expired)\n");    else if((unsigned int)(icmph->type) == ICMP_ECHOREPLY)     fprintf(sniffer->logfile,"  (ICMP Echo Reply)\n");    fprintf(sniffer->logfile,"   |-Code : %d\n",(unsigned int)(icmph->code));    fprintf(sniffer->logfile,"   |-Checksum : %d\n",ntohs(icmph->checksum));    fprintf(sniffer->logfile,"\n");    fprintf(sniffer->logfile,"IP Header\n");    PrintData(buf, iphdrlen, sniffer);    fprintf(sniffer->logfile,"UDP Header\n");    PrintData(buf + iphdrlen , sizeof(icmph), sniffer);      fprintf(sniffer->logfile,"Data Payload\n");      /* 最後將使用者資料寫入記錄檔中 */    PrintData(buf + iphdrlen + sizeof(icmph),        (size - sizeof(icmph) - iph->ihl * 4),        sniffer);      fprintf(sniffer->logfile,"\n###########################################################");}/* 寫使用者資料到記錄檔 */void PrintData(unsigned char *buf, int size, t_sniffer *sniffer){  int i;  for(i = 0 ; i < size ; i++)    {        if(i % 16 == 0)        fprintf(sniffer->logfile, "\n");        fprintf(sniffer->logfile, " %02X",(unsigned int)buf[i]);              if( i == size - 1)            fprintf(sniffer->logfile, "\n");    }}

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 0x0800int 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_date(){    INITCOLOR(RED_COLOR);    printf("[%s]", __DATE__); /* 列印日期 */    INITCOLOR(GREEN_COLOR);    printf("[%s]  ", __TIME__); /* 列印時間 */    INITCOLOR(ZERO_COLOR);}void getting_started(){    CLEARSCREEN(); /* 清空螢幕 */    display_time_and_date();    printf("Getting started of Network sniffer\n\n");  }/* 主函數入口 */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)***\n", __DATE__, __TIME__);    if (sniffer.logfile == NULL)    {        perror("fopen(): ");        return (EXIT_FAILURE);    }    sniffer.prot = malloc(sizeof(t_protocol *));      /* 建立原始通訊端,ETH_P_ALL 表示偵聽負載為 IP 資料報的乙太網路幀 */    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);    /* 迴圈偵聽乙太網路幀,並調用 ProcessPacket 函數解析 */    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            {                /* 如果是標準輸入可讀,進入命令列處理常式 command_interpreter,暫時只支援 ‘quit‘ 命令 */                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("recvfrom(): ");                                return (EXIT_FAILURE);                            }                        ProcessPacket(buffer, data_size, &sniffer); /* 調用 ProcessPacket 函數解析出資料包的類型 */                    }            }    }        close(sd);    return (EXIT_SUCCESS);}void ProcessPacket(unsigned char* buffer, int size, t_sniffer *sniffer){    buffer = buffer + 6 + 6 + 2; /* 根據太網幀結構,前 6B 是目的 MAC 位址,接下來的是源 MAC 位址,接下來 2B 是幀長度,其餘的是負載(上層的 IP 資料報) */    struct iphdr *iph = (struct iphdr*)buffer;    ++sniffer->prot->total; /* 資料包總數加 1 */    /* 根據 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_date(); /* 顯示時間 */    /* 列印 sniffer 中的資訊 */    printf("TCP : %d   UDP : %d   ICMP : %d   IGMP : %d   Others : %d Total : %d\n",     sniffer->prot->tcp, sniffer->prot->udp,     sniffer->prot->icmp, sniffer->prot->igmp,     sniffer->prot->others, sniffer->prot->total);}
0x04資料報分析

以一個UDP資料包為例

***LOGFILE(Dec 14 2017 - 21:41:38)**************************UDP Packet*************************IP Header   |-IP Version        : 4   |-IP Header Length  : 5 DWORDS or 20 Bytes   |-Type Of Service   : 0   |-IP Total Length   : 213  Bytes(size of Packet)   |-Identification    : 6639   |-TTL      : 64   |-Protocol : 17   |-Checksum : 31927   |-Source IP        : 172.16.69.82   |-Destination IP   : 172.16.69.255UDP Header   |-Source Port      : 138   |-Destination Port : 138   |-UDP Length       : 193   |-UDP Checksum     : 26258IP Header保護隱私,這部分我刪除了 AC 10 45 FFUDP Header保護隱私,這部分我刪除了Data Payload保護隱私,這部分我刪除了###########################################################
0x05附

我認為本實驗的亮點在於使用指令碼控制,有必要好好學習下指令碼編程
launcher.sh

#!/bin/shsigint(){    printf ‘\nQUIT !\n‘    exit 1}main(){    clear    printf "\t\t\t\t\tWelcome to Sniffer Project r\n\n"    while [ 1 ]; do    printf "Select option: \n\n"    printf "1 : Build Project\n"    printf "2 : Launch Project\n"    printf "3 : Remove Object files\n"    printf "4 : Rebuild\n"    printf "0 : Exit\n"    printf "\nYou choose: "    read option        if [ $option = 0 ]    then        exit    fi    if [ $option -ge 1 ] && [ $option -le 4 ]    then        if [ $option = 1 ]        then        make "network_sniffer"        fi        if [ $option = 2 ]        then        "./network_sniffer"        fi        if [ $option = 3 ]        then        make clean        fi        if [ $option = 4 ]        then        make re        fi          else        printf "This option does not exist\n"    fi    done}trap ‘sigint‘ 2main

C語言實現Linux網路嗅探器

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.