2017-01-04 10 views
1

CのRAWソケットを介してTCP SYNパケットを送信しようとしています(これは最も簡単なことではありませんが、Cでパケットを送信しようとしたときにTCPチェックサムが正しくない

発信パケットをチェックすると、すべてのフィールドは良好ですが、1つはTCPチェックサムです。確かに、Wiresharkはそれが間違っていると私に伝えます。 次のコードでは、パケットをどのように構築するかを見ることができます(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 ...] 

これは「packetBuffer」の両方がのmemsetを使用してゼロで埋め(単に「疑似」等である)と 「メッセージ」は、通常の文字列であるとされていることは注目に値します。ここで

は、チェックサムを計算する関数です:

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のは、これは、「TCPチェックサムオフロード」によって引き起こされることを示唆しているが、私は、私はマシンからの応答を受信しないよう 私はそれを疑いますプローブ(私が私がすべきことを知っていても)。

TCPチェックサムが正しくない理由を知っている人はいますか?

ありがとうございます。

答えて

3

ご迷惑をおかけして申し訳ございませんが、実際に私に質問をするとその時代の1つです。

RAWソケットを使用する場合、「ソース」フィールドが0(http://man7.org/linux/man-pages/man7/raw.7.html#DESCRIPTION)の場合にのみ、カーネルはIPソースアドレスを送信インターフェイスのアドレスに置き換えます。

私はこの機能を使用していたので、IPソースが0のTCP擬似ヘッダーでチェックサムを計算しました。これは明らかに機能しませんでした。

誰かが私の問題を解決しようとしてくれてありがとう。

関連する問題