Шрифт:
36 pid = getpid;
37 Signal(SIGALRM, sig_alrm);
38 ai = Host_serv(host, NULL, 0, 0);
39 printf("traceroute to %s (%s): %d hops max, %d data bytes\n",
40 ai->ai_canonname,
41 Sock_ntop_host(ai->ai_addr, ai->ai_addrlen);
42 max_ttl, datalen);
43 /* инициализация в зависимости от протокола */
44 if (ai->ai_family == AF_INET) {
45 pr = &proto_v4;
46 #ifdef IPV6
47 } else if (ai->ai_family == AF_INET6) {
48 pr = &proto_v6;
49 if (IN6_IS_ADDR_V4MAPPED
50 (&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr)))
51 err_quit("cannot traceroute IPv4-mapped IPv6 address");
52 #endif
53 } else
54 err_quit("unknown address family %d", ai->ai_family);
55 pr->sasend = ai->ai_addr; /* содержит адрес получателя */
56 pr->sarecv = Calloc(1, ai->ai_addrlen);
57 pr->salast = Calloc(1, ai->ai_addrlen);
58 pr->sabind = Calloc(1, ai->ai_addrlen);
59 pr->salen = ai->ai_addrlen;
60 traceloop;
61 exit(0);
62 }
Определение структуры proto
2-9
Определяются две структуры proto
, одна для IPv4 и другая для IPv6, хотя указатели на структуры адреса сокета не размещаются в памяти до окончания выполнения данной функции. Установка значений по умолчанию
10-13
Максимальное значение поля TTL или поля предельного количества транзитных узлов, используемое в программе, по умолчанию равно 30. Предусмотрен параметр командной строки – m
, чтобы пользователь мог поменять это значение. Для каждого значения TTL посылается три пробных пакета, но их количество также может быть изменено с помощью параметра командной строки. Изначально используется номер порта получателя 32 768 + 666, и каждый раз, когда посылается новая дейтаграмма UDP, это значение увеличивается на 1. Мы можем надеяться, что порты с такими номерами не используются на узле получателя в тот момент, когда приходит дейтаграмма, однако гарантии здесь нет. Обработка аргументов командной строки
19-37
Параметр командной строки -v позволяет вывести все остальные ICMP-сообщения. Обработка имени узла или IP-адреса и завершение инициализации
38-58
Имя узла получателя или IP-адрес обрабатывается функцией host_serv
, возвращающей указатель на структуру addrinfo
. В зависимости от типа возвращенного адреса (IPv4 или IPv6) заканчивается инициализация структуры proto
, сохраняется указатель в глобальной переменной pr, а также размещается в памяти дополнительная структура адреса сокета соответствующего размера. Функция
traceloop
, приведенная в листинге 28.15, отправляет дейтаграммы и читает вернувшиеся ICMP-сообщения. Это основной цикл программы. Листинг 28.15. Функция traceloop: основной цикл обработки
//traceroute/traceloop.c
1 #include "trace.h"
2 void
3 traceloop(void)
4 {
5 int seq, code, done;
6 double rtt;
7 struct rec *rec;
8 struct timeval tvrecv;
9 recvfd = Socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto);
10 setuid(getuid); /* права привилегированного пользователя больше
не нужны */