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

我有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; /* 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 //For standard things #include //malloc #include //memset #include //Provides declarations for icmp header #include //Provides declarations for udp header #include //Provides declarations for tcp header #include //Provides declarations for ip header #include #include #include #include #include #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; /* 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 

几乎所有字段都显示不正确的值,我该如何解决这个问题?

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

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

假设数据包含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 ... 

编辑:

看起来我们的数据看起来很像。 我拿了你在这个问题中列出的数据字节,将它们读入一个缓冲区并用UDP包发送出去。 我解雇了Wireshark,它给了我们这个:

Wireshark捕获

所以包包含:

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

第一个样本包含:

  • 样本类型为data_format (在本例中为流样本)
  • struct flow_sample
  • 流样本数(32位int,value = 2)

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

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

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

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

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

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

如果您需要更多示例,我强烈建议您使用Wireshark捕获这些sflow数据包,这样您就可以准确地看到它们中的内容,以validation您的解析器是否适用于所有预期的输入。