UNIX: разработка сетевых приложений
Шрифт:
8 }
9 out->tv_sec -= in->tv_sec;
10 }
В листинге 28.6 приведена функция
proc_v4
, обрабатывающая все принимаемые сообщения ICMPv4. Можно также обратиться к рис. А.1, на котором изображен формат заголовка IPv4. Кроме того, следует осознавать, что к тому моменту, когда процесс получает на символьном сокете ICMP-сообщение, ядро уже проверило, что основные поля в заголовке IPv4 и в сообщении ICMPv4 действительны [128, с. 214, с. 311]. Листинг 28.6.Функция proc_v4: обработка сообщений ICMPv4
//ping/prov_v4.c
1 #include "ping.h"
2 void
3 proc_v4(char *ptr, ssize_t len, struct msghdr *msg, struct timeval *tvrecv)
4 {
5 int hlen1, icmplen;
6 double rtt;
7 struct ip *ip;
8 struct icmp *icmp;
9 struct timeval *tvsend;
10 ip = (struct ip*)ptr; /*
начало IP-заголовка */
11 hlen1 = ip->ip_hl << 2; /* длина IP-заголовка */
12 if (ip->ip_p != IPPROTO_ICMP)
13 return; /* не ICMP */
14 icmp = (struct icmp*)(ptr + hlen1); /* начало ICMP-заголовка */
15 if ((icmplen = len - hlen1) < 8)
16 return; /* плохой пакет */
17 if (icmp->icmp_type == ICMP_ECHOREPLY) {
18 if (icmp->icmp_id != pid)
19 return; /* это не ответ на наш ECHO_REQUEST */
20 if (icmplen < 16)
21 return; /* недостаточно данных */
22 tvsend = (struct timeval*)icmp->icmp_data;
23 tv_sub(tvrecv, tvsend);
24 rtt = tvrecv->tv_sec * 1000.0 + tvrecv->tv_usec / 1000.0;
25 printf("%d bytes from %s: seq=%u, ttl=%d, rtt=%.3f ms\n",
26 icmplen, Sock_ntop_host(pr->sarecv, pr->salen),
27 icmp->icmp_seq, ip->ip_ttl, rtt);
28 } else if (verbose) {
29 printf(" %d bytes from %s: type = %d, code = %d\n",
30 icmplen, Sock_ntop_host(pr->sarecv, pr->salen),
31 icmp->icmp_type, icmp->icmp_code);
32 }
33 }
Извлечение указателя на ICMP-заголовок
10-16
Значение поля длины заголовка IPv4, умноженное на 4, дает размер заголовка IPv4 в байтах. (Следует помнить, что IPv4-заголовок может содержать параметры.) Это позволяет нам установить указатель icmp так, чтобы он указывал на начало ICMP-заголовка. Мы проверяем, относится ли данный пакет к протоколу ICMP и имеется ли в нем достаточно данных для проверки временной отметки, включенной нами в эхо-запрос. На рис. 28.3 приведены различные заголовки, указатели и длины, используемые в коде. Рис. 28.3. Заголовки, указатели и длина при обработке ответов ICMPv4
Проверка эхо-ответа ICMP
17-21
Если сообщение является эхо-ответом ICMP, то необходимо проверить поле идентификатора, чтобы выяснить, относится ли этот ответ к посланному данным процессом запросу. Если программа ping запущена на одном узле несколько раз, каждый процесс получает копии всех полученных ICMP-сообщений.
22-27
Путем вычитания времени отправки сообщения (содержащегося в части ICMP-ответа, отведенной под дополнительные данные) из текущего времени (на которое указывает аргумент функции tvrecv
) вычисляется значение RTT. Время RTT преобразуется из микросекунд в миллисекунды и выводится на экран вместе с полем порядкового номера и полученным значением TTL. Поле порядкового номера позволяет пользователю проследить, не были ли пакеты пропущены, переупорядочены или дублированы, а значение TTL показывает количество транзитных узлов между двумя узлами. Вывод всех полученных ICMP-сообщений при включении параметра verbose
28-32
Если пользователем указан параметр командной строки – v
, также выводятся поля типа и кода из всех других полученных ICMP-сообщений. Обработка сообщений ICMPv6 управляется функцией
proc_v6
, приведенной в листинге 28.8. Она аналогична функции proc_v4
, представленной в листинге 28.6. Однако поскольку символьные сокеты IPv6 не передают процессу заголовок IPv6, ограничение на количество транзитных узлов приходится получать в виде вспомогательных данных. Для этого нам приходится подготавливать сокет функцией init_v6
, представленной в листинге 28.7. Листинг 28.7. Функция init_v6: подготовка сокета
1 void
2 init_v6
3 {
4 #ifdef IPV6
5 int on = 1;
6 if (verbose == 0) {
7 /* установка фильтра, пропускающего только пакеты ICMP6_ECHO_REPLY. если
не включен параметр verbose (вывод всех ICMP-сообщений) */
8 struct icmp6_filter myfilt;
9 ICMP6_FILTER_SETBLOCKALL(&myfilt);
10 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &myfilt);
11 setsockopt(sockfd, IPPROTO_IPV6, ICMP6_FILTER, &myfilt,
12 sizeof(myfilt));
13 /* игнорируем ошибку, потому что фильтр - необязательная оптимизация */
Поделиться:
Популярные книги
Горькие ягодки
Любовные романы:
современные любовные романы
7.44
рейтинг книги
Сама себе хозяйка
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Черный Маг Императора 6
6. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
7.00
рейтинг книги
Последний Паладин. Том 2
2. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Огни Аль-Тура. Завоеванная
4. Эйнар
Любовные романы:
любовно-фантастические романы
эро литература
5.00
рейтинг книги
Законы Рода. Том 7
7. Граф Берестьев
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Жандарм 2
2. Жандарм
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Измена. Мой заклятый дракон
Любовные романы:
любовно-фантастические романы
7.50
рейтинг книги
Его темная целительница
2. Любовь среди туманов
Фантастика:
фэнтези
5.75
рейтинг книги
Кодекс Охотника. Книга V
5. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
4.50
рейтинг книги
Неудержимый. Книга XVI
16. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Жена по ошибке
Любовные романы:
любовно-фантастические романы
7.71
рейтинг книги
Real-Rpg. Город гоблинов
1. Real-Rpg
Фантастика:
фэнтези
7.81
рейтинг книги
Венецианский купец
1. Венецианский купец
Фантастика:
фэнтези
героическая фантастика
альтернативная история
7.31