UNIX: разработка сетевых приложений
Часть 315 из 399 Информация о книге
Листинг 28.12. Функция send_v6: построение и отправка ICMPv6-сообщения эхо-запроса
//ping/send_v6.c1 #include "ping.h"2 void3 send_v6()4 {5 #ifdef IPV66 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, приведенной в предыдущем разделе, мы представляем нашу собственную, а не общедоступную версию. Это делается для того, чтобы во-первых, получить версию, поддерживающую как IPv4, так и IPv6, а во-вторых, не отвлекаться на множество параметров, не относящихся к обсуждению сетевого программирования.pingПрограмма
позволяет нам проследить путь IP-дейтаграмм от нашего узла до получателя. Ее действие довольно просто, а в главе 8 книги [111] оно детально описано со множеством примеров.tracerouteВ версии IPv6 программа
использует поле TTL (в версии IPv4) или поле предельного количества транзитных узлов (называемое также полем ограничения пересылок), а также два типа ICMP-сообщений. Эта программа начинает свою работу с отправки UDP-дейтаграммы получателю, причем полю TTL (ограничения пересылок) присваивается значение 1. Такая дейтаграмма вынуждает первый маршрутизатор отправить ICMP-сообщение об ошибке «Time exceeded in transit» (Превышено время передачи). Затем значение TTL увеличивается на 1 и посылается следующая UDP-дейтаграмма, которая достигает следующего маршрутизатора. Когда UDP-дейтаграмма достигает конечного получателя, необходимо заставить узел вернуть ICMP-ошибкуtraceroute(Порт недоступен). Для этого UDP-дейтаграмма посылается на случайный порт, который (как можно надеяться) не используется на данном узле.Port unreachableРанние версии программы
могли устанавливать поле TTL в заголовке IPv4 только с помощью параметра сокетаtracerouteпутем построения своего собственного заголовка. Однако современные системы поддерживают параметр сокетаIP_HDRINCL, позволяющий определить значение TTL для исходящих дейтаграмм. (Данный параметр сокета впервые был представлен в выпуске 4.3BSD Reno.) Проще установить данный параметр сокета, чем полностью формировать IPv4-заголовок (хотя в разделе 29.7 показано, как строить собственные заголовки IPv4 и UDP). Параметр сокета IPv6IP_TTLпозволяет контролировать поле предельного количества транзитных узлов (ограничения пересылок) в дейтаграммах IPv6.IPV6_UNICAST_HOPSВ листинге 28.13 приведен заголовочный файл t
, подключаемый ко всем файлам нашей программы.race.hЛистинг 28.13. Заголовочный файл trace.h
//traceroute/trace.h1 #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 15007 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 */