简体   繁体   English

TCP校验和为0

[英]TCP checksum is 0

I have the followiing code for tcp header: 我有tcp标头的以下代码:

struct tcp_header {
    uint16_t tcp_sport;
    uint16_t tcp_dport;
    uint32_t tcp_th_seq;
    uint32_t tcp_ack;
    uint8_t tcp_off:4;
    uint8_t tcp_res:6;
    uint8_t tcp_uf:1, tcp_af:1, tcp_pf:1, tcp_rf:1, tcp_sf:1, tcp_ff:1;
    uint16_t tcp_win;
    uint16_t tcp_sum;
    uint16_t tcp_urp;
};

...

void decode_tcp(const unsigned char *header_start) {

    const struct tcp_header *tcp_hdr;

    tcp_hdr = (const struct tcp_header *)(header_start + ETHERNET_HEADER_SIZE + IP_HEADER_SIZE);

    printf("\n    TCP Header\n");

    printf("\tSource Port       : %u\n", ntohs(tcp_hdr->tcp_sport));
    printf("\tDestination Port  : %u\n", ntohs(tcp_hdr->tcp_dport));
    printf("\tSequence number   : %u\n", ntohl(tcp_hdr->tcp_th_seq));
    printf("\tAcknowledge number: %u\n", ntohl(tcp_hdr->tcp_ack));
    printf("\tOffset            : %d\n", tcp_hdr->tcp_off);
    printf("\tReserved          : %d\n", (unsigned int)tcp_hdr->tcp_res);
    printf("\tUrgent Flag       : %d\n", (unsigned int)tcp_hdr->tcp_uf);
    printf("\tAcknoledge Flag   : %d\n", (unsigned int)tcp_hdr->tcp_af);
    printf("\tPush Flag         : %d\n", (unsigned int)tcp_hdr->tcp_pf);
    printf("\tReset Flag        : %d\n", (unsigned int)tcp_hdr->tcp_rf);
    printf("\tSynchronise Flag  : %d\n", (unsigned int)tcp_hdr->tcp_sf);
    printf("\tFinish Flag       : %d\n", (unsigned int)tcp_hdr->tcp_ff);
    printf("\tWindow            : %d\n", ntohs(tcp_hdr->tcp_win));
    printf("\tChecksum          : %d\n", ntohs(tcp_hdr->tcp_sum));
    printf("\tUrgent Pointer    : %d", ntohs(tcp_hdr->tcp_urp));
}

The output I get is 我得到的输出是 在此输入图像描述

CHecksum is 0, so I think something is false. CHecksum是0,所以我认为有些事情是错误的。 Can you guys spot the mistake? 你们能发现错误吗? Or canchecksum should be 0? 或者canchecksum应该是0?

Also can sourceport be 22? sourceport也可以22?

Most of the conversion specifiers used are wrong here: 这里使用的大多数转换说明符都是错误的:

printf("\tSource Port       : %u\n", ntohs(tcp_hdr->tcp_sport));
printf("\tDestination Port  : %u\n", ntohs(tcp_hdr->tcp_dport));
printf("\tSequence number   : %u\n", ntohl(tcp_hdr->tcp_th_seq));
printf("\tAcknowledge number: %u\n", ntohl(tcp_hdr->tcp_ack));
printf("\tOffset            : %d\n", tcp_hdr->tcp_off);
printf("\tReserved          : %d\n", (unsigned int)tcp_hdr->tcp_res);
printf("\tUrgent Flag       : %d\n", (unsigned int)tcp_hdr->tcp_uf);
printf("\tAcknoledge Flag   : %d\n", (unsigned int)tcp_hdr->tcp_af);
printf("\tPush Flag         : %d\n", (unsigned int)tcp_hdr->tcp_pf);
printf("\tReset Flag        : %d\n", (unsigned int)tcp_hdr->tcp_rf);
printf("\tSynchronise Flag  : %d\n", (unsigned int)tcp_hdr->tcp_sf);
printf("\tFinish Flag       : %d\n", (unsigned int)tcp_hdr->tcp_ff);
printf("\tWindow            : %d\n", ntohs(tcp_hdr->tcp_win));
printf("\tChecksum          : %d\n", ntohs(tcp_hdr->tcp_sum));
printf("\tUrgent Pointer    : %d", ntohs(tcp_hdr->tcp_urp));

It should be: 它应该是:

printf("\tSource Port       : %hu\n", ntohs(tcp_hdr->tcp_sport));
printf("\tDestination Port  : %hu\n", ntohs(tcp_hdr->tcp_dport));
printf("\tSequence number   : %u\n", ntohl(tcp_hdr->tcp_th_seq));
printf("\tAcknowledge number: %u\n", ntohl(tcp_hdr->tcp_ack));
printf("\tOffset            : %hhu\n", tcp_hdr->tcp_off);
printf("\tReserved          : %u\n", (unsigned int)tcp_hdr->tcp_res);
printf("\tUrgent Flag       : %u\n", (unsigned int)tcp_hdr->tcp_uf);
printf("\tAcknoledge Flag   : %u\n", (unsigned int)tcp_hdr->tcp_af);
printf("\tPush Flag         : %u\n", (unsigned int)tcp_hdr->tcp_pf);
printf("\tReset Flag        : %u\n", (unsigned int)tcp_hdr->tcp_rf);
printf("\tSynchronise Flag  : %u\n", (unsigned int)tcp_hdr->tcp_sf);
printf("\tFinish Flag       : %u\n", (unsigned int)tcp_hdr->tcp_ff);
printf("\tWindow            : %hu\n", ntohs(tcp_hdr->tcp_win));
printf("\tChecksum          : %hu\n", ntohs(tcp_hdr->tcp_sum));
printf("\tUrgent Pointer    : %hu", ntohs(tcp_hdr->tcp_urp));

If you'd removed all those castings to unsigned int you could use hhu as conversion specifier for printf() ing, as all those variables are defined to be unsigned 8-bit values. 如果你将所有这些转换删除为unsigned int你可以使用hhu作为printf()转换说明符,因为所有这些变量都被定义为unsigned 8位值。

Your code has some problems: 您的代码有一些问题:

  • do not use bitfields! 不要使用位域! They are not portable across different ABIs. 它们不能在不同的ABI中移植。
  • ensure that structure is packed (eg by __attribute__((__packed__)) annotation). 确保结构被打包(例如通过__attribute__((__packed__))注释)。 ABI can add padding between attributes else. ABI可以在其他属性之间添加填充。
  • the tcp_hdr = (const struct tcp_header *)(header_start can cause misaligned access when reading/writing tcp_hdr fields. The __packed__ annotation above can prevent this; alternatively, you can copy content in a (correctly aligned) local variable. tcp_hdr = (const struct tcp_header *)(header_start在读取/写入tcp_hdr字段时可能导致错位访问。上面的__packed__注释可以防止这种情况;或者,您可以复制(正确对齐的)局部变量中的内容。

I would add some sanity checks like 我会添加一些健全性检查

BUILD_BUG_ON(offsetof(struct tcp_header, tcp_sum) != 0x10));

(please check in tcp rfc whether tcp_sum is really at position 0x10!) (请检查tcp rfc tcp_sum是否确实位于0x10位置!)

I think your TCP header definiton has problem (which is 24 bytes but standard header is 20). 我认为你的TCP头定义有问题(这是24字节,但标准头是20)。 Use standard declaration on system which also considers alignment: 在系统上使用标准声明,也考虑对齐:

#include <netinet/tcp.h>

tcp header definition: tcp头定义:

struct tcphdr {
    u_short th_sport;               /* source port */
    u_short th_dport;               /* destination port */
    tcp_seq th_seq;                 /* sequence number */
    tcp_seq th_ack;                 /* acknowledgement number */
#if __BYTE_ORDER == __LITTLE_ENDIAN
    u_int   th_x2:4,                /* (unused) */
        th_off:4;               /* data offset */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
    u_int   th_off:4,               /* data offset */
        th_x2:4;                /* (unused) */
#endif
    u_char  th_flags;
#define TH_FIN  0x01
#define TH_SYN  0x02
#define TH_RST  0x04
#define TH_PUSH 0x08
#define TH_ACK  0x10
#define TH_URG  0x20
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG)

    u_short th_win;                 /* window */
    u_short th_sum;                 /* checksum */
    u_short th_urp;                 /* urgent pointer */
};

Inbound or outbound? 入境或出境? The outbound checksum can be 0 if checksum offloading to the NIC is enabled... 如果启用了校验和卸载到NIC,则出站校验和可以为0 ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM