8.8. Проверка полученного ответа

8.8. Проверка полученного ответа

В конце раздела 8.6 мы упомянули, что любой процесс, который знает номер динамически назначаемого порта клиента, может отправлять дейтаграммы нашему клиенту, и они будут перемешаны с нормальными ответами сервера. Все, что мы можем сделать, — это изменить вызов функции recvfrom, представленный в листинге 8.4, так, чтобы она возвращала IP-адрес и порт отправителя ответа, и игнорировать любые дейтаграммы, приходящие не от того сервера, которому мы отправляем дейтаграмму. Однако здесь есть несколько ловушек, как мы дальше увидим.

Сначала мы изменяем функцию клиента main (см. листинг 8.3) для работы со стандартным эхо-сервером (см. табл. 2.1). Мы просто заменяем присваивание

servaddr.sin_port = htons(SERV_PORT);

присваиванием

servaddr.sin_port = htons(7);

Теперь мы можем использовать с нашим клиентом любой узел, на котором работает стандартный эхо-сервер.

Затем мы переписываем функцию dg_cli, с тем чтобы она размещала в памяти другую структуру адреса сокета для хранения структуры, возвращаемой функцией recvfrom. Мы показываем ее в листинге 8.5.

Листинг 8.5. Версия функции dg_cli, проверяющая возвращаемый адрес сокета

//udpcliserv/dgcliaddr.c

 1 #include "unp.h"

 2 void

 3 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)

 4 {

 5  int n;

 6  char sendline[MAXLINE], recvline[MAXLINE + 1];

 7  socklen_t len;

 8  struct sockaddr *preply_addr;

 9  preply_addr = Malloc(servlen);

10  while (Fgets(sendline, MAXLINE, fp) != NULL) {

11   Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

12   len = servlen;

13   n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);

14   if (len != servlen || memcmp(pservaddr, preply_addr, len) != 0) {

15    printf("reply from %s (ignored) ",

16    continue;

17   }

18   recvline[n] = 0; /* завершающий нуль */

19   Fputs(recvline, stdout);

20  }

21 }

Размещение другой структуры адреса сокета в памяти

9 Мы размещаем в памяти другую структуру адреса сокета при помощи функции malloc. Обратите внимание, что функция dg_cli все еще является не зависящей от протокола. Поскольку нам не важно, с каким типом структуры адреса сокета мы имеем дело, мы используем в вызове функции malloc только ее размер.

Сравнение возвращаемых адресов

12-13 В вызове функции recvfrom мы сообщаем ядру, что нужно возвратить адрес отправителя дейтаграммы. Сначала мы сравниваем длину, возвращаемую функцией recvfrom в аргументе типа «значение-результат», а затем сравниваем сами структуры адреса сокета при помощи функции memcmp.

Новая версия нашего клиента работает замечательно, если сервер находится на узле с одним единственным IP-адресом. Но эта программа может не сработать, если сервер имеет несколько сетевых интерфейсов (multihomed server). Запускаем эту программу, обращаясь к узлу freebsd4, у которого имеется два интерфейса и два IP-адреса:

macosx % host freebsd4

freebsd4.unpbook.com has address 172.24.37.94

freebsd4.unpbook.com has address 135.197.17.100

macosx % udpcli02 135.197.17.100

hello

reply from 172.24.37.94:7 (ignored)

goodbye

reply from 172.24.37.94:7 (ignored)

По рис. 1.7 видно, что мы задали IP-адрес из другой подсети. Обычно это допустимо. Большинство реализаций IP принимают приходящую IP-дейтаграмму, предназначенную для любого из IP-адресов узла, независимо от интерфейса, на который она приходит [128, с. 217-219]. Документ RFC 1122 [10] называет это моделью системы с гибкой привязкой (weak end system model). Если система должна реализовать то, что в этом документе называется моделью системы с жесткой привязкой (strong end system model), она принимает приходящую дейтаграмму, только если дейтаграмма приходит на тот интерфейс, которому она адресована.

IP-адрес, возвращаемый функцией recvfrom (IP-адрес отправителя дейтаграммы UDP), не является IP-адресом, на который мы посылали дейтаграмму. Когда сервер отправляет свой ответ, IP-адрес получателя — это адрес 172.24.37.94. Функция маршрутизации внутри ядра на узле freebsd4 выбирает адрес 172.24.37.94 в качестве исходящего интерфейса. Поскольку сервер не связал IP-адрес со своим сокетом (сервер связал со своим сокетом универсальный адрес, что мы можем проверить, запустив программу netstat на узле freebsd4), ядро выбирает адрес отправителя дейтаграммы IP. Этим адресом становится первичный IP-адрес исходящего интерфейса [128, с. 232-233]. Если мы отправляем дейтаграмму не на первичный IP-адрес интерфейса (то есть на альтернативное имя, псевдоним), то наша проверка, показанная в листинге 8.5, также окажется неудачной.

Одним из решений будет проверка клиентом доменного имени отвечающего узла вместо его IP-адреса. Для этого имя сервера ищется в DNS (см. главу 11) на основе IP-адреса, возвращаемого функцией recvfrom. Другое решение — сделать так, чтобы сервер UDP создал по одному сокету для каждого IP-адреса, сконфигурированного на узле, связал с помощью функции bind этот IP-адрес с сокетом, вызвал функцию select для каждого из всех этих сокетов (ожидая, когда какой-либо из них станет готов для чтения), а затем ответил с сокета, готового для чтения. Поскольку сокет, используемый для ответа, связан с IP-адресом, который являлся адресом получателя клиентского запроса (иначе дейтаграмма не была бы доставлена на сокет), мы можем быть уверены, что адреса отправителя ответа и получателя запроса совпадают. Мы показываем эти примеры в разделе 22.6.

ПРИМЕЧАНИЕ

В системе Solaris с несколькими сетевыми интерфейсами IP-адрес отправителя ответа сервера — это IP-адрес получателя клиентского запроса. Сценарий, описанный в данном разделе, относится к реализациям, происходящим от Беркли, которые выбирают IP-адрес отправителя, основываясь на исходящем интерфейсе.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

ОПЫТЫ: Половина ответа

Из книги Журнал «Компьютерра» № 6 от 13 февраля 2007 года автора Журнал «Компьютерра»

ОПЫТЫ: Половина ответа Автор: Павел ПротасовДавным-давно, когда так называемое «информационное право» только зарождалось, в ходу был вопрос о том, нужно ли судьям и следователям, ведущим уголовные дела о «компьютерных преступлениях», разбираться в технике. Может


Как время ответа сайта влияет на пользовательскую психологию

Из книги Разгони свой сайт автора Мациевский Николай

Как время ответа сайта влияет на пользовательскую психологию Пользователи ощущают, что сайты, которые загружаются медленно, менее надежны и менее качественны. В случае, если удерживать время загрузки в пределах «терпимого», пользователи будут ощущать гораздо меньше


Время ожидания ответа сервера (Internet Explorer 4.0 SP1 и выше)

Из книги Реестр Windows автора Климов Александр

Время ожидания ответа сервера (Internet Explorer 4.0 SP1 и выше) При работе в интернете иногда приходится обращаться к весьма удаленным или очень медленным сайтам, в связи с чем у Internet Explorer не всегда хватает терпения дождаться ответа от сервера, и он выдает такие сообщения: "Microsoft Internet


Три ответа

Из книги Основы объектно-ориентированного программирования автора Мейер Бертран

Три ответа С недостижимыми объектами можно поступать тремя способами:[x]. Проигнорировать проблему и надеяться, что хватит памяти для размещения всех объектов: достижимых и недостижимых. Это можно назвать несерьезным (casual) подходом.[x]. Предложить разработчикам включать в


12.16.3 Секция ответа

Из книги TCP/IP Архитектура, протоколы, реализация (включая IP версии 6 и IP Security) автора Фейт Сидни М

12.16.3 Секция ответа Сам ответ, информация об авторитетности и дополнительные сведения структурированы так же, как и в запросе. Ответ состоит из последовательности записей о ресурсах, содержащих поля, показанные в таблице 12.4.Таблица 12.4 Поля записей о


Установка заголовков ответа

Из книги Справочник по PHP автора

Установка заголовков ответа HeaderВывод заголовка.Синтаксис:int Header(string $string)Обычно функция Header() является одной из первых команд сценария. Она предназначена для установки заголовков ответа, которые будут переданы браузеру - по одному заголовку на вызов. Вызов Header()


14.4.2. Формирование ответа на вопрос "почему"

Из книги Программирование на языке Пролог для искусственного интеллекта автора Братко Иван

14.4.2. Формирование ответа на вопрос "почему" Вопрос "почему" возникает в ситуации, когда система просит пользователя сообщить ей некоторую информацию, а пользователь желает знать, почему эта информация необходима. Допустим, что система спрашивает:а — это правда?В ответ


14.4.3. Формирование ответа на вопрос "как"

Из книги Деловая e-mail переписка. Пять правил успеха автора Воротынцева Тамара

14.4.3. Формирование ответа на вопрос "как" Получив ответ на свой вопрос, пользователь возможно захочет увидеть, как система пришла к такому заключению. Один из подходящих способов ответить на вопрос "как" — это представить доказательство, т.е. те правила и подцели, которые


Проверка

Из книги Секреты приложений Google автора Балуев Денис

Проверка      Так ли уж правильны наши рассуждения? Давайте проверим нашу функцию на учебной программе:/* проверка функции getint( )*/#define STOP - 1#define NONUM 1#define YESNUM 0main( ){int num, status;printf(" Программа прекращает считывание чисел, если встречает EOF. " );while((status = getint(&num)) != STOP)if(status = =


Уничтожение полученного маршрута от отправителя

Из книги автора

Уничтожение полученного маршрута от отправителя К сожалению, использование параметра маршрутизации образует брешь в системе обеспечения безопасности программ, выполняющих аутентификацию по IP-адресам (сейчас такая проверка считается недостаточной). Если хакер


Проверка

Из книги автора

Проверка Установка цветов в соответствии с правилами может здорово помочь при проверке данных на этапе ввода. Например, аварийным красным будут выделяться значения, явно выходящие за рамки указанного диапазона, или подсвечиваться желтым «подозрительные» слова и цифры.