在这里的代码中,有一行:
struct iphdr * iph = (struct iphdr *)buffer;
Run Code Online (Sandbox Code Playgroud)
在ProcessPacket函数where buffer类型char*.buffer已经recvfrom在主函数中给出了值.如何将简单的string(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. */
};
Run Code Online (Sandbox Code Playgroud)
buffer是不是一个string.它是指向原始二进制数据的指针.使用原始IP/TCP帧(也称为数据包)recvfrom填充(在此示例中,见下文buffer).因此,第一个sizeof(iphdr)字节buffer是IP头结构:iphdr.这正是博客作者使用您提供的代码段的原因:
struct iphdr * iph = (struct iphdr *)buffer;
Run Code Online (Sandbox Code Playgroud)
如果包含IP标头选项,则标头的实际大小为iph->ihl*4.
然后在(在博客中)检查报头的协议字段(iph->protocol)ProcessPacket,以确定该分组包含哪个传输协议.
如果使用的传输协议是TCP,则可以使用(来自博客的片段)提取TCP标头(以及稍后的数据):
unsigned short iphdrlen = iph->ihl*4;
struct tcphdr *tcph = (struct tcphdr*)(buffer + iphdrlen);
Run Code Online (Sandbox Code Playgroud)
原始帧
该博客的作者使用以下方法创建了套接字:
sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
Run Code Online (Sandbox Code Playgroud)
或者,如果您想要UDP帧,您可以使用:
sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_UDP);
Run Code Online (Sandbox Code Playgroud)
如果您贪婪并希望每个数据包都使用(请在使用之前阅读框架格式!):
socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
Run Code Online (Sandbox Code Playgroud)