ИП_Л_4 Лекция № 4. Система имен доменов 1. Концепция

advertisement
ИП_Л_4
Лекция № 4. Система имен доменов
1.
Концепция сервера DNS
2.
Преобразователь адресов
1. Концепция сервера DNS.
Преобразование имен в IP-адреса
Идеальная картина работы преобразователя адресов значительно отличается от реального положения вещей. На самом деле, программа-клиент
(преобразователь) связывается с сервером имен из своей зоны. Сервер рассматривает запрос, чтобы выяснить, в каком домене находится указанное там
имя и кто его обслуживает. Если указанный домен входит в зону ответственности этого сервера, сервер преобразует имя в IP-адрес, пользуясь собственными таблицами, а затем отправляет ответ клиенту.
Если сервер не в состоянии обслужить запрос, то есть домен находится
вне его зоны, дальнейшее его поведение зависит от типа запроса клиента.
Преобразователь устанавливает один из двух типов запросов. Сперва он просит сервер произвести полное преобразование. В официальной терминологии
этот тип запроса называется «рекурсивное выполнение» (recursive resolution).
Если клиент запрашивает рекурсивное выполнение и сервер не в состоянии
выполнить преобразование, он должен обратиться к тому серверу, который
сможет выполнить запрос, а затем возвращает ответ клиенту.
Второй тип запроса — выполнение методом итераций (iterative resolution). Запрос на выполнение методом итераций просит сервер либо выполнить преобразование, либо, в случае неудачи, указать клиенту следующий
сервер, к которому можно обратиться. Когда сервер получает запрос на выполнение методом итераций, он либо успешно преобразует имя в IP-адрес,
либо его ответ содержит адрес следующего сервера, который, возможно,
имеет больше информации. При этом, как видим, наш сервер не делает полного преобразования для клиента.
Взаимодействие между серверами DNS
Серверу DNS не обязательно знать имена или IP-адреса остальных серверов в Интернет. Достаточно располагать информацией о корневых серверах. Файлы конфигурации каждого первичного сервера содержат IP-адреса
корневых серверов. Корневые серверы должны знать имена и IP-адреса каждого сервера DNS второго уровня. В табл. 9.2 приведен список корневых серверов DNS по состоянию на май 1994 г.
2. Преобразователь адресов
Как устроен преобразователь адресов?
Специальное программное обеспечение, работающее на стороне клиента в составе DNS, называется «преобразователь» (resolver) или «преобразователь имен». Windows API обеспечивает выполнение двух функций преобразователя: gethostbyaddr и gethostbyname. Обе функции получают информацию
о сетевом компьютере. Прикладные программы пользуются этими функциями, чтобы преобразовать IP-адрес или имя компьютера. В обоих случаях
функции связываются с серверами DNS для выполнения этого преобразования. Другими словами, программа вызывает эти функции, чтобы преобразо1
ИП_Л_4
вать IP-адрес в имя или наоборот. Функция, в свою очередь, открывает коммуникационный канал и посылает запрос к серверу имен доменов. Получив
необходимую информацию, она закрывает канал и возвращает полученное
значение вызывавшей прикладной программе.
Рассмотрим следующую небольшую программу, QLookup (Quick
Lookup). Она демонстрирует основные шаги, которые нужно предпринять
для обращения к серверу имен доменов. Из программы выброшено все, не
относящееся к делу. Оставлены только детали, необходимые для работы с
функциями gethostbyaddr и gethostbyname. Жестко заданные значения переменных и панели сообщений освобождают нас от необходимости программировать пользовательский интерфейс Windows. Исходный текст программы, QLOOKUP.CPP, находится на приложенной к книге дискете. Программа
подробно обсуждается в этом разделе, и здесь же приведен ее исходный
текст:
2
ИП_Л_4
Пишем программу Quick Lookup
Оператор в первой строчке листинга включает файл заголовков функций интерфейса Windows Sockets — WINSOCK.DLL.
#include "..\winsock.h"
Вы знаете, что файл winsock.h необходимо включать в каждую программу, использующую интерфейс программирования Windows Sockets. В
нем заданы константы и определены прототипы функций для всего Winsock
API.
Операторы include в программах-примерах предполагают, что они будут компилироваться из тех каталогов, в которых были установлены изначально. То есть копируя программы оттуда в другое место, не забывайте со3
ИП_Л_4
ответственно менять операторы include. В противном случае компилятор выдаст сообщение о том, что он не может найти файл заголовков winsock.h.
В большинстве Windows-программ необходимо указывать файл заголовков windows.h. Где-то в начале файла winsock.h можно найти следующее
выражение:
#ifndef _INC_WINDOWS #include <windows.h> #endif
Выражение означает, что файл заголовков windows.h будет включен
автоматически, если вы не сделали этого раньше. В файле windows.h находится выражение, предотвращающее его повторное включение в программу:
#ifndef _INC_WINDOWS
#define _INC_WINDOWS // Если файл windows.h включен, это
// выражение определено
Значения констант
Сразу после оператора, включающего winsock.h, следуют пять операторов, задающих значения необходимых для работы констант:
#define PROG_NAME "Simple DNS Lookup"
#define HOST_NAME "CERFNET.COM" // Любое (настоящее) имя
// компьютера
#define WINSOCK_VERSION 0x0101
// Необходим Winsock
// версии 1.1
#define PF_INET_LENGTH 4 // Длина адреса
// в протоколах Интернет
// всегда равна 4 байтам
#define HOST_ADDR "129.79.26.27" // winftp.cica.indiana.edu
WINSOCK_VERSION обозначает версию интерфейса Winsock (1.1).
Константа AF_INET_LENGTH определяет длину (в байтах) адреса, указываемого в вызове функции gethostbyaddr. Эти константы используются во всех
программах-примерах, приведенных в этой книге.
Константа PROG_NAME определяет название (краткое описание) программы, которое можно использовать в дальнейшем. Если вы решите сменить имя программы, просто замените значение этой константы на другое.
HOST_NAME и HOST_ADDR задают имя и адрес сетевого компьютера
в Интернет. В их качестве можно использовать имя и адрес любого реально
существующего сетевого компьютера.
Значения переменных
Следующие несколько строк листинга Q Lookup начинают определение
функции WinMain (она нужна для всех программ под Windows) и определяют три локальные переменные: dwIPAddr, wsaData и lpHostEnt.
int main( )
{
WSADATA wsaData; // Сведения о реализации
// Winsock
LPHOSTENT lpHostEnt; // Структура с информацией
// о сетевом компьютере
DWORD dwIPAddr;
// IP-адрес в виде
// "беззнаковое целое двойной
// длины"
LPSTR szIPAddr;
// IP-адрес в виде "десятичное
// с точкой"
IP-адрес, как известно из третьей главы, 32-битная величина. Перемен4
ИП_Л_4
ная dwIPAddr типа unsigned long (беззнаковое целое двойной длины) служит
для хранения двоичного представления IP-адреса. Тип WSADATA определяет структуру данных, содержащую версию, описание, статус и информацию
сокета о Winsock DLL. В нашей программе переменная wsaData сохраняет
информацию о реализации Windows Sockets. Функции gethostbyaddr и
gethostbyname требуются для доступа к службе DNS. Обе функции возвращают информацию о сетевом компьютере. Windows Sockets хранит эту информацию в специальной структуре данных, называемой host-entry. Тип данных PHOSTENT определяет переменную-указатель на эту структуру. Содержимое структуры описано в файле winsock.h:
struct hostent
{
char FAR * h_name;
char FAR * FAR * h_aliases;
short h__addrtype;
short h_length;
char FAR * FAR * h_addr_list;
#define h_addr h_addr_list[0]
};
В табл. 9.3 описано назначение каждого элемента структуры.
Таблица 9.3. Элементы структуры данных host-entry Windows Sockets
Элемент
h_name
h aliases
h_addrtype
h_length
h_addr_list
Назначение
Официальное имя хоста.
Массив псевдонимов данного хоста, заканчивающийся нулем.
Тип возвращенного функцией адреса; в случае Windows Sockets он всегда равен AF_INET.
Длина адреса в байтах. Для типа AF_INET длина всегда 4 байта. В
наших примерах для обозначения длины используется константа
AF_INET_LENGTH.
Список (массив) адресов хоста. Он заканчивается нулем, и в случае
Windows Sockets порядок следования байтов сетевой.
Переменная lpHostEnt имеет тип LPHOSTENT. Она нужна программе
QLookup, чтобы размещать информацию о сетевом компьютере, возвращаемую функциями gethostbyname и gethostbyaddr.
Инициализация Winsock DLL
До того как выполнить какую-либо функцию, входящую в состав Windows Sockets API, необходимо вызвать функцию WSAStartup. Следующие
несколько строчек программы QLookup инициализируют Windows Sockets
DLL, вызывая WSAStartup. Далее, QLookup проверяет результат выполнения
этой функции. (WSAStartup возвращает ноль, если все в порядке, и код
ошибки в случае неуспеха.) Для выдачи результата на монитор используется
стандартная функция MessageBox:
if (WSAStartup(WINSOCK_VERSION, &wsaData))
MessageBox(NULL, "Could not load Windows Sockets DLL.",
PROG_NAME, MB_OK|MB_ICONSTOP);
else {
// Программа продолжается
}
5
ИП_Л_4
WSACleanup();
// Программа освобождает занятые ресурсы и
// завершается
return(NULL);
QLookup прекратит выполнение, если WSAStartup вернет код ошибки.
Функция WSACleanup стирает информацию о регистрации программы в
Winsock DLL. Перед тем как закончить выполнение, программа всегда должна выполнять эту функцию. Она освобождает занятые программой системные ресурсы. Qlookup всегда возвращает NULL в качестве результата своей
работы.
Получение информации о компьютере по его имени
Интерфейс Winsock Sockets содержит семь функций для работы с базами данных, позволяющих получить информацию о сетевых компьютерах,
протоколах и коммуникационных службах. Функция gethostbyname, например, возвращает информацию о компьютере по его имени. Приведенный ниже оператор демонстрирует прототип функции gethostbyname:
struct hostent FAR * PASCAL FAR gethostbyname
(const char FAR * name);
Чтобы воспользоваться функцией, ей необходимо передать единственный параметр — указатель на имя компьютера, например cerfnet.com. Функцию можно вызвать так:
lpHostEnt = gethostbyname(HOST_NAME);
В данном случае именем компьютера служит константа HOST_NAME,
равная cerfnet.com. Функция gethostbyname, в свою очередь, выполняет запрос на определение адреса и возвращает указатель на структуру PHOSTENT
в переменной lpHostEnt.
Подробнее о функции gethostbyname
Переменная-результат выполнения gethostbyname указывает на структуру типа host-entry, специально отведенную для программы. В Windows
Socket существует только одна такая структура, поэтому данные не могут
храниться в ней постоянно. Реализация Windows Sockets гарантирует их сохранность только до следующего вызова функций из Windows Sockets API.
Другими словами, спецификация Windows Sockets позволяет разработчикам использовать область данных повторно при следующих вызовах функций Windows Sockets. Для того чтобы сохранить полученные данные, необходимо скопировать нужную информацию из структуры в собственные переменные программы, до того, как вызвана какая-либо другая функция.
Следующие операторы демонстрируют, как QLookup проверяет результат вызова gethostbyname и выдает его на монитор:
lpHostEnt = gethostbyname(HOST_NAME);
if (!lpHostEnt)
MessageBox(NULL, "Could not get IP address!", HOST_NAME,
MB_OK|MB_ICONSTOP);
else // IP-адрес преобразуется в "десятичное с точкой"
{
szIPAddr = inet_ntoa(*(PIN_ADDR)*(lpHostEnt->h_addr_list));
MessageBox(NULL, szIPAddr, lpHostEnt->h_name,
MB_OK|MB_ICONINFORMATION);
6
ИП_Л_4
}
Если gethostbyname не в состоянии определить адрес хоста по его имени, она возвращает NULL. Если lpHostEnt не равен NULL, QLookup вызывает
функцию MessageBox, чтобы выдать IP-адрес хоста на монитор (в формате
«десятичное с точкой»).
Подробнее о функции inet_ntoa
Элемент структуры host-entry, h_addr_list, указывает на список IPадресов сетевого компьютера. Их может быть несколько, по числу сетевых
интерфейсных карт, установленных в компьютере. Функция inet_ntoa требуется для того, чтобы преобразовать первый адрес в списке, на который указывает h_addr_list, в символьное представление, то есть в адрес вида «десятичное с точкой». Прототип функции inet_ntoa следующий:
char FAR * PASCAL FAR inet_ntoa(struct in_addr in);
Параметром функции является структура типа in_addr. Структура состоит из объединения, в котором 32-битный IP-адрес представлен тремя способами: как четыре байта, два 16-битовых числа и как одно 32-битовое число.
Описание структуры in_addr находится в файле winsock.h:
struct in_addr {
union
{
struct
{
// IP-адрес по байтам
u_char // (Четыре байта)
s_bl, // Байт 1 (старший)
s_b2, // Байт 2
s_b3, // Байт 3
s_b4; // Байт 4 (младший)
} S_un_b;
struct
// IP-адрес в виде двух 16-битовых величин
{
u_short
s_wl, // Первые (старшие) 16 битов
s_w2, // Вторые (младшие) 16 битов
} S_un_w;
u_long S_addr; // IP-адрес в виде 32-битной величины
} S_un;
}
Примечание: Как видим, IP-адрес, записанный в структуре, хранится в
любых мыслимых для прикладной программы форматах. Структура in_addr
снимает с прикладной программы необходимость самостоятельно транслировать адреса из одной системы счисления в другую и тем самым рисковать совершить ошибку.
Функция inet_ntoa возвращает указатель на строку, содержащую IPадрес в формате «десятичное с точкой», извлеченный из структурыпараметра вызова. Выдавая номер компьютера на монитор, наша программа
QLookup использует этот указатель в качестве второго аргумента в вызове
функции MessageBox. Например, если gethostbyname, вызванная с аргументом cerfnet.com, возвращает действительный указатель на структуру host7
ИП_Л_4
entry, панель, выведенная QLookup на экран, будет выглядеть, как показано
на рис. 9.4.
Рис. 9.4. Панель сообщения QLookup с адресом сетевого компьютера
cerfnet.com
Как видно из рис. 9.4, текст в панели сообщения — это IP-адрес компьютера cerfnet.com, равный 192.102.249.3. Поле h_field в структуре hostentry является указателем на официальное имя хоста. QLookup помещает этот
элемент структуры (lpHostEnt->h_name) в заголовок панели сообщения.
Если указатель lpHostEnt равен NULL, QLookup вызывает функцию
Message-Box, чтобы вывести сообщение «Could not get IP address» («преобразование имени в адрес осуществить не удалось»). В качестве заголовка панели используется параметр, переданный gethostbyname. На рис. 9.5 показана
панель, возникающая, когда gethostbyname не смогла преобразовать имя
cerfnet.com в IP-адрес.
Рис. 9.5. Функции gethostbyname не удалось найти адрес
Подробнее о функции inet_addr
Независимо от того, удалось ли получить информацию о сетевом компьютере по имени, QLookup пробует получить информацию по его адресу.
Для этого QLookup преобразует адрес из десятичного с точкой в 32-битный
IP-адрес. Функция inet_addr находится в библиотеке функций Windows Sockets. Она не обращается к Интернет (или любой другой сети TCP/IP). Ее задача
— преобразовать строку с IP-адресом «десятичное с точкой» в его 32разрядное двоичное представление. Прототип inet_addr следующий:
unsigned long PASCAL FAR inet_addr(const char FAR * cp);
Функция возвращает значения типа unsigned long (беззнаковое длинное
целое). Переменная этого типа представляет 32-разрядное число, равное IPадресу аргумента. Программа QLookup преобразует строковую константу
HOST_ADDR в переменную dwIPAddr, имеющую тип unsigned long:
dwIPAddr = inet_addr(HOST_ADDR);
Если аргумент inet_addr задан неверно, функция вернет значение
INADDR_NONE. QLookup проверяет результат inet_addr (присвоенный
dwIPAddr), чтобы установить, было ли преобразование успешным:
if (dwIPAddr == INADDR_NONE)
MessageBox(NULL, "Invalid Internet address!", HOST_ADDR,
8
ИП_Л_4
MB_OK|MB_ICONSTOP);
Если inet_addr вернула значение INADDR_NONE, QLookup выводит
панель сообщения с соответствующей надписью: «Invalid Internet address!».
Подробнее о функции gethostbyaddr
Если dwIPAddr содержит правильный 32-битный IP-адрес, QLookup
пробует получить информацию о сетевом компьютере по нему. Для этого используется функция gethostbyaddr. Прототип функции описан ниже:
struct hostent FAR * PASCAL FAR gethostbyaddr(const char FAR * addr, int len, int
type);
У gethostbyaddr три параметра: указатель на IP-адрес (с сетевой последовательностью байтов, в том виде, в каком его возвращает функция
inet_addr), длина адреса (в Интернет всегда равная четырем байтам) и тип адреса (всегда равный AF_INET). Первый параметр в вызове gethostbyaddr в
нашей программе равен dwIPAddr. Это значение, полученное при вызове
inet_addr. Для оставшихся двух параметров используются константы
AF_INET_LENGTH и AF_INET. Первая определена в QLookup и равна четырем байтам. Вторая определена в файле winsock.h. QLookup использует переменную lpHostEnt — указатель на структуру host-entry повторно для сохранения результата функции gethostbyaddr:
lpHostEnt = gethostbyaddr((LPSTR) &dwIPAddr, AF_INET_LENGTH,
Так же как и gethostbyname, gethostbyaddr возвращает указатель на
структуру host-entry. Далее QLookup проверяет результаты вызова, присвоенные переменной lpHostEnt:
if (!lpHostEnt)
MessageBox(NULL, "Could not get host name!", HOST_ADDR,
MB_OK|MB_ICONSTOP);
else
MessageBox(NULL, lpHostEnt-»h_name, HOST_ADDR,
MB_OK|MB_ICONINFORMATION);
Так же как и gethostbyname, gethostbyaddr возвращает NULL в случае
неудачной попытки получить нужную информацию или ошибки. Если результат не NULL, QLookup выводит панель сообщения, на котором присутствует h_name (имя сетевого компьютера) как поле структуры host-entry.
Константа HOST_ADDR находится в заголовке панели. Она показывает значение первого аргумента, переданного функции inet_addr. Определив константу HOSTADDR как 129.79.26.27, например, получим сообщение, показанное на рис. 9.6.
Рис. 9.6. Программа QLookup выводит имя сетевого компьютера,
определив его по IP-adpecy 129.79.26.27
Если указатель lpHostEnt равен NULL, QLookup выведет панель сообщения с текстом «Could not get host name» («He могу получить имя хоста»),
как показано на рис. 9.7.
9
ИП_Л_4
Рис. 9.7. Сообщение об ошибке при работе функции gethostbyaddr
Подводя итоги
В этой главе вы узнали, что система имен доменов Интернет (DNS)
представляет собой превосходный образец широкомасштабной распределенной базы данных. Децентрализованная иерархическая система DNS позволяет с легкостью управлять назначением имен миллионов сетевых компьютеров в Интернет.
В следующей главе мы воспользуемся техникой программирования,
изученной в этой главе. Вы узнаете, как устроен и функционирует протокол
информации о пользователях Finger. До того как перейти к главе 10, убедитесь, хорошо ли вы понимаете следующие ключевые моменты:
* Система имен доменов Интернет (DNS) предназначена для пользователей, желающих обращаться к компьютерам по именам, например
jamsa.com, а не по номерам, таким как 168.158.20.102.
* Система имен доменов Интернет преобразует (ставит в соответствие)
имя компьютера с его IP-адресом в формате «десятичное с точкой» или 32битовым эквивалентом.
* База данных DNS является распределенной.
* Серверы DNS общаются друг с другом для выяснения, кто из них обладает информацией для преобразования имени домена в IP-адрес.
10
Download