2010-10-25 2 views
1

Я вычисления контрольной суммы UDP, используя следующую функцию (нашел его где-нибудь):UDP ошибка контрольной суммы с ++

uint16_t udp_checksum(const void *buff, size_t len, in_addr_t src_addr, in_addr_t dest_addr) 
    { 
      const uint16_t *buf=(const uint16_t *)buff; 
      uint16_t *ip_src=(uint16_t *)&src_addr, 
         *ip_dst=(uint16_t *)&dest_addr; 
      uint32_t sum; 
      size_t length=len; 


     // Calculate the sum          
     sum = 0; 
     while (len > 1) 
     { 
       sum += *buf++; 
       if (sum & 0x80000000) 
         sum = (sum & 0xFFFF) + (sum >> 16); 
       len -= 2; 
     } 

     if (len & 1) 
       // Add the padding if the packet length is odd   
       sum += *((uint8_t *)buf); 

     // Add the pseudo-header          
     sum += *(ip_src++); 
     sum += *ip_src; 

     sum += *(ip_dst++); 
     sum += *ip_dst; 

     sum += htons(IPROTO_UDP); 
     sum += htons(length); 

    // Add the carries            
     while (sum >> 16) 
       sum = (sum & 0xFFFF) + (sum >> 16); 

     // Return the one's complement of sum       
     return ((uint16_t)(~sum) ); 
} 



    int form_checksums(char * buff) 
    { 
     // Get IP and UDP headers 
     IP_Header* ipHdr = (IP_Header*)(buff); 
     struct UDP_Header* udpHdr = (struct UDP_Header*) (buff + 4*ipHdr->ihl); 

     //---- Form and fill IP checksum now-------------------------------------- 
     ipHdr->check = 0; 
     ipHdr->check = in_cksum((unsigned short *)ipHdr, sizeof(*ipHdr)); 


     //---- calculate and fill udp checksum now --- 
     udpHdr->checksum = 0; 

     udpHdr->checksum = udp_checksum(buff + 4*ipHdr->ihl, udpHdr->length, ipHdr->saddr, ipHdr->daddr); 

     return 0; 
    } 

Wireshark показывает, что неправильно UDP контрольная сумма вычисляется. Я не вижу никаких проблем в функции. Что может быть не так?

+0

Я пытаюсь найти ошибку в этой функции. Благодарю. – SkypeMeSM

ответ

3

Для вычисления контрольной суммы UDP требуется UDP псевдо-заголовок.

Вот некоторые примеры кода из моей библиотеки, которые могут помочь:

// SmartBuffer is a stream-like buffer class 
uint16_t SmartBuffer::checksum(const void* buf, size_t buflen) 
{ 
    assert(buf); 

    uint32_t r = 0; 
    size_t len = buflen; 

    const uint16_t* d = reinterpret_cast<const uint16_t*>(buf); 

    while (len > 1) 
    { 
     r += *d++; 
     len -= sizeof(uint16_t); 
    } 

    if (len) 
    { 
     r += *reinterpret_cast<const uint8_t*>(d); 
    } 

    while (r >> 16) 
    { 
     r = (r & 0xffff) + (r >> 16); 
    } 

    return static_cast<uint16_t>(~r); 
} 

UDPFrame Контрольная сумма вычислений:

uint16_t UDPFrame::computeChecksum(const ipv4_header& ih) const 
{ 
    udp_pseudo_header uph; 

    memset(&uph, 0x00, sizeof(uph)); 

    uph.source = ih.source; 
    uph.destination = ih.destination; 
    uph.mbz = 0x00; 
    uph.type = ih.protocol; 
    uph.length = getData()->length; 

    systools::SmartBuffer tmp(sizeof(uph) + d_data.size()); 

    tmp.appendValue(uph); 
    tmp.append(d_data); // d_data is the UDP frame payload 

    return tmp.checksum(); 
} 

Во всяком случае, иметь в виду, что обычно Wireshark предупреждает, что неправильное значение контрольная сумма может быть вычислена из-за UDP checksum offload.

Возможно, ваша функция контрольной суммы действительно неверна, но надежный способ убедиться в том, что вы пытаетесь получить ваши UDP-кадры.

+0

спасибо. Я надеюсь узнать, что не так в функции, которую я уже использую. – SkypeMeSM

+0

@SkypeMeSM: Понимание - это хорошо, но функции контрольной суммы трудно понять. Они разработаны в основном математиками. Если вы застряли слишком долго, просто попробуйте использовать мою функцию в ее нынешнем виде. Он умеет работать. ;) – ereOn

+0

Привет, не могли бы вы обновить свой ответ с более полной реализацией 'SmartBuffer' и' udp_pseudo_header'? – Meysam

1

Контрольная сумма UDP обычно рассчитывается с использованием UDP pseudo header. Это включает идентификатор протокола (17) уже в сетевом порядке. Я думаю, вы должны заменить sum = htons(17) на sum += 17.

+0

Я изменил его на более стандартный htons (IPPROTO_UDP). Нам нужно htons, потому что мы хотим добавить протокол в порядок байтов. Но в функции есть что-то еще неправильное. Я не могу его найти. – SkypeMeSM

+1

Вы должны использовать подход псевдо-заголовка UDP или правильную _endianess_, когда вы добавляете отдельные элементы из псевдо-заголовка. Идентификатор протокола IPPROTO_UDP должен * не * обрабатываться с помощью htons(). – harper

0

В моем случае это плохо работало, потому что я неправильно заполнял аргументы источника и адресата назначения (проблемы endianess), но функция работает хорошо, как опубликовано в этом вопросе. Вы должны установить контрольную сумму в 0xFFFF, если функция возвращает ноль.