Расчет контрольной суммы 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 плюс полезная нагрузка, которая следует за ним?)

Благодарю.

3 ответа

Решение

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

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

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

Сумма дополнения не просто сумма всех значений дополнения. Это немного сложнее.

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


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

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


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

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

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

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

Хороший и простой для понимания пример вычисления контрольной суммы UDP сделан Гердом Хоффманном.

Вы можете найти в Google "net-checkum.c Gerd Hoffmann" или посмотреть файл здесь:

https://gist.github.com/fxlv/81209bbd150abfeaceb1f85ff076c9f3

Ты можешь использовать net_checksum_tcpudp функция, передайте ему длину полезной нагрузки UDP, IP-адреса proto, src и dst, а затем саму полезную нагрузку UDP, и все будет работать правильно.

В конце вы должны позвонить htons() на контрольной сумме и ты в порядке.

Я искал в сети некоторый код, который вычислит заголовок udp (с псевдо-заголовком ip, как упомянуто выше).

Наконец я нашел пакет open-bsd dhclient.c:

https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sbin/dhclient/packet.c

проверить функцию assemble_udp_ip_header()

Другие вопросы по тегам