将char *转换为struct

时间:2017-06-30 07:22:26

标签: c++ c sockets

在代码here中,有一行:

struct iphdr * iph = (struct iphdr *)buffer;
ProcessPacket函数中的

,其中buffer的类型为char*buffer已在主函数中被recvfrom赋予值。如何将简单字符串(buffer)转换为结构以及如何安全地提取数据?

iphdr:

struct iphdr {
    #if defined(__LITTLE_ENDIAN_BITFIELD)
        __u8    ihl:4,
                version:4;
    #elif defined (__BIG_ENDIAN_BITFIELD)
        __u8    version:4,
                ihl:4;
    #else
        #error  "Please fix <asm/byteorder.h>"
    #endif
         __u8   tos;
         __u16  tot_len;
         __u16  id;
         __u16  frag_off;
         __u8   ttl;
         __u8   protocol;
         __u16  check;
         __u32  saddr;
         __u32  daddr;
         /*The options start here. */
};

3 个答案:

答案 0 :(得分:5)

buffer a string。它是指向原始二进制数据的指针。 recvfrom使用原始IP / TCP帧(也称为数据包)填充(在此示例中,见下文)buffer。因此,sizeof(iphdr)的前buffer个字节是IP-header结构:iphdr。这正是博客作者使用您提供的代码段的原因:

struct iphdr * iph = (struct iphdr *)buffer;

如果包含IP标头选项,则标头的实际大小为iph->ihl*4

然后在iph->protocol(在博客中)检查标头的协议字段(ProcessPacket),以确定数据包包含哪种传输协议。

如果使用的传输协议是TCP,则可以使用(来自博客的片段)提取TCP标头(以及稍后的数据):

unsigned short iphdrlen = iph->ihl*4;
struct tcphdr *tcph = (struct tcphdr*)(buffer + iphdrlen);

原始框架

博客作者使用以下方式创建了套接字:

sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
  • 第一个参数AF_INET表示您需要IPv4数据包(与IPv6AF_INET6相对)。
  • 第二个参数告诉socket您想要原始帧
  • 第三个参数(IPPROTO_TCP)确保您获得TCP帧

或者,如果您想要UDP帧,可以使用:

 sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_UDP);

如果您贪婪并且想要每个数据包使用(请在使用之前先阅读框架格式!):

socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

答案 1 :(得分:2)

我认为代码引入了未定义的行为,因为在程序过程中执行了以下两行:

unsigned char *buffer = (unsigned char *)malloc(65536);
...
struct iphdr *iph = (struct iphdr*)buffer;

buffer是指向保留为unsigned char*的内存块的指针,然后将其转换为类型为struct iphdr的指针;但是struct iphdr很可能具有与char*不同的对齐限制,这是未定义的行为(例如,参见this online c11 draft standard):

  

6.3.2.3指针

     

(7)指向对象类型的指针可以转换为指向a的指针   不同的对象类型。如果结果指针不正确   对于引用的类型,行为是未定义的。 ...

虽然它可能有用(它仍然是UB的选项之一),但也可能是程序的行为与你不打算一样。

我建议将信息复制到正确对齐的struct iphdr - 对象中:

unsigned char *buffer = (unsigned char *)malloc(65536);
...
struct iphdr iphobj;
memcpy(&iphobj,buffer,sizeof(struct iphdr));
...

然后照顾对象的生命周期。

请注意,您已对代码CC++进行了标记,并且两种语言都有不同的规则(例如,有关malloc结果的显式转换,这在C ++中是必需的,但不是C)鼓励。

但是关于UB,我很确定代码在C和C ++这两种语言中引入了UB。

答案 2 :(得分:0)

首先要理解的是,无论转换(struct iphdr *)如何,内存中的位都保持完全相同。只是你现在说buffer现在被视为指向struct iphdr而不是之前的指针。您只是告诉编译器使用不同的眼镜看比特,因此进行相应的解释。编译器突然发现buffer已成为struct iphdr *。说&#34;好的&#34;这就是全部。重要的是,您确切地知道buffer是什么,并将其转换为正确的类型。

如果你愿意,你可以使用类型转换bufferint *(或任何其他指针类型),编译器也不会说什么。虽然你以后会遇到问题。