
Сервис WHOIS – это один из основных инструментов для людей, которые постоянно работают с доменными именами. Он нужен как любому человеку, желающему подобрать себе красивое доменное имя, так и хостинг-провайдеру, который помимо прочих услуг может предоставлять возможность регистрации домена. И те, и другие ищут автоматизации своей работы.
Итак, давайте разберёмся как это работает.
У каждой доменной зоны, будь то RU, COM или HOST есть как минимум один центр (whois-сервер), который обладает информацией о находящемся в её зоне домене. Для зоны RU, например, это whois.ripn.net и whois.tcinet.ru
Все whois-сервера всех доменных зон предоставляют информацию по строго унифицированному протоколу, слушающем подключения и запросы на 43-м порту.
Сам же запрос к whois-серверу – это просто отправка интересующего доменного имени на данный порт, после чего мы просто читаем ответ.
Для разработки системы автоматизированного получения WHOIS информации по доменам в первую очередь необходимо заполучить список серверов whois для всех существующих доменных зон. Правильным запросом Google в первой же строчке выдаёт ссылку на проект в GitHub, где выложен полноценный XML, содержащий всю требуемую нам информацию:
https://raw.githubusercontent.com/whois-server-list/whois-server-list/master/whois-server-list.xml
Сохраняем этот файл себе для последующего открытия в нашем приложении.
Если кому-то покажется, что постоянно обновлять XML файл и парсить его дело не очень удобное, то можно воспользоваться более простым способом – сторонним online-сервисом whois-servers.net. Просто склейте имя корневой зоны с хвостом «.whois-servers.net» и получите готовый адрес для отправки запроса на данные WHOIS (например, для зоны COM получится адрес «com.whois-servers.net»). Этот сервис к WHOIS не имеет никакого отношения, просто своими доменами третьего уровня ссылается на корректные адреса рабочих серверов WHOIS.
Пример разработан на C# в обычном WinForms: всего 2 текстовых поля и 1 кнопка.
Для получения списка серверов WHOIS по доменной зоне из загруженного файла XML была написана следующая функция:
public static List<string> GetWhoisServers(string domainZone){ if (_serverList == null){ _serverList = new XmlDocument(); //загружаем XML если ранее он не был загружен _serverList.Load("whois-server-list.xml"); } List<string> result = new List<string>(); //определяем функцию для рекурсивной обработки XML Action<XmlNodeList> find = null; find = new Action<XmlNodeList>((nodes) =>{ foreach (XmlNode node in nodes) if (node.Name == "domain"){ //находим в XML документе интересующую нас зону if (node.Attributes["name"] != null && node.Attributes["name"].Value.ToLower() == domainZone){ foreach (XmlNode n in node.ChildNodes) //забираем все адреса серверов, по которым можно получить данные о домене в требуемой зоне if (n.Name == "whoisServer"){ XmlAttribute host = n.Attributes["host"]; if (host != null && host.Value.Length > 0 && !result.Contains(host.Value)) result.Add(host.Value); } } find(node.ChildNodes); } }); find(_serverList["domainList"].ChildNodes); return result; }
Функция для получения WHOIS информации с уже известного сервера выглядит так:
public static string Lookup(string whoisServer, string domainName){ try{ if (string.IsNullOrEmpty(whoisServer) || string.IsNullOrEmpty(domainName)) return null; //Punycode-конвертер (если требуется) Func<string, string> formatDomainName = delegate(string name){ return name.ToLower() //если в названии домена есть нелатинские буквы и это не цифры и не точка и не тире, //например, "россия.рф" то сконвертировать имя в XN--H1ALFFA9F.XN--P1AI .Any(v => !"abcdefghijklmnopqrstuvdxyz0123456789.-".Contains(v)) ? new IdnMapping().GetAscii(name) ://вернуть в Punycode name;//вернуть исходный вариант }; StringBuilder result = new StringBuilder(); result.AppendLine("По данным " + whoisServer + ": ------------------------------------------"); using (TcpClient tcpClient = new TcpClient()){ //открываем соединение с сервером WHOIS tcpClient.Connect(whoisServer.Trim(), 43); byte[] domainQueryBytes = Encoding.ASCII.GetBytes(formatDomainName(domainName) + "\r\n"); using (Stream stream = tcpClient.GetStream()){ //отправляем запрос на сервер WHOIS stream.Write(domainQueryBytes, 0, domainQueryBytes.Length); //читаем ответ в формате UTF8, так как некоторые национальные домены содержат информацию на местном языке using (StreamReader sr = new StreamReader(tcpClient.GetStream(), Encoding.UTF8)){ string row; while ((row = sr.ReadLine()) != null) result.AppendLine(row); } } } result.AppendLine("---------------------------------------------------------------------\r\n"); return result.ToString(); }catch{} return "Не удалось получить данные с сервера " + whoisServer; }
Функция умеет автоматически конвертировать домены на кириллице (или любом другом языке), благодаря чему запрос отлично работает как с доменами в классических зонах на латинице, так и с любыми национальными. Особенно приятно, что в .NET эта конвертация реализуется одной строчкой кода с использованием класса System.Globalization.IdnMapping
Эти 2 созданные функции дают нам всё, что требуется и остаётся только обработать нажатие кнопки «Получить данные» на форме.
Имея доменное имя на входе для проверки WHOIS сначала нам необходимо вычленить зону, в которой он находится. Ввиду того, то домен может быть в зоне какого угодно уровня (вовсе не обязательно, что всегда во второй!), я написал простой цикл, который для каждого уровня, начиная с наивысшего, проверит наличие серверов WHOIS.
private void get_BTN_Click(object sender, EventArgs e){ List<string> whoisServers = null; //разбиваем домен на уровни string[] domainLevels = domainName_TB.Text.Trim().Split('.'); //по шагам пытаемся найти WHOIS-сервер для доменной зоны различного уровня от большей к меньшей for (int a = 1; a < domainLevels.Length; a++){ /* * Если требуется информация по домену test.some-name.ru.com, * то сначала попытаемся найти WHOIS-сервера для some-name.ru.com, * после для ru.com и если всё ещё не найдём, то для com */ string zone = string.Join(".", domainLevels, a, domainLevels.Length - a); whoisServers = WhoisService.GetWhoisServers(zone); //если нашли WHOIS-сервер, то поиск прекращаем if (whoisServers.Count > 0) break; } if (whoisServers == null || whoisServers.Count == 0) result_TB.Text = domainName_TB.Text + "\r\n----------------\r\nНеизвестная доменная зона"; else{ result_TB.Text = ""; foreach (string whoisServer in whoisServers) result_TB.Text += WhoisService.Lookup(whoisServer, domainName_TB.Text); } }
Далее спрашиваем информацию по домену у каждого из найденных серверов и записываем её в окно вывода результата.

Чтобы не собирать по частям из кода в статье, проект в готовом виде загрузил сюда.