使用memcpy将数据从缓冲区存储到struct中

时间:2015-08-13 18:08:39

标签: c struct memcpy

我有sflow数据包捕获代码,我需要从缓冲区打印sflow数据信息。我已经为所需信息定义了结构,并尝试使用memcpy将缓冲区信息复制到结构中。当我打印字段时,我得到了一些不正确的值。已附加下面的结构代码:

     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;                                                                  

我使用的缓冲区是unsigned char* buffer = (unsigned char *)malloc(65535);

我在这里附上了memcpy部分:

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

我收到的输出是:

     ethernet protocol : 31961104
     Frame Length : 0

我附上代码供您考虑:

    #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;
    }

我已将我的输出粘贴到您的考虑

---------------------------------------------
 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

几乎所有字段都显示错误值,如何解决此问题?

2 个答案:

答案 0 :(得分:0)

显示的memcpy()的所有3次使用都是*buffer&buffer&buffer,因此您的副本来自错误的位置,导致输出错误看到。只需传递buffer,因为它已经是所需的指针。

答案 1 :(得分:0)

您正在从缓冲区中的错误偏移进行复制。

假设数据包含struct sampled_header,后跟struct sampled_ethernet,后跟struct sampled_ipv4,后跟struct extended_switch,则应执行以下操作:

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
...

编辑:

看起来我们已经开始关注数据的样子了。我获取了this question中列出的数据字节,将它们读入缓冲区并通过UDP数据包发送出去。我解雇了Wireshark,它给了我们这个:

Wireshark capture

所以数据包包含:

  • sflow版本,32位(5)
  • 32位int(值= 1)
  • a struct sample_datagram_v5
  • 样本数(32位int,值= 6)
  • 六个样本

第一个样本包含:

  • 样本类型为data_format(在本例中为流量样本)
  • a struct flow_sample
  • 流样本数(32位整数,值= 2)

第一个样本中的第一个流程:

  • 流类型为data_format(在本例中为原始数据包样本,因此......)
  • 流数据长度(32位int,值= 144)
  • a struct sampled_header
  • 根据sampled_header.stripped
  • 的值跳过的4个字节
  • 以太网标题
  • IP标头(有效负载= TCP)
  • TCP标头(端口= 80)
  • 数据字节(62)

第一个样本中的第二个流程:

  • 流类型为data_format(在本例中为扩展交换机数据)
  • 流数据长度(32位int,值= 16)
  • a struct extended_switch

然后又有五个样本。在这种情况下,所有样本都包含原始数据包标头和扩展开关数据。

所以这应该可以让你更好地了解你需要做什么。由于每个数据包都不同,因此您需要确定您拥有的样本数量。然后,对于每个样本,您需要确定类型,并根据该数据解析如何解析各个流。

如果您需要更多示例,我强烈建议您使用Wireshark捕获这些sflow数据包,以便您可以准确了解其中的内容,以验证您的解析器是否适用于所有预期的输入。