C语言设置TCP报文自定义SYN/ACK值:解决显示与设置不符问题
你遇到的问题核心是网络字节序与主机字节序的不匹配——TCP协议头中的序列号(seq)和确认号(ack_seq)要求使用**网络字节序(大端序)**存储,但你直接赋值的是主机字节序的数值,导致Wireshark解析时出现了反转后的异常值。
一、TCP序列号的存储规则
TCP协议规定,报文中的所有多字节字段(包括seq、ack_seq、端口号等)都必须采用网络字节序(大端字节序):即高位字节先传输、先存储,低位字节在后。
而我们常用的x86/x86_64架构主机默认是小端字节序:低位字节存储在内存的低地址,高位字节存储在高地址。这就导致直接给TCP头字段赋值主机字节序数值时,实际发送的字节顺序会被反转,Wireshark按网络字节序解析后就会得到和预期完全不同的数值。
比如你设置tcph->seq = 1,小端主机内存中会存储为0x01 0x00 0x00 0x00,网络传输后Wireshark按大端序读取字节流,会把第一个字节当作最高位,最终解析为0x01000000(十进制16777216),而非你预期的1。你看到的4227858432本质也是未转换字节序的数值被反转后的结果。
二、正确设置自定义SYN/ACK值的方法
要解决这个问题,你需要使用系统提供的字节序转换函数,把主机字节序的数值转换为网络字节序:
- 对于32位的seq和ack_seq,使用
htonl()函数(Host TO Network Long) - 对于16位的端口号,使用
htons()函数(Host TO Network Short)
修改你代码中设置seq和ack_seq的部分:
// 原错误代码(未转换字节序) // tcph->seq = 1; // tcph->ack_seq = 6; // 修改后(正确转换为网络字节序) tcph->seq = htonl(1); tcph->ack_seq = htonl(6);
这样赋值后,函数会自动根据主机架构把数值转换为网络字节序,发送到网络后,Wireshark就能正确解析出你设置的1和6了。
额外验证:为什么端口号显示正常?
你代码中设置源端口和目的端口时用了htons(sourceport)和htons(destinationport),这是正确的——因为端口是16位字段,所以用htons()转换,这也是为什么端口号在Wireshark中显示正常,而seq/ack_seq出现异常的原因。
内容的提问来源于stack exchange,提问作者IwontDoIt

