使用C编程将端口6343中的sflow数据写入Scientific Linux中的csv文件

时间:2015-07-07 10:03:59

标签: c linux sockets

我正在尝试将端口sflow中的6343数据写入csv文件。代码编译但数据包不存储在文件中。以下代码由我使用。我引用this code进行了修改,仅捕获UDP个数据包以及IP标头和UDP标头信息,并为特定端口创建socket

 #include<stdio.h> //For standard things
 #include<stdlib.h>    //malloc
 #include<string.h>    //memset
 #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/socket.h>
 #include <sys/types.h>
 #define PORT 6343

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

int sock;
FILE *logfile;
int udp=0,total=0,i,j;
struct sockaddr_in source,dest;

int main()
{
    int saddr_size , data_size;
    int yes=1;
    struct sockaddr saddr;
    struct in_addr in;
    struct sockaddr_in myaddr;

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

    logfile=fopen("log.csv","w");
    if(logfile==NULL) printf("Unable to create file.");
    printf("Starting...\n");

     myaddr.sin_family=AF_INET;
     myaddr.sin_addr.s_addr=INADDR_ANY;
     myaddr.sin_port=htons(6343);     

     sock=socket(AF_INET,SOCK_DGRAM,0);
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) 
     {
        perror("setsockopt");
        exit(1);
     }
     if(sock<0)
     {
         printf("failed to create socket");
         return 1;
      }

     if(bind(sock,(struct sockaddr *)&myaddr,sizeof(myaddr))<0)
     {
         printf("binding failed");
         return 1;
     }

     listen(sock,5);
     while(1)
     {
        saddr_size = sizeof saddr;
        //Receive a packet
        data_size = recvfrom(sock , buffer , 65536 , 0 , &saddr , &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);
    printf("Finished");
    return 0;
}

void ProcessPacket(unsigned char* buffer, int size)
{
    //Get the IP Header part of this packet
    struct iphdr *iph = (struct iphdr*)buffer;
    ++total;
    switch (iph->protocol) //Check the Protocol and do accordingly...
    {

        case 17: //UDP Protocol
            ++udp;
            print_udp_packet(buffer , size);
            break;
    }

    printf("UDP : %d   Total : %d\r",udp,total);
}

void print_ip_header(unsigned char* Buffer, int Size)
{
    unsigned short iphdrlen;

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

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

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

    unsigned short iphdrlen;

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

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

    fprintf(logfile,"\n\n***********************UDP Packet*************************\n");

    print_ip_header(Buffer,Size);           

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

    fprintf(logfile,"\n");
    fprintf(logfile,"IP Header\n");
    PrintData(Buffer , iphdrlen);

    fprintf(logfile,"UDP Header\n");
    PrintData(Buffer+iphdrlen , sizeof udph);

    fprintf(logfile,"Data Payload\n");  
    PrintData(Buffer + iphdrlen + sizeof udph ,( Size - sizeof udph - iph->ihl * 4 ));

    fprintf(logfile,"\n###########################################################");
}

void PrintData (unsigned char* data , int Size)
{

    for(i=0 ; i < Size ; i++)
    {
        if( i!=0 && i%16==0)   //if one line of hex printing is complete...
        {
            fprintf(logfile,"         ");
            for(j=i-16 ; j<i ; j++)
            {
                if(data[j]>=32 && data[j]<=128)
                    fprintf(logfile,"%c",(unsigned char)data[j]); //if its a number or alphabet

                else fprintf(logfile,"."); //otherwise print a dot
            }
            fprintf(logfile,"\n");
        } 

        if(i%16==0) fprintf(logfile,"   ");
            fprintf(logfile," %02X",(unsigned int)data[i]);

        if( i==Size-1)  //print the last spaces
        {
            for(j=0;j<15-i%16;j++) fprintf(logfile,"   "); //extra spaces

            fprintf(logfile,"         ");

            for(j=i-i%16 ; j<=i ; j++)
            {
                if(data[j]>=32 && data[j]<=128) fprintf(logfile,"%c",(unsigned char)data[j]);
                else fprintf(logfile,".");
            }
            fprintf(logfile,"\n");
        }
    }
}
你可以告诉我代码中有什么问题吗?

1 个答案:

答案 0 :(得分:0)

原始数据包嗅探代码会创建一个原始套接字

sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);

原始套接字获取包含IP标头的数据。但是你的程序会创建UDP套接字

sock=socket(AF_INET,SOCK_DGRAM,0);

UDP套接字和TCP套接字提供没有IP,UDP和TCP标头的数据。这意味着缓冲区仅包含数据。

编辑 - 解释详情:

是的,这是网络协议栈设计的结果。每个层都有特定的任务。

简化处理如下:

  • 接收数据包并在IP层中处理。 IP层删除IP标头并将数据包移至UDP层。
  • UDP层删除UDP标头并将数据复制到缓冲区。然后内核唤醒recvfrom调用。

当您使用UDP套接字时,您无法从IP标头获取信息,因为它已被删除。当您使用原始套接字时,您无法按端口过滤数据包,因为在IP和UDP层中处理之前,端口是未知的。

你想念的功能在初看时看起来很合理,但你必须考虑在

时做什么
  • 您的端口收到非IPv4数据包。
  • 收到属于您所需端口的数据包的IPv4片段。
  • UDP数据包封装在IPsec或任何其他协议中。
  • ...

所以你必须默认只有两个选择。要么使用UDP套接字提供的舒适性,要么您不会看到较低协议的细节或使用原始套接字,然后在您的应用程序中执行更多工作并实现端口过滤。