0

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?

dbush
  • 205,898
  • 23
  • 218
  • 273
user known
  • 31
  • 2
  • 6
  • You didn't show us what `*buffer` is. Should it be just `buffer`? – Weather Vane Aug 13 '15 at 18:13
  • you're reading from some struct named `head`, but you don't show us what that is either. – Dan O Aug 13 '15 at 18:16
  • The buffer is unsigned char* buffer = (unsigned char *)malloc(65535); – user known Aug 13 '15 at 18:23
  • head is the object I am creating for the struct sampled_header. – user known Aug 13 '15 at 18:23
  • @userknown please put that in your question. But in that case, you should pass `buffer` to `memcpy` and not `*buffer`. – Weather Vane Aug 13 '15 at 18:23
  • @weather vane will the memcpy take a pointer of buffer ? I mean *buffer ?? its not accepting. – user known Aug 13 '15 at 18:28
  • You are making it very hard to answer by not posting complete code or a MCVE. Have you included the header file for `memcpy`? If I write `char *buffer; char *buffed; memcpy(buffed, buffer, 4);` that compiles perfectly well (apart from I have not initialised the pointers). – Weather Vane Aug 13 '15 at 18:32
  • I have included string.h and stdio.h header files. – user known Aug 13 '15 at 18:45
  • Related to http://stackoverflow.com/questions/31967938/finding-octet-in-a-udp-data-payload-in-c-program – dbush Aug 13 '15 at 18:46
  • @Weather Vane I have included the full code for your consideration – user known Aug 13 '15 at 18:51
  • @dbush its not completely related to it though both are same part of code. here I have posted a different question about the issues in memcpy I am defining. – user known Aug 13 '15 at 18:55
  • You shouldn't be using `memcpy`. You should be taking a pointer to the struct you want and pointing it to the proper place in the buffer you read from the network. You'll be doing basically the same thing as in your original post (before the edit), just with different structs. – dbush Aug 13 '15 at 18:57
  • struct sampled_header *head= (struct sampled_header *)buffer; can I do like this ? is this right way ? – user known Aug 13 '15 at 19:06
  • Your question was about the use of `memcpy()`. As I already wrote `memcpy(&head,&buffer,sizeof head);` or `memcpy(&head,*buffer,sizeof head);` should be `memcpy(&head,buffer,sizeof head);` because `head` is a struct and `buffer` is a pointer already. Although as @dbush says, maybe this is not the right way to do it anyway. – Weather Vane Aug 13 '15 at 19:09
  • when I used the above mentioned struct pointer, I am receiving following errors: 1) incompatible types when returning type ‘int’ but ‘struct sampled_header’ was expected 2) request for member ‘protocol’ in something not a structure or union 3) request for member ‘frame_length’ in something not a structure or union – user known Aug 13 '15 at 19:14

2 Answers2

1

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.

donjuedo
  • 2,475
  • 18
  • 28
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/87075/discussion-on-answer-by-donjuedo-use-of-memcpy-to-store-data-from-buffer-into-st). – Martijn Pieters Aug 16 '15 at 02:11
0

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.

Community
  • 1
  • 1
dbush
  • 205,898
  • 23
  • 218
  • 273
  • It doesn't show any difference in output. Will there be any mistake in printf statements I am using ? – user known Aug 14 '15 at 14:17
  • @userknown Did this answer your question? – dbush Aug 15 '15 at 02:54
  • your wireshark result gave an idea about how the details look like in a flow. But due to lack of knowledge on this, I am struggling to transform this idea into code. – user known Aug 15 '15 at 08:53
  • 1
    I am confused on how to locate the details i require to display. will the use of offset do some good for me and i am again confused how to make use of it. – user known Aug 15 '15 at 08:55
  • @userknown you now know the layout of the packet, so based on that you know what the offset of each field should be and what structs you should use to access them. – dbush Aug 17 '15 at 03:57
  • Yes. I collected the offset value of each fields inside the packet from their individual structs. But when I tried to use it in memcpy to specify the location from where the data should be read from buffer, it still doesn't show the right value. memcpy(&head.protocol,&buffer[4],4); Tis s for protocol field n sampled_ header struct. In buffer I have mentioned 4 to specify read the data until this offset. and third parameter is 4 specifying the size of data to be read. – user known Aug 17 '15 at 09:48
  • @userknown the protocol is at offset 0, not 4. That's where you start. Then add the size of that field to the current offset to get the next field. Do that for each subsequent field. Keep in mind that the contents of each field may dictate what the next field is – dbush Aug 17 '15 at 11:59
  • memcpy(&head.protocol,&buffer[0],4); memcpy(&head.frame_length,&buffer[4],4); I used this. The protocol value I received is 83886080 and frame_length is 1. – user known Aug 17 '15 at 12:39
  • My another doubt here is If I have to print the next struct after sampled_header, what is the offset value I would haveto start with. example, frame_length is the last field in sampled_header. its offset is 4. next struct is sampled_ethernet and first field is length starting from 0 in that struct. so should I add up the previous struct offset value and then start from that value ?? – user known Aug 17 '15 at 12:41
  • @userknown yes you would add up the values of everything that came before. The next field is not a sampled_ethernet however. It's a struct sample_datagram_v5 as detailed in my answer. After that is a 32 bit int that's not part of any struct. Also make sure to call ntohl on any 32 bit int to read it correctly. – dbush Aug 17 '15 at 12:53