Простой поиск в DNS
Проблема
Требуется определить IP-адрес хоста или преобразовать IP-адрес в имя. Сетевые серверы
решают эту задачу в процессе аутентификации своих клиентов, а клиенты — когда пользователь
вводит имя хоста, но для библиотеки сокетов Perl нужен IP-адрес. Более того, многие серверы
регистрируют в файлах журналов IP-адреса, но аналитическим программам и людям удобнее
работать с именами хостов.
Решение
Для получения всех IP-адресов по имени хоста (например, www.perl.com) воспользуйтесь
функцией gethostbyname:
use Socket;
@addresses = gethostbyname($name) or die "Can't resolve $name: $!\n";
@addresses = map { inet_ntoa($_) } @addresses[4..$#addresses];
#@addresses - список IP-адресов ("208.201.239.48", "208.201.239.49")
Если вам нужен только первый адрес, воспользуйтесь функцией inet_aton:
use Socket;
$address = inet_ntoa(inet_aton($name));
#$address - один IP-адрес ("208.201.239.48")
Для получения имени хоста по строке с IP-адресом (например, "208. 201.239.48"),
воспользуйтесь следующим фрагментом:
use Socket:
$name = gethostbyaddr(inet_aton($address), AF_INET)
or die "Can't resolve $address: $!\n";
# $name - имя хоста ("www.perl.com")
Комментарий
Наша задача усложняется тем, что функции Perl являются простыми оболочками для системных
функций С, поэтому IP-адреса приходится преобразовывать из ASCII-строк ("208. 201. 239.48")
в структуры С. Стандартный модуль Socket содержит функцию inet_aton для перехода от ASCII
к упакованному числовому формату и функцию inet_ntoa, выполняющую обратное преобразование:
use Socket;
$packed_address = inet_aton("208.146.140.1");
$ascii_address = inet_ntoa($packed_address);
Функция gethostbyname получает строку, содержащую имя хоста (или IP-адрес).
В скалярном контексте она возвращает IP-адрес удаленного хоста, который можно передать
inet_ntoa (или undef в случае ошибки). В списковом контексте она возвращает список,
состоящий по крайней мере из пяти элементов (или пустой список в случае ошибки).
Список состоит из следующих элементов.
Индекс |
Значение |
0 |
Официальное имя хоста |
1 |
Синонимы (строка, разделенная пробелами) |
2 |
Тип адреса (обычно AF_INET) |
3 |
Длина структуры адреса (не имеет значения) |
4,5... |
Структуры адресов |
Имени хоста может соответствовать несколько IP-адресов; в частности, это происходит на
сильно загруженных Web-серверах, где для снижения загрузки на разных компьютерах размещаются
идентичные Web-страницы. В подобных ситуациях сервер DNS, предоставляющий адреса, чередует
их, обеспечивая сбалансированную нагрузку на сервер. Если вы хотите выбрать IP-адрес для
подключения, просто возьмите первый адрес в списке (а если он не работает,
попробуйте остальные адреса):
$packed = gethostbyname($hostname)
or die "Couldn't resolve address for $hostname: $!\n";
$address = inet_ntoa($packed);
print "I will use $address as the address for $hostname\n";
Используя имена хостов для разрешения или отказа в обслуживании, будьте осторожны.
Любой желающий может настроить свой сервер DNS так, чтобы его компьютер идентифицировался
как www.whitehouse.gov, www.yahoo.com или this.is.not.funny. Нельзя сказать, действительно
ли ему принадлежит то имя, на которое он претендует, пока вы не вызовете gethostbyname и
не проверите исходный адрес по адресному списку для данного имени.
# $address - проверяемый IP-адрес (например, "128.138.243.20")
use Socket;
$name = gethostbyaddr(inet_aton($address), AF_INET)
or die "Can't look up $address : $!\n";
@addr = gethostbyname($name)
or die "Can't look up $name : $!\n";
$found = grep { $address eq inet_ntoa($_) } @addr[4..#$addr];
Оказывается, даже такой алгоритм не дает полной уверенности в получении имени,
поскольку существуют разнообразные обходные пути. Даже IP-адрес из которого вроде
бы поступают пакеты, может быть поддельным, и в процессе аутентификации не следует
полагаться на сетевой уровень. В действительно важных ситуациях всегда выполняйте
аутентификацию сами (с помощью паролем или криптографических методов), поскольку сеть
IPv4 не проектировалась для соблюдения безопасности.
Информация о хосте не ограничивается адресами и синонимами. Чтобы полноценно
работать с дополнительными данными, воспользуйтесь модулем Net::DNS с CPAN.
Следующая программа показывает, как получить записи MX (mail exchange) для произвольного хоста.
#!/usr/bin/perl
# mxhost - поиск записей mx для хоста
use Net::DNS;
$host = shift;
$res = Net::DNS::Resolver->new();
@mx = mx($res, $host)
or die "Can't find MX records for $host (".$res->errorstring.")\n";
foreach $record (@mx) {
print $record->preference, " ", $record->exchange, "\n";
}
Примерный вывод выглядит так:
% mxhost cnn.com
10 mail.turner.com
30 alfw2.turner.com
См. также
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|