Робимо власний сервіс з визначення WHOIS будь-якого домену



Сервіс 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 файл і парсити його справа не дуже зручне, то можна скористатися більш простим способом – стороннім онлайн-сервісом 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 == "-"){
//знаходимо у 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\пНеизвестная доменна зона";
else{
result_TB.Text = "";
foreach (string whoisServer in whoisServers)
result_TB.Text += WhoisService.Lookup(whoisServer, domainName_TB.Text);
}
}

Далі запитуємо інформацію по домену у кожного із знайдених серверів і записуємо її в вікно виводу результату.



Щоб не збирати по частинах з коду в статті, проект в готовому вигляді завантажив сюди: http://my-page.ru/whois.rar
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.