2015-03-21 1 views
0

Я сделал сниффер пакетов, используя libpcap на C++. Я использую pcap_loop и вызываю функцию loopback, которая на данный момент я не думал. Вот мой код.libpcap Packet sniffing Анализ трафика

int PacketSniff(int *count) 
{ 
    int ifnum; 
    int NumOfDevs=0; 
    char errbuf[PCAP_ERRBUF_SIZE]; 
    bpf_u_int32 ip; 
    bpf_u_int32 netmask; 
    struct in_addr ip_addr , netmask_addr; 
    pcap_if_t *devs , *d; 
    pcap_t *handler; 
    char packet_filter[] = "ip"; 
    struct bpf_program fcode; 


    /* Find all interface devices */ 
    pcap_findalldevs(&devs, errbuf); 

    for(d=devs; d; d=d->next) 
    { 
     printf("%d. %s", ++NumOfDevs, d->name); 
     if (d->description) 
     { 
      printf(" (%s)\n", d->description); 
     } 
     else 
     { 
      printf(" (No description available)\n"); 
     } 
    } 
    if(NumOfDevs==0) 
    { 
     printf("\nNo interfaces found!\n"); 
     return (-1); 
    } 


    /* Prompt User to select interface */ 
    printf("Enter the interface number (1-%d):\n",NumOfDevs); 
    scanf("%d",&ifnum); 

    if(ifnum < 1 || ifnum > NumOfDevs) 
    { 
     printf("\nInterface number out of range.\n"); 
     /* Free the device list */ 
     pcap_freealldevs(devs); 
     return (-1); 
    } 


    /* Jump to the selected adapter/interface */ 
    for(d=devs; ifnum>1 ;d=d->next, ifnum--); 

    /* Open the selected adapter/interface */ 
    handler = pcap_open_live(d->name, 65535, 0, 2000, errbuf); 

    if ((handler = pcap_open_live(d->name, 65535, 0, 2000, errbuf)) == NULL) 
    { 
     fprintf(stderr, "Couldn't open device %s: %s\n", d->name, errbuf); 
     return(-1); 
    } 




    if (pcap_datalink(handler) != DLT_EN10MB) 
    { 
     fprintf(stderr,"\nThis program works only on Ethernet networks.\n"); 
     pcap_freealldevs(devs); 
     return -1; 

    } 

    /* This means that we set the datalink layer header size at 14 */ 
    int linkhdrlen = 14; 


    if (pcap_lookupnet(d->name, &ip, &netmask, errbuf) <0) 
    { 
     fprintf(stderr, "Can't get netmask for device %s\n", d->name); 
     netmask = 0; 
     ip = 0; 
    } 


    /* Compile the filter */ 
    if (pcap_compile(handler, &fcode, packet_filter, 1, netmask) <0) 
    { 
     fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax. Error: %s\n", errbuf); 
     pcap_freealldevs(devs); 
     return -1; 
    } 

    /* Set the filter */ 
    if (pcap_setfilter(handler, &fcode)<0) 
    { 
     fprintf(stderr,"\nError setting the filter. Error: %s\n", errbuf); 
     pcap_freealldevs(devs); 
     return -1; 
    } 


    printf("\nListening for packets on interface <%s>...\n", d->name); 

    /* At this point, we don't need any more the device list. Free it */ 
    pcap_freealldevs(devs); 

    pcap_loop(handler, 0, my_callback, NULL);} 

И my_callback как это:

void my_callback(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_ptr){ 

    struct tm ltime; 
    char timestr[16]; 
    struct ip_header *iphdr; 
    struct tcp_header *tcphdr; 
    time_t local_tv_sec; 




    /* Convert the timestamp to readable format */ 

    local_tv_sec = header->ts.tv_sec; 
    localtime_r(&local_tv_sec , &ltime); 
    strftime(timestr, sizeof timestr, "%H:%M:%S", &ltime); 

    /* Print timestamp and length of the packet */ 
    printf("Time >> %s.%.6d \nPacket Length:%d \n\n", timestr, header->ts.tv_usec, header->len); 

    /* Retireve the position of the ip header http://www.tcpdump.org/pcap.html */ 
    iphdr = (ip_header *) (pkt_ptr +14);  




    // Advance to the transport layer header then parse and display 
    // the fields based on the type of hearder: tcp, udp or icmp. 

    pkt_ptr += 4*iphdr->ver_ihl ; 
    tcphdr = (tcp_header *)(pkt_ptr + 14); 
    /* print ip addresses and tcp ports */ 
    printf("%d.%d.%d.%d : %d ---> %d.%d.%d.%d : %d\n\n", 
      iphdr->saddr.byte1, 
      iphdr->saddr.byte2, 
      iphdr->saddr.byte3, 
      iphdr->saddr.byte4, 
      tcphdr->src_port, 
      iphdr->daddr.byte1, 
      iphdr->daddr.byte2, 
      iphdr->daddr.byte3, 
      iphdr->daddr.byte4, 
      tcphdr->dst_port);} 

Теперь я могу нюхать пакеты и печатать различные вещи. Но моя цель - извлечь статистику из пакетов (например, numOfpackets, numOfTCPpackets, numOfIncomingPAcket, numOfOutgoingPackets, Variable Size Variance, Time Interval Variance), пока их обнюхивают. Но я хочу, чтобы это было сделано в 1000 мс Time-Windows.

Например: Каждые 1000 мс я хочу выходной файл ..

numOfTCPPackets = ....

numof = ....

.

.

.

Мои вопросы: Как я могу использовать эти временные окна? Как извлечь необходимую статистику, не мешая слишком много с скоростью обнюхивания.?

Большое вам спасибо!

+0

Ваш вопрос немного широк/неспецифичен. Фактически вы можете отслеживать _'Time-Window'_, используя функцию обратного вызова, которая накапливает статистические значения и проверяет прошедшее время, когда вывести их на самом деле. Вид пассивного класса таймера может быть полезным (предназначен для вычисления прошедшего времени с определенной операции 'start()' или 'reset()'). –

+0

Кстати, код в вашем вопросе - это код C и не содержит реального C++. Я бы подумал об изменении тега C++ на тег C. – juhist

ответ

0

Используйте pcap_next() вместо pcap_loop(), чтобы получить пакет и установить таймаут с помощью pcap_set_timeout() до небольшого значения, такого как 10 миллисекунд, чтобы предотвратить блокировку pcap_next() навсегда, чтобы ваш код записывал статистику в файл получает возможность запускать. Вам нужно позвонить pcap_next() в цикле и имеют код как следующий после pcap_next() вызов:

if (cur_time64() - last_time64 >= stat_time64) 
{ 
    last_time64 += stat_time64; 
    print_statistics_to_file(); 
} 

... где cur_time64() возвращает текущее время в виде 64-разрядного целого числа в микросекундах, поскольку эпоху (вы можете использовать gettimeofday() для реализации cur_time64(), если вы используете Unix-подобную операционную систему). stat_time64 будет в 1 секунду, то есть 1000 * 1000, в вашем примере.

Затем перейдите к обработке пакета. Проверьте возвращаемое значение pcap_next(), чтобы узнать, вернул ли он пакет: если нет, продолжите цикл; если да, обработайте пакет.

Для выполнения проверок, не слишком мешая скорости обнюхивания, единственный вариант - максимально эффективно написать код. Обрабатывайте только те поля заголовков, которые вам абсолютно необходимо обрабатывать, т. Е. Вы можете избежать проверки контрольных сумм заголовков IP и TCP.