Литмир - Электронная Библиотека
Содержание  
A
A

Листинг 28.12. Функция send_v6: построение и отправка ICMPv6-сообщения эхо-запроса

//ping/send_v6.c

 1 #include "ping.h"

 2 void

 3 send_v6()

 4 {

 5 #ifdef IPV6

 6  int len;

 7  struct icmp6_hdr *icmp6;

 8  icmp6 = (struct icmp6_hdr*)sendbuf,

 9  icmp6->icmp6_type = ICMP6_ECHO_REQUEST;

10  icmp6->icmp6_code = 0;

11  icmp6->icmp6_id = pid;

12  icmp6->icmp6_seq = nsent++;

13  memset((icmp6 + 1), 0xa5, datalen); /* заполнение по шаблону */

14  Gettimeofday((struct timeval*)(icmp6 + 1), NULL);

15  len = 8 + datalen; /* 8-байтовый заголовок ICMPv6 */

16  Sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen);

17  /* ядро вычисляет и сохраняет контрольную сумму само */

18 #endif /* IPV6 */

19 }

28.6. Программа traceroute

В этом разделе мы приведем собственную версию программы

traceroute
. Как и в случае с программой
ping
, приведенной в предыдущем разделе, мы представляем нашу собственную, а не общедоступную версию. Это делается для того, чтобы во-первых, получить версию, поддерживающую как IPv4, так и IPv6, а во-вторых, не отвлекаться на множество параметров, не относящихся к обсуждению сетевого программирования.

Программа

traceroute
позволяет нам проследить путь IP-дейтаграмм от нашего узла до получателя. Ее действие довольно просто, а в главе 8 книги [111] оно детально описано со множеством примеров.

В версии IPv6 программа

traceroute
использует поле TTL (в версии IPv4) или поле предельного количества транзитных узлов (называемое также полем ограничения пересылок), а также два типа ICMP-сообщений. Эта программа начинает свою работу с отправки UDP-дейтаграммы получателю, причем полю TTL (ограничения пересылок) присваивается значение 1. Такая дейтаграмма вынуждает первый маршрутизатор отправить ICMP-сообщение об ошибке «Time exceeded in transit» (Превышено время передачи). Затем значение TTL увеличивается на 1 и посылается следующая UDP-дейтаграмма, которая достигает следующего маршрутизатора. Когда UDP-дейтаграмма достигает конечного получателя, необходимо заставить узел вернуть ICMP-ошибку
Port unreachable
(Порт недоступен). Для этого UDP-дейтаграмма посылается на случайный порт, который (как можно надеяться) не используется на данном узле.

Ранние версии программы

traceroute
могли устанавливать поле TTL в заголовке IPv4 только с помощью параметра сокета
IP_HDRINCL
путем построения своего собственного заголовка. Однако современные системы поддерживают параметр сокета
IP_TTL
, позволяющий определить значение TTL для исходящих дейтаграмм. (Данный параметр сокета впервые был представлен в выпуске 4.3BSD Reno.) Проще установить данный параметр сокета, чем полностью формировать IPv4-заголовок (хотя в разделе 29.7 показано, как строить собственные заголовки IPv4 и UDP). Параметр сокета IPv6
IPV6_UNICAST_HOPS
позволяет контролировать поле предельного количества транзитных узлов (ограничения пересылок) в дейтаграммах IPv6.

В листинге 28.13 приведен заголовочный файл t

race.h
, подключаемый ко всем файлам нашей программы.

Листинг 28.13. Заголовочный файл trace.h

//traceroute/trace.h

 1 #include "unp.h"

 2 #include <netinet/in_systm.h>

 3 #include <netinet/ip.h>

 4 #include <netinet/ip_icmp.h>

 5 #include <netinet/udp.h>

 6 #define BUFSIZE 1500

 7 struct rec { /* структура данных UDP */

 8  u_short rec_seq; /* порядковый номер */

 9  u_short rec_ttl; /* значение TTL, с которым пакет отправляется */

10  struct timeval rec_tv; /* время отправки пакета */

11 };

12 /* глобальные переменные */

13 char recvbuf[BUFSIZE];

14 char sendbuf[BUFSIZE];

15 int datalen; /* размер данных в байтах после заголовка ICMP */

16 char *host;

17 u_short sport, dport;

18 int nsent; /* добавляет 1 для каждого вызова sendto() */

19 pid_t pid; /* идентификатор нашего процесса PID */

20 int probe, nprobes;

21 int sendfd, recvfd; /* посылает на сокет UDP. читает на

                          символьном сокете ICMP */

22 int ttl, max_ttl;

23 int verbose;

24 /* прототипы функций */

25 char *icmpcode_v4(int);

26 char *icmpcode_v6(int);

27 int recv_v4(int. struct timeval*);

28 int recv_v6(int. struct timeval*);

29 void sig_alrm(int);

30 void traceloop(void);

31 void tv_sub(struct timeval*, struct timeval*);

32 struct proto {

33  char *(*icmpcode)(int);

34  int (*recv)(int. struct timeval*);

35  struct sockaddr *sasend; /* структура sockaddr{} для отправки.

                                получена из getaddrinfo */

315
{"b":"225366","o":1}