29 ui-ui_len = htons((uint16_t)(sizeof(struct udphdr) + userlen));
30 /* добавление 28 к длине IP-дейтаграммы */
31 userlen += sizeof(struct udpiphdr);
32 ui-ui_pr = IPPROTO_UDP;
33 ui-ui_src.s_addr = ((struct sockaddr_in*)local)-sin_addr.s_addr;
34 ui-ui_dst.s_addr = ((struct sockaddr_in*)dest)-sin_addr.s_addr;
35 ui-ui_sport = ((struct sockaddr_in*)local)-sin_port;
36 ui-ui_dport = ((struct sockaddr_in*)dest)-sin_port;
37 ui-ui_ulen = ui-ui_len;
38 if (zerosum == 0) {
39 #if 1 /* заменить на if 0 для Solaris 2.x. x 6 */
40 if ((ui-ui_sum = m_cksum((u_int16_t*)in, userlen)) == 0)
41 ui-ui_sum = 0xffff;
42 #else
43 ui-ui_sum = ui-ui_len;
44 #endif
45 }
46 /* заполнение оставшейся части IP-заголовка */
47 /* функция p_output вычисляет и сохраняет контрольную сумму IP */
48 ip-ip_v = IPVERSION;
49 ip-ip_hl = sizeof(struct ip) 2;
50 ip-ip_tos = 0;
51 #if defined(linux) || defined(__OpenBSD__)
52 ip-ip_len = htons(userlen); /* сетевой порядок байтов */
53 #else
54 ip-ip_len = userlen; /* порядок байтов узла */
55 #endif
56 ip-ip_id = 0; /* это пусть устанавливает уровень IP */
57 ip-ip_off = 0; /* смещение флагов, флаги MF и DF */
58 ip-ip_ttl = TTL_OUT;
59 Sendto(rawfd, buf, userlen, 0, dest, destlen);
60 }
24-26
Указатель
ip
указывает на начало заголовка IP (структуру
ip
), а указатель
ui
указывает на то же место, но структура
udpiphdr
является объединением заголовков IP и UDP.
27
Мы явным образом записываем в заголовок нули, чтобы предотвратить учет случайного мусора, который мог остаться в буфере, при вычислении контрольной суммы.
28-31
Переменная
ui_len
— это длина дейтаграммы UDP: количество байтов пользовательских данных плюс размер заголовка UDP (8 байт). Переменная
userlen
(количество байтов пользовательских данных, которые следуют за заголовком UDP) увеличивается на 28 (20 байт на заголовок IP и 8 байт на заголовок UDP), для того чтобы соответствовать настоящему размеру дейтаграммы IP.
32-45
При вычислении контрольной суммы UDP учитывается не только заголовок и данные UDP, но и поля заголовка IP. Эти дополнительные поля заголовка IP образуют то, что называется
ui_sum
, если не установлен флаг
zerosum
(что соответствует наличию аргумента командной строки -0).
Если при вычислении контрольной суммы получается 0, вместо него записывается значение
0xffff
. В обратном коде эти числа совпадают, но протокол UDP устанавливает контрольную сумму в нуль, чтобы обозначить, что она вовсе не была вычислена. Обратите внимание, что в листинге 28.10 мы не проверяем, равно ли значение контрольной суммы нулю: дело в том, что в случае ICMPv4 нулевое значение контрольной суммы не означает ее отсутствия.