从UDP客户端服务器捕获数据包

时间:2014-09-17 14:37:29

标签: c linux sockets

我试图从UDP客户端 - 服务器通信中捕获数据包。我不允许使用libpcap或tcpdump。 我发现了一篇关于它的好文章here.

但是,我无法理解该计划。因为,给出的评论非常少。

有人可以指点我这样的信息来源吗? 或者更准确地说,我正在寻找一个关于在Linux中使用C进行数据包分析的来源。

提前致谢。

1 个答案:

答案 0 :(得分:1)

这是类似于你想要的东西,你可以删除不必要的标题。我编辑了代码的来源(来自您的链接)以获得所需的功能。

基本上这个人使用RAW套接字。 RAW套接字可以接收包含所有标头的任何数据包。在普通的Socket中,您可以定义您期望的协议,从哪个端口和哪个IP Source。 Linux IP Stack处理标头,您只获得应用程序层数据。此外,您还可以获取源和目标IP地址(来自您的sockaddr_in类型结构)。

现在,在这种情况下,您可以获得所有标头,这意味着您可以接收界面上的所有数据包,并根据需要插入标题。如果需要,这些类型的套接字对于数据包嗅探和创建一些自定义协议非常有用。

在下面提供的代码中,我只根据您的要求嗅探UDP数据包

#include<netinet/in.h>
#include<errno.h>
#include<netdb.h>
#include<stdio.h> //For standard things
#include<stdlib.h>    //malloc
#include<string.h>    //strlen

#include<netinet/ip_icmp.h>   //Provides declarations for icmp header
#include<netinet/udp.h>   //Provides declarations for udp header
#include<netinet/tcp.h>   //Provides declarations for tcp header
#include<netinet/ip.h>    //Provides declarations for ip header
#include<netinet/if_ether.h>  //For ETH_P_ALL
#include<net/ethernet.h>  //For ether_header
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
#include <net/if.h>           // struct ifreq
//#include <fcntl.h>
#include <linux/if_packet.h>



void ProcessPacket(unsigned char* , int);
void print_ip_header(unsigned char* , int);
void print_udp_packet(unsigned char * , int );

struct sockaddr_in source_epc,dest_epc;

//uint32_t ipSrc;
//uint16_t portSrc;

int main()
{

    //struct sockaddr_ll sll;
    //struct ifreq ifr;

    int saddr_size , data_size;
    struct sockaddr saddr;
    //int udp = 0, others = 0;

    unsigned char *buffer = (unsigned char *) malloc(500); //Its Big!

    int sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;
    if(sock_raw < 0)
    {
        //Print the error with proper message
        perror("Socket Error");
        return 1;
    }

    /////////////////setsockopt(sock_raw , SOL_SOCKET , SO_BINDTODEVICE , "eth1" , strlen("eth1")+ 1 );


    //memset(&sll, 0, sizeof(sll));
    //memset(&ifr, 0, sizeof(ifr));
    //strncpy((char *)ifr.ifr_name, "eth1", IFNAMSIZ);
    /*if((ioctl(sock_raw, SIOCGIFHWADDR, &ifr)) == -1)
    {     
        printf("Error getting Interface hw address!\n");
        exit(-1);
    }*/

    while(1)
    {
        saddr_size = sizeof saddr;
        //Receive a packet
        //setsockopt(sock_raw , SOL_SOCKET , SO_BINDTODEVICE , "eth0" , strlen("eth0")+ 1 );

        data_size = recvfrom(sock_raw , buffer , 65536 , 0 , &saddr , (socklen_t*)&saddr_size);

        if(data_size <0 )
        {
            printf("Recvfrom error , failed to get packets\n");
            return 1;
        }
        //Now process the packet
        ProcessPacket(buffer , data_size);
    }
    close(sock_raw);
    printf("Finished");
    return 0;

}


void ProcessPacket(unsigned char* buffer, int size)
{
    //Get the IP Header part of this packet , excluding the ethernet header
    struct iphdr *iph = (struct iphdr*)(buffer + sizeof(struct ethhdr));
    //++total;
    if ( iph->protocol == 17)
    {
        printf("UDP Packet received\n");
        print_ip_header(buffer, size);
        print_udp_packet(buffer , size);
    }

    else
    {
    printf("Packet received in not UDP\n");
    return 1;
    }
}

void print_ip_header(unsigned char* Buffer, int Size)
{
   // print_ethernet_header(Buffer , Size);

    unsigned short iphdrlen;

    struct iphdr *iph = (struct iphdr *)(Buffer  + sizeof(struct ethhdr) );
    iphdrlen =iph->ihl*4;

    memset(&source_epc, 0, sizeof(source_epc));
    source_epc.sin_addr.s_addr = iph->saddr;

    memset(&dest_epc, 0, sizeof(dest_epc));
    dest_epc.sin_addr.s_addr = iph->daddr;


    printf(" \n\n***********************IP HEADER*************************\n " );
    printf("   |-IP Version        : %d\n",(unsigned int)iph->version);
    printf("   |-IP Header Length  : %d DWORDS or %d Bytes\n",(unsigned int)iph->ihl,((unsigned int)(iph->ihl))*4);
    printf("   |-Type Of Service   : %d\n",(unsigned int)iph->tos);
    printf("   |-IP Total Length   : %d  Bytes(Size of Packet)\n",ntohs(iph->tot_len));
    printf("   |-Identification    : %d\n",ntohs(iph->id));
    //printf("   |-Reserved ZERO Field   : %d\n",(unsigned int)iphdr->ip_reserved_zero);
    //printf("   |-Dont Fragment Field   : %d\n",(unsigned int)iphdr->ip_dont_fragment);
    //printf("   |-More Fragment Field   : %d\n",(unsigned int)iphdr->ip_more_fragment);
    printf("   |-TTL      : %d\n",(unsigned int)iph->ttl);
    printf("   |-Protocol : %d\n",(unsigned int)iph->protocol);
    printf("   |-Checksum : %d\n",ntohs(iph->check));
    printf("   |-Source IP        : %s\n",inet_ntoa(source_epc.sin_addr));
    printf("   |-Destination IP   : %s\n",inet_ntoa(dest_epc.sin_addr));




    }


void print_udp_packet(unsigned char *Buffer , int Size)
{

    unsigned short iphdrlen;

    struct iphdr *iph = (struct iphdr *)(Buffer +  sizeof(struct ethhdr));
    iphdrlen = iph->ihl*4;

    struct udphdr *udph = (struct udphdr*)(Buffer + iphdrlen  + sizeof(struct ethhdr));

    int header_size =  sizeof(struct ethhdr) + iphdrlen + sizeof udph;

    printf("\n\n***********************UDP Packet*************************\n");

    //print_ip_header(Buffer,Size);           

    printf("\nUDP Header\n");
    printf("   |-Source Port      : %d\n" , ntohs(udph->source));
    printf("   |-Destination Port : %d\n" , ntohs(udph->dest));
    printf("   |-UDP Length       : %d\n" , ntohs(udph->len));
    printf("   |-UDP Checksum     : %d\n" , ntohs(udph->check));

    printf("\n");
    //printf("IP Header\n");
    //PrintData(Buffer , iphdrlen);

    //printf("UDP Header\n");
    //PrintData(Buffer+iphdrlen , sizeof udph);

    //printf("Data Payload\n");    

    //Move the pointer ahead and reduce the size of string
    //PrintData(Buffer + header_size , Size - header_size);

    printf("\n###########################################################");
}