Расчёт чек-суммы TCP

Несколько дней пытаюсь найти в чем проблема и видимо глаз замылился. Пытаюсь рассчитать чек-сумму TCP, никак не модифицируя пакет (очевидно должно получиться то же значение как и изначально).

  1. Сначала формирую псевдо-заголовок, его код ниже.
struct TransportIpv4PseudoHeader
{       
    UByte data[12];

    TransportIpv4PseudoHeader(UInt src, UInt dst, UByte protocol, UShort length);


    std::pair<const UByte*, const UByte*> get_by_bytes() const;

};

TransportIpv4PseudoHeader::TransportIpv4PseudoHeader(UInt src, UInt dst, UByte protocol, UShort length)
{
    constexpr auto addr_size = sizeof(src);
    constexpr auto proto_size = sizeof(protocol);
    constexpr auto length_size = sizeof(length);
    
    std::memcpy(data, &src, addr_size); // src ip
    std::memcpy(data + addr_size, &dst, addr_size); // dst ip
    data[8] = 0; // reserverd
    data[9] = protocol; // protocol
    std::memcpy(&data[10], &length, length_size); // Tcp length
    
}

std::pair<const UByte*, const UByte*> TransportIpv4PseudoHeader::get_by_bytes() const
{
    return std::make_pair<>(std::begin(data), std::end(data));
}


decltype(auto) PacketView::get_pseudo_header()
{
    UShort length = get_ip_total_length() - (get_ip_header_length() * 4);
    auto [b, e] = get_data();
    auto pseudo = TransportIpv4PseudoHeader(get_ip_source(), get_ip_dest(), get_ip_protocol(), length);
    return pseudo;
}
  1. Далее собственно считаю саму TCP - чексумму, и вот тут как раз закавыка, алгоритм вроде правильный, а результат нет.

class TcpPacketView
{
    // ...
    
    void set_tcp_checksum(UShort checksum);
    void recalculate_transport_checksum(const TransportIpv4PseudoHeader& pseudo_header, const UByte* begin, const UByte* end);
    std::pair<const UByte*, const UByte*> get_data();
    // ...

};

void TcpPacketView::recalculate_transport_checksum(const TransportIpv4PseudoHeader& pseudo_header, const UByte* begin, const UByte* end)
{
    unsigned int sum = 0;
    UShort res = 0;
    auto [b, e] = pseudo_header.get_by_bytes();

    
    set_tcp_checksum(0);
    // pseudo-header checksum
    for (auto i = b; i < e; i+=2)
    {
        UShort temp = static_cast<UShort>(*i << 8 | *(i + 1));
        sum += temp;
    }


    // tcp header checksum
    for (int i = 0; i < tcp_header_size; i+=2) {
        UShort temp = static_cast<UShort>(header_[i] << 8 | header_[i + 1]);
        sum += temp;
    }


    // tcp header options checksum
    for (int i = 0; i < tcp_options_size; i+=2) {
        UShort temp = static_cast<UShort>(options_[i] << 8 | options_[i + 1]);
        sum += temp;
    }

    auto data_size = std::distance(begin, end);
    // data checksum
    for (auto i = begin; i < end; i++) {
        UShort temp;
        if (i + 1 < end)
        {
            temp = *i << 8 | *(i + 1);
            i++;
        }
        else
        {
            temp = *i << 8;
        }
        sum += temp;
    }

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

    }
        
    res = static_cast<UShort>(sum);
    res = ~res;
    set_tcp_checksum(res);
}


Ответы (1 шт):

Автор решения: mazik7512

Проблема оказалась в порядке байт.

Благодарность @Pavel Mayorov за помощь в решении проблемы.

В конструкторе класса TransportIpv4PseudoHeader функция memcpy копировала байты в обратном порядке (что вообщем-то немудрено, т.к. архитектура little-endian). Ниже приведу код верного копирования (для little-endian машин).

TransportIpv4PseudoHeader::TransportIpv4PseudoHeader(UInt src, UInt dst, UByte protocol, UShort length)
{
    // src
    data[3] = src & 0xFF;
    data[2] = src >> 8 & 0xFF;
    data[1] = src >> 16 & 0xFF;
    data[0] = src >> 24 & 0xFF;

    //dst
    data[7] = dst & 0xFF;
    data[6] = dst >> 8 & 0xFF;
    data[5] = dst >> 16 & 0xFF;
    data[4] = dst >> 24 & 0xFF;

    //zero
    data[8] = 0;

    // proto
    data[9] = protocol;

    //length
    data[11] = length & 0xFF;
    data[10] = length >> 8 & 0xFF;
    
}

→ Ссылка