Вычисление контрольной суммы UDP

Структура заголовка UDP, определенная в/usr/include/netinet/udp.h, следующие

struct udphdr
{
  u_int16_t source;
  u_int16_t dest;
  u_int16_t len;
  u_int16_t check;
};

Какое значение хранится в поле проверки заголовка? Как проверить, корректна ли контрольная сумма? Я имел в виду, на каких данных вычисляется контрольная сумма? (Это - просто udp заголовок или udp заголовок плюс полезная нагрузка, которая следует за ним?)

Спасибо.

21
задан red0ct 27 November 2019 в 15:43
поделиться

1 ответ

Контрольная сумма UDP выполняется для всей полезной нагрузки, и других полей в заголовке, и некоторых полей из заголовка IP. Псевдозаголовок создается из заголовка IP для выполнения вычислений (которые выполняются над этим псевдозаголовком, заголовком UDP и полезной нагрузкой). Причина, по которой включен псевдозаголовок, состоит в том, чтобы перехватить пакеты, которые были маршрутизированы на неправильный IP-адрес.

Обычно на принимающей стороне все 16-битные слова заголовков плюс область данных складываются вместе (упаковка на 16 бит), и результат проверяется по 0xffff .

На отправляющей стороне все немного сложнее. Сумма дополнения до единицы выполняется для всех 16-битных значений, затем дополнение до единицы (т. Е. инвертировать все биты) из этого значения берется для заполнения поля контрольной суммы (с дополнительным условием, что вычисленная контрольная сумма нуля будет заменена на все единичные биты).

Сумма дополнения до единицы равна , а не просто сумма всех дополнительных ценностей. Это немного сложнее.

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


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

Если бы не было переноса, ADC просто добавлял бы нулевой бит из переноса. В те дни, когда это было сделано (и да, к сожалению, я такой старый), память была гораздо большим ограничением, чем скорость, что не так актуально в наши дни, поэтому экономия нескольких байтов в вашем код мог бы поднять вас до уровня полубога-императора-вселенной: -)


Обратите внимание, что вам никогда не приходилось беспокоиться о переносе во второй раз (или о переносе двух с последующим ] ADC , если вы используете метод, упомянутый в предыдущем абзаце), поскольку два самых больших 16-битных значения при суммировании дают (усечено из 0x1fffe ) 0xfffe - добавление одного к этому никогда не вызовет другого переноса.

После того, как вычисленная сумма дополнений до одного вычислена, ее биты инвертированы и вставлены в пакет, это приведет к тому, что вычисление на принимающей стороне приведет к 0xffff , конечно, при отсутствии ошибок при передаче.

Стоит отметить, что полезная нагрузка всегда дополняется, чтобы гарантировать наличие целого числа 16-битных слов. Если он был дополнен , в поле длины будет указана фактическая длина.

RFC768 - это спецификация, в которой это подробно описано.

s целое число 16-битных слов. Если он был дополнен , в поле длины будет указана фактическая длина.

RFC768 - это спецификация, в которой это подробно описано.

s целое число 16-битных слов. Если он был дополнен , в поле длины будет указана фактическая длина.

RFC768 - это спецификация, в которой это подробно описано.

36
ответ дан 29 November 2019 в 20:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: