简体   繁体   English

尝试在C中发送数据包时,TCP校验和不正确

[英]TCP checksum is incorrect when trying to send packet in C

I am trying to send a TCP SYN packet through a RAW socket in C (I know it's not the easiest thing to do but I have academic reasons to do so). 我正在尝试通过C中的RAW套接字发送TCP SYN数据包(我知道这不是最简单的事情,但我有学术理由这样做)。

When I check the outgoing packet, every fields are good but one: the TCP checksum. 当我检查传出数据包时,每个字段都很好,但只有一个:TCP校验和。 Indeed, Wireshark tells me it is incorrect. 确实,Wireshark告诉我这是不正确的。 In the following code, you can see how I build the packet (the IP headers are omitted because they seem to be OK). 在下面的代码中,您可以看到我如何构建数据包(IP头被省略了,因为它们看起来还可以)。

#define MINIMUM_TCP_HEADER_LENGTH 20
#define DEFAULT_TCP_WINDOW 32767

// [... Code that sets the IP headers ...]

struct tcphdr * tcpHeaders = (struct tcphdr *) (packetBuffer + IPHeaderLength);

tcpHeaders->source = htons(srcPort_16);
tcpHeaders->dest = htons(dstPort_16);
tcpHeaders->seq = htonl(tcpSeq_32);
tcpHeaders->ack_seq = 0;
tcpHeaders->doff = (MINIMUM_TCP_HEADER_LENGTH / 4);
tcpHeaders->res1 = 0;
tcpHeaders->res2 = 0;
tcpHeaders->syn = 1;
tcpHeaders->ack = 0;
tcpHeaders->fin = 0;
tcpHeaders->psh = 0;
tcpHeaders->urg = 0;
tcpHeaders->rst = 0;
tcpHeaders->window = htons(DEFAULT_TCP_WINDOW);
tcpHeaders->check = 0x0;
tcpHeaders->urg_ptr = 0x0;

//Sets the data
uint8_t * tcdData = ((uint8_t*) tcpHeaders + MINIMUM_TCP_HEADER_LENGTH);
memcpy(tcdData, message, strlen(message));

//Compute TCP checksum over the pseudo TCP header
uint8_t * pseudo = pseudoBuffer;
memset(pseudo, 0, DEFAULT_BUFFER_SIZE);
memcpy(pseudo, &((ipHeaders->ip_src).s_addr), 4);
pseudo += 4;
memcpy(pseudo, &((ipHeaders->ip_dst).s_addr), 4);
pseudo += 4;
memset(pseudo++, 0, 1);
memset(pseudo++, IPPROTO_TCP, 1);
uint16_t tcpSegmentLength = htons(MINIMUM_TCP_HEADER_LENGTH + (uint32_t) strlen(message));
memcpy(pseudo, &tcpSegmentLength, 2);
pseudo += 2;

//Append the TCP headers and data to the pseudo header
memcpy(pseudo, tcpHeaders, MINIMUM_TCP_HEADER_LENGTH + strlen(attentionMessage));
pseudo += MINIMUM_TCP_HEADER_LENGTH + strlen(attentionMessage);

//Compute checksum
int pseudoBufferLength = pseudo - pseudoBuffer;
tcpHeaders->check = calculateInternetChecksum((uint16_t*) pseudoBuffer, pseudoBufferLength);

//[... Code that proceed to send the packet ...]

It is worth noting that both "packetBuffer" have been filled with zeros using memset (just like "pseudo" is) and that the "message" is a regular string. 值得注意的是,两个“ packetBuffer”都使用memset填充了零(就像“ pseudo”一样),并且“ message”是常规字符串。

Here is the function that computes the checksum: 这是计算校验和的函数:

uint16_t onesComplementAddition(uint16_t *buff, unsigned int nbytes) {
    if(buff == 0 || nbytes == 0)
        return 0;

    uint32_t sum = 0;
    for (; nbytes > 1; nbytes -= 2)
        sum += *buff++;

    if (nbytes == 1)
        sum += *(uint8_t*) buff;

    sum  = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);

    return sum;
}

uint16_t calculateInternetChecksum(uint16_t *buff, unsigned int nbytes) {
    return ~(onesComplementAddition(buff, nbytes));
}

Wireshark suggests that this could be caused by "TCP checksum offload" but I doubt it as I don't receive any response from the machine I probe (even though I know for a fact that I should). Wireshark建议这可能是由于“ TCP校验和卸载”引起的,但我对此表示怀疑,因为我没有从所探测的计算机收到任何响应(即使我知道应该这样做)。

Does anyone have an idea why the TCP checksum is not correct? 有谁知道为什么TCP校验和不正确?

Thanks in advance. 提前致谢。

Sorry guys, it's one of those times when asking the question actually gives me the answer. 抱歉,这是问问题实际上给我答案的那一次。

If I understood the documentation correctly, when using a RAW socket, the kernel will replace the IP source address with the address of the sending interface only if the "source" field is 0 ( http://man7.org/linux/man-pages/man7/raw.7.html#DESCRIPTION ). 如果我正确理解了文档,则在使用RAW套接字时,仅当“源”字段为0时,内核才会将IP源地址替换为发送接口的地址( http://man7.org/linux/man- pages / man7 / raw.7.html#DESCRIPTION )。

As I was using that feature, I computed my checksum over a TCP pseudo header with an IP source that was 0. That could obviously not work. 当我使用该功能时,我通过IP源为0的TCP伪头计算了校验和。这显然不起作用。

Thanks if anyone tried to solve my issue. 如果有人试图解决我的问题,谢谢。

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

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