首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >报文解析错误

报文解析错误
EN

Stack Overflow用户
提问于 2012-02-07 00:12:37
回答 3查看 661关注 0票数 0

我正在尝试解析一个数据包。直到有了ip头,一切都正常了(我能够正确地检索所有值)。但对于udp报头(如果协议是17,则检查),结果显示值是错误的(所有4个字段)。我正在尝试这样做:

代码语言:javascript
复制
struct udp_header{
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t chksum;
};
 struct udp_header* udp= (struct udp_header*)(packet + 14 + ip_hdr->ip_hl*4); 

packet是指向数据包开头的指针。14表示以太网header.The报头长度ip在被检查时给出了正确的值。但在执行此操作后,我错误地获取了所有字段。当尝试使用uint8_t作为数据类型时(我知道这是错误的!)不知何故,目标端口输出正确。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-02-07 00:14:44

你遇到了endianness。IP数据包的所有字段都是网络字节顺序(也称为"big-endian"),而您的主机系统可能运行little-endian。在ntohs()和朋友中寻找一种方法。

正确的方法是不从网络数据中按原样复制结构,而是手动提取每个字段,并在必要时对其进行字节交换。这也解决了与填充和对齐有关的任何问题,不能保证您的struct以与序列化数据包完全相同的方式映射到计算机内存中。

所以你会这样做,例如:

代码语言:javascript
复制
udp_header.sport = ntohs(*(unsigned short*) (packet + 14 + 4 * ip_hdr->ip_hl));

这也有点可疑,因为它假设结果地址可以有效地转换为指向unsigned short的指针。在x86上,这是可行的,但它不是史诗。

在我看来,更好的做法是放弃使用指针,而是编写一个名为unsigned short read_u16(void *packet, size_t offset)的函数,它逐个字节地提取值并返回它。然后你就会这样做:

代码语言:javascript
复制
udp_header.sport = read_u16(packet, 14 + 4 * ip_hdr->ip_hl);
票数 3
EN

Stack Overflow用户

发布于 2012-02-07 00:51:32

我总是对IP报头使用这个结构:

代码语言:javascript
复制
struct sniff_ip {
    u_char  ip_vhl;                 /* version << 4 | header length >> 2 */
    u_char  ip_tos;                 /* type of service */
    u_short ip_len;                 /* total length */
    u_short ip_id;                  /* identification */
    u_short ip_off;                 /* fragment offset field */
    #define IP_RF 0x8000            /* reserved fragment flag */
    #define IP_DF 0x4000            /* dont fragment flag */
    #define IP_MF 0x2000            /* more fragments flag */
    #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
    u_char  ip_ttl;                 /* time to live */
    u_char  ip_p;                   /* protocol */
    u_short ip_sum;                 /* checksum */
    struct  in_addr ip_src,ip_dst;  /* source and dest address */
};
#define IP_HL(ip)               (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip)                (((ip)->ip_vhl) >> 4)

并获取UDP结构指针:

代码语言:javascript
复制
udp = (struct sniff_udp*)(packet + SIZE_ETHERNET + (IP_HL(ip)*4));
票数 2
EN

Stack Overflow用户

发布于 2012-02-07 02:39:21

正如另一个答案所说,您必须处理数据的字节顺序。

您需要处理的另一件事是字节对齐。为了提高速度,当您在C中定义一个结构时,如下所示:

代码语言:javascript
复制
struct udp_header{
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t chksum;
};

C编译器可以在这些字段之间保留填充字节,以便可以使用更快的单指令内存访问汇编指令来完成成员访问。您可以通过printf("struct size is: %u\n", sizeof(struct udp_header));检查c++编译器是否正在执行此操作。

假设您使用的是GCC,则必须通过在结构定义前添加#pragma pack(1)来禁用填充字节。要重新启用填充以提高速度,您应该使用#pragma pack()

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9163216

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档