2017-01-04 3 views
1

Я пытаюсь отправить пакет TCP SYN через сокет RAW в C (я знаю, что это не самая простая вещь, но у меня есть академические причины для этого).Контрольная сумма TCP неверна при попытке отправить пакет в C

Когда я проверяю исходящий пакет, все поля хороши, но одно: контрольная сумма TCP. Действительно, Вирешарк говорит мне, что это неверно. В следующем коде вы можете увидеть, как я создаю пакет (заголовки 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 контрольной разгрузкой», но я сомневаюсь в этом, как я не получаю никакого ответа от машины I зонд (хотя я знаю, что я должен).

У кого-нибудь есть идея, почему контрольная сумма TCP неверна?

Заранее спасибо.

ответ

3

Извините, ребята, это одно из тех случаев, когда я задаю вопрос, на самом деле дает мне ответ.

Если я правильно понял документацию, при использовании гнезда RAW ядро ​​заменит адрес источника IP адресом передающего интерфейса, только если поле «источник» равно 0 (http://man7.org/linux/man-pages/man7/raw.7.html#DESCRIPTION).

Как я использовал эту функцию, я вычислил свою контрольную сумму через псевдо-заголовок TCP с источником IP, который был 0. Это, очевидно, не работает.

Спасибо, если кто-то попытался решить мою проблему.

Смежные вопросы