K
K
kuzko2020-02-20 12:59:04
linux
kuzko, 2020-02-20 12:59:04

How to read the PCAP header of a c/c++ packet?

I am trying to understand how to read IP Source and Destination from header and data from pcap file

#include <string>
#include <iostream>
#include <pcap.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <sys/types.h>
using namespace std;

#define ETHER_ADDR_LEN 6
#define SIZE_ETHERNET 14


 struct sniff_ethernet {
    u_char ether_dhost[ETHER_ADDR_LEN]; /* Адрес назначения */
    u_char ether_shost[ETHER_ADDR_LEN]; /* Адрес источника */
    u_short ether_type;
 };

 /* IP header */
 struct sniff_ip {
    u_char ip_vhl;  /* версия << 4 | длина заголовка >> 2 */
    u_char ip_tos;  /* тип службы */
    u_short ip_len;  /* общая длина */
    u_short ip_id;  /* идентефикатор */
    u_short ip_off;  /* поле фрагмента смещения */
    #define IP_RF 0x8000  /* reserved флаг фрагмента */
    #define IP_DF 0x4000  /* dont флаг фрагмента */
    #define IP_MF 0x2000  /* more флаг фрагмента */
    #define IP_OFFMASK 0x1fff /* маска для битов фрагмента */
    u_char ip_ttl;  /* время жизни */
    u_char ip_p;  /* протокол */
    u_short ip_sum;  /* контрольная сумма */
   // struct in_addr ip_src,ip_dst; /* адрес источника и адрес назначения */
    struct in_addr ip_src,ip_dst;
 };
 #define IP_HL(ip)  (((ip)->ip_vhl) & 0x0f)
 #define IP_V(ip)  (((ip)->ip_vhl) >> 4)

int main(int argc, char *argv[])
{
  pcap_t *pcap;
  char errbuf[PCAP_ERRBUF_SIZE];
  struct sniff_ethernet *ethernet; /* Заголовок Ethernet */
  const struct sniff_ip *ip; /* Заголовок IP */
  struct pcap_pkthdr *header;
  const u_char *data;
  u_int packetCount = 0;

  if(argc != 2)
  {
    printf("usage: %s filename", argv[0]);
    return -1;
  }
  
  if ((pcap = pcap_open_offline(argv[1],errbuf )) == NULL)
  {
    fprintf(stderr,"\nUnable to open the file %s.\n", argv[1]);
    return -1;
  }

  while (int returnValue = pcap_next_ex(pcap, &header, &data) >= 0)
  {
    printf("Packet # %i\n", ++packetCount);
    printf("Packet size: %d bytes\n", header->len);

    ethernet = (struct sniff_ethernet*)(data);
    ip = (struct sniff_ip*)(data + SIZE_ETHERNET);
    printf("src address: %s dest address: %s \n",  inet_ntoa(ip->ip_src),  inet_ntoa(ip->ip_dst));
    
    printf("ETH\tsource: %s", (char *) ether_ntoa((struct ether_addr *) & ethernet->ether_shost));
    printf(" dest: %s\n", (char *) ether_ntoa((struct ether_addr *) & ethernet->ether_dhost));


    if (header->len != header->caplen)
      printf("Warning! Capture size different than packet size: %ld bytes\n", header->len);

    printf("Epoch Time: %d:%d seconds\n", header->ts.tv_sec, header->ts.tv_usec);

    for (u_int i = 0; (i < header->caplen); i++)
    {
      if ((i % 16) == 0) printf("\n");
      printf("%.2x ", data[i]);
    }
    printf("\n\n");
  }
}


The IP addresses of Source and Destination are displayed the same and do not match the information from Wireshark. I can't figure out what's wrong.

For example:
src address: 15.210.194.66 dest address: 15.210.194.66

And it should be:
src address: 172.30.255.18 dest address: 224.0.0.5

Answer the question

In order to leave comments, you need to log in

1 answer(s)
J
jcmvbkbc, 2020-02-20
@kuzko

Source and Destination IP addresses are displayed the same

From man inet_ntoa:
The string is returned in a statically allocated buffer,
which subsequent calls will overwrite.

With this change, your code works as expected for me:
printf("src address: %s ",  inet_ntoa(ip->ip_src));
printf("dest address: %s\n",  inet_ntoa(ip->ip_dst));

I suspect that completely left IP can climb from non-IP frames. Check the protocol field in the ethernet header before parsing the IP header.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question