0
votes

I have sflow packet capture code in which I need to print the sflow data information from buffer. I have defined the structs for the required information and trying to use memcpy to copy the buffer information into the struct. when I print the fields, I get some big value which isn't the correct one. The have attached the struct code below:

     typedef unsigned char mac[6];
     typedef unsigned char ip_v4[4];
     typedef unsigned char ip_v6[16];
     typedef unsigned int header_protocol;


     /* Packet header data */

     const MAX_HEADER_SIZE = 256;   /* The maximum sampled header size. */

     struct sampled_header {
     header_protocol protocol;       /* Format of sampled header */
     unsigned int frame_length;      /* Original length of packet before
                                      sampling */
    //opaque header<MAX_HEADER_SIZE>; /* Header bytes */
    }head;

    /* Ethernet Frame Data */
    /* opaque = flow_data; enterprise = 0; format = 2 */

    struct sampled_ethernet {
    unsigned int length;   /* The length of the MAC packet received on the
                               network, excluding lower layer encapsulations
                               and framing bits but including FCS octets */
     mac src_mac;           /* Source MAC address */
     mac dst_mac;           /* Destination MAC address */
     unsigned int type;     /* Ethernet packet type */
    }ether;

    /* Packet IP version 4 data */

    struct sampled_ipv4 {
    unsigned int length;     /* The length of the IP packet excluding
                               lower layer encapsulations */
    unsigned int protocol;   /* IP Protocol type
                               (for example, TCP = 6, UDP = 17) */
    ip_v4 src_ip;            /* Source IP Address */
    ip_v4 dst_ip;            /* Destination IP Address */
    unsigned int src_port;   /* TCP/UDP source port number or
                               equivalent */
    unsigned int dst_port;   /* TCP/UDP destination port number or
                               equivalent */
    unsigned int tcp_flags;  /* TCP flags */
    unsigned int tos;        /* IP type of service */
    }ip4;
    /* Packet IP version 6 data */

    struct sampled_ipv6 {
    unsigned int length;     /* The length of the IP packet excluding
                               lower layer encapsulations */
    unsigned int protocol;   /* IP next header
                               (for example, TCP = 6, UDP = 17) */
    ip_v6 src_ip;            /* Source IP Address */
    ip_v6 dst_ip;            /* Destination IP Address */
    unsigned int src_port;   /* TCP/UDP source port number or
                               equivalent */
    unsigned int dst_port;   /* TCP/UDP destination port number or
                               equivalent */
    unsigned int tcp_flags;  /* TCP flags */
    unsigned int priority;   /* IP priority */
    }ip6;

    /* Extended switch data */

    struct extended_switch {
   unsigned int src_vlan;     /* The 802.1Q VLAN id of incoming frame */
   unsigned int src_priority; /* The 802.1p priority of incoming
                                 frame */
   unsigned int dst_vlan;     /* The 802.1Q VLAN id of outgoing frame */
   unsigned int dst_priority; /* The 802.1p priority of outgoing
                                 frame */
}swch;                                                                  

The buffer I am using is unsigned char* buffer = (unsigned char *)malloc(65535);

I have attached memcpy part here:

memcpy(&sampled_ethernet,*buffer,sizeof sampled_ethernet);
printf("ethernet protocol : %d\n", head.protocol);
printf("Frame Length : %d\n", head.frame_length); 

The output I am receiving is :

     ethernet protocol : 31961104
     Frame Length : 0

I am attaching the code for your consideration:

    #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<sys/socket.h>
#include<arpa/inet.h>
#include<net/ethernet.h>
#include<netinet/if_ether.h>
#include<fcntl.h>
#define PORT 6343             // define the port to connect
#define ETH_P_IP 0x0800

int sockt;
int i,j;
struct sockaddr_in source,dest; 

typedef unsigned char mac[6];
typedef unsigned char ip_v4[4];
typedef unsigned char ip_v6[16];
typedef unsigned int header_protocol;


/* Packet header data */

const MAX_HEADER_SIZE = 256;   /* The maximum sampled header size. */

struct sampled_header {
   header_protocol protocol;       /* Format of sampled header */
   unsigned int frame_length;      /* Original length of packet before
                                      sampling */
   //opaque header<MAX_HEADER_SIZE>; /* Header bytes */
}head;

/* Ethernet Frame Data */
/* opaque = flow_data; enterprise = 0; format = 2 */

struct sampled_ethernet {
     unsigned int length;   /* The length of the MAC packet received on the
                               network, excluding lower layer encapsulations
                               and framing bits but including FCS octets */
     mac src_mac;           /* Source MAC address */
     mac dst_mac;           /* Destination MAC address */
     unsigned int type;     /* Ethernet packet type */
}ether;

/* Packet IP version 4 data */

struct sampled_ipv4 {
   unsigned int length;     /* The length of the IP packet excluding
                               lower layer encapsulations */
   unsigned int protocol;   /* IP Protocol type
                               (for example, TCP = 6, UDP = 17) */
   ip_v4 src_ip;            /* Source IP Address */
   ip_v4 dst_ip;            /* Destination IP Address */
   unsigned int src_port;   /* TCP/UDP source port number or
                               equivalent */
   unsigned int dst_port;   /* TCP/UDP destination port number or
                               equivalent */
   unsigned int tcp_flags;  /* TCP flags */
   unsigned int tos;        /* IP type of service */
}ip4;
/* Packet IP version 6 data */

struct sampled_ipv6 {
   unsigned int length;     /* The length of the IP packet excluding
                               lower layer encapsulations */
   unsigned int protocol;   /* IP next header
                               (for example, TCP = 6, UDP = 17) */
   ip_v6 src_ip;            /* Source IP Address */
   ip_v6 dst_ip;            /* Destination IP Address */
   unsigned int src_port;   /* TCP/UDP source port number or
                               equivalent */
   unsigned int dst_port;   /* TCP/UDP destination port number or
                               equivalent */
   unsigned int tcp_flags;  /* TCP flags */
   unsigned int priority;   /* IP priority */
}ip6;

/* Extended switch data */

struct extended_switch {
   unsigned int src_vlan;     /* The 802.1Q VLAN id of incoming frame */
   unsigned int src_priority; /* The 802.1p priority of incoming
                                 frame */
   unsigned int dst_vlan;     /* The 802.1Q VLAN id of outgoing frame */
   unsigned int dst_priority; /* The 802.1p priority of outgoing
                                 frame */
}swch;


int main()
    {

    int saddr_size,data_size, datasize; 
    struct sockaddr_in saddr;
    struct sockaddr_in daddr;
    struct in_addr addr;
    unsigned char* buffer = (unsigned char *)malloc(65535); // Its Big ! Malloc allocates a block of size bytes of memory,returning a pointer to the begining of the block

    //Create a socket

    sockt = socket(AF_INET ,SOCK_DGRAM ,IPPROTO_UDP);
    if(sockt < 0)
    {
        printf("Socket Error\n");
        return 1;
    }
    memset((char *)&daddr,0,sizeof(daddr));

    //prepare the sockaddr_in structure
    saddr.sin_family = AF_INET;
    daddr.sin_family = AF_INET;
    daddr.sin_addr.s_addr = htonl(INADDR_ANY);
    daddr.sin_port = htons(PORT);
    saddr.sin_port = htons(PORT);

    //Bind the socket

    if(bind(sockt,(struct sockaddr *)&daddr, sizeof(daddr))<0)
    {
      printf("bind failed");
      return 1;
    }
    printf("bind done");

    while(1)
    {
    saddr_size = sizeof saddr;
    printf(" waiting for data...\n");

    //Receive a packet

    datasize = recvfrom(sockt , buffer ,65535 , 0 , (struct sockaddr*) &saddr , (socklen_t*)&saddr_size);
    data_size = recvfrom(sockt , buffer ,65535 , 0 , NULL , NULL);
    if(data_size <0)
    {
      printf("Packets not recieved \n");
      return 1;
    }
    printf("Packets arrived from %d \n",ntohs(daddr.sin_port));
    printf("packet recieved : %lu bytes\n", datasize);

    memcpy(&head,&buffer,sizeof head);
    printf("---------------------------------------------\n");
    printf(" Sampled Header \n");
    printf("---------------------------------------------\n");

    printf("ethernet protocol : %d\n",ntohl(head.protocol));
    printf("Frame Length : %d\n", htonl(head.frame_length));

    memcpy(&ether,&buffer,sizeof ether);
    printf("---------------------------------------------\n");
    printf(" Sampled Ethernet \n");
    printf("---------------------------------------------\n");

    printf("Ethernet Length : %u bytes\n",ntohs(ether.length));
    printf("Source MAC : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n", ether.src_mac[0], ether.src_mac[1], ether.src_mac[2], ether.src_mac[3], ether.src_mac[4], ether.src_mac[5], ether.src_mac[6]);
    printf("Destination MAC : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n", ether.dst_mac[0], ether.dst_mac[1], ether.dst_mac[2], ether.dst_mac[3], ether.dst_mac[4], ether.dst_mac[5], ether.dst_mac[6]);
    printf(" Ethernet Type : %u\n",htons(ether.type));

memcpy(&ip4,&buffer[sizeof(head)],sizeof ip4);

printf("---------------------------------------------\n");
    printf(" Sampled IPv4 \n");
    printf("---------------------------------------------\n");

    printf("IPv4 Length : %d\n", sizeof(ip4.length));
    printf("IP Protocol : %d\n", ntohl(ip4.protocol));
    printf("Source IP Address : %d.%d.%d.%d\n",ip4.src_ip[0],ip4.src_ip[1],ip4.src_ip[2],ip4.src_ip[3]);
    printf("Destination IP Address : %d.%d.%d.%d\n",ip4.dst_ip[0],ip4.dst_ip[1],ip4.dst_ip[2],ip4.dst_ip[3]);
    printf("Source Port : %d\n",ntohs(myaddr.sin_port));
    printf("Destination Port : %d\n",ntohs(daddr.sin_port));
    printf("TCP flags : %d\n",(unsigned int)ip4.tcp_flags);
    printf("Type of Service : %d\n",htons(ip4.tos));

    memcpy(&swh,&buffer[sizeof(ip4)],sizeof swh);
printf("---------------------------------------------\n");
    printf(" Extended Switch \n");
    printf("---------------------------------------------\n");    

    printf("Source VLAN : %lu\n",offsetof(struct extended_switch,src_vlan));
    printf("Source Priority : %lu\n",(unsigned int)swh.src_priority);
    printf("Destination VLAN : %lu\n",(unsigned int)swh.dst_vlan);
    printf("Destination Priority : %lu\n",(unsigned int)swh.src_priority);
    }
    close(sockt);
    printf("Finished");
    return 0;
    }

I have pasted my output for your consideration

---------------------------------------------
 Sampled Header 
---------------------------------------------
    ethernet protocol : 5
Frame Length : 1

---------------------------------------------
 Sampled Ethernet 
---------------------------------------------


 Ethernet Length : 2478620678 bytes
Source MAC : 00-00-00-00-00-35
Destination MAC : 6D-28-2F-D9-AB-B0
 Ethernet Type : 0
---------------------------------------------
 Sampled IPv4 
---------------------------------------------
IPv4 Length : 4
    IPv4 Length : 4
IP Protocol : 0
Source IP Address : 0.53.109.40
Destination IP Address : 47.217.171.176
Source Port : 61842
Destination Port : 6343
TCP flags : -1811939328
Type of Service : 302

---------------------------------------------
 Extended Switch 
---------------------------------------------
    Source VLAN : 2483027968
Source Priority : 1653157377
Destination VLAN : 486539264
Destination Priority : 1653157377

There are still incorrect values shown for almost all the fields, how can I solve this issue?

2
You didn't show us what *buffer is. Should it be just buffer?Weather Vane
you're reading from some struct named head, but you don't show us what that is either.Dan O
The buffer is unsigned char* buffer = (unsigned char *)malloc(65535);user known
head is the object I am creating for the struct sampled_header.user known
@userknown please put that in your question. But in that case, you should pass buffer to memcpy and not *buffer.Weather Vane

2 Answers

1
votes

All 3 uses of memcpy() shown are passing *buffer, &buffer, and &buffer, so your copies are coming from the wrong location, leading to the wrong output you see. Just pass buffer instead, as it is already the pointer needed.

0
votes

You're copying from the wrong offsets in your buffer.

Assuming the data contains a struct sampled_header, followed by a struct sampled_ethernet, followed by a struct sampled_ipv4, followed by a struct extended_switch, you should do the following:

memcpy(&head,buffer,sizeof head);
// read contents of head
...
memcpy(&ether,&buffer[sizeof(head)],sizeof ether);
// read contents of ether
...
memcpy(&ip4,&buffer[sizeof(head) + sizeof(ether)],sizeof ip4);
// read contents of ip4
...
memcpy(&swh,&buffer[sizeof(head) + sizeof(ether) + sizeof(ip4)],sizeof swh);
// read contents of swh
...

Edit:

It looks like we're way off on what the data looks like. I took the data bytes you listed in this question, read them into a buffer and sent it out in a UDP packet. I fired up Wireshark, which gave us this:

Wireshark capture

So the packet contains:

  • The sflow version, 32-bit (5)
  • an 32 bit int (value=1)
  • a struct sample_datagram_v5
  • the number of samples (32-bit int, value=6)
  • six samples

The first sample contains:

  • The sample type as a data_format (in this case a flow sample)
  • a struct flow_sample
  • the number of flow samples (32-bit int, value=2)

The first flow in the first sample:

  • The flow type as a data_format (int this case a raw packet sample, so...)
  • the flow data length (32-bit int, value=144)
  • a struct sampled_header
  • 4 bytes that are skipped as per the value of sampled_header.stripped
  • ethernet header
  • IP header (payload=TCP)
  • TCP header (port=80)
  • data bytes (62)

The second flow in the first sample:

  • The flow type as a data_format (int this case extended switch data)
  • the flow data length (32-bit int, value=16)
  • a struct extended_switch

Then five more samples. In this case, all the samples contain a raw packet header and extended switch data.

So this should give you a better idea of what you need to do. Since each data packet will be different, you'll need to figure our how many samples you have. Then for each sample, you'll need to figure out the type, and based on that figure out how to parse the individual flows.

If you need more examples I'd strongly suggest using Wireshark to capture these sflow packets so you can see exactly what's in them to validate that your parser works for all expected input.