Расчёт чек-суммы TCP
Несколько дней пытаюсь найти в чем проблема и видимо глаз замылился. Пытаюсь рассчитать чек-сумму TCP, никак не модифицируя пакет (очевидно должно получиться то же значение как и изначально).
- Сначала формирую псевдо-заголовок, его код ниже.
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;
}
- Далее собственно считаю саму 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;
}