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 нулевое значение контрольной суммы не означает ее отсутствия.