WHOIS представляет собой сетевой протокол прикладного уровня, базирующийся на протоколе TCP (и использующий порт 43). По бо́льшей части применяется для получения регистрационных данных о доменных именах: дате регистрации домена, информации о владельце, регистраторе и прочем.

В unix-like системах есть одноимённая утилита, позволяющая быстро получить искомые сведения. В частности для пользователей gentoo linux процесс её установки будет выглядеть следующим образом:

$ eix whois
* net-misc/whois
     Available versions:  5.0.11^t {iconv idn nls}
     Homepage:            http://www.linux.it/~md/software/
     Description:         improved Whois Client
# emerge -pav net-misc/whois

Тем, кому любопытно сделать свой вариант клиента whois, посвящается этот пост. Для написания подобной вещи предлагается использовать python3.

Для начала нужно импортировать необходимые модули и сделать проверку установленной версии python, поскольку во второй и третьей версии различаются некоторые типы данных:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket, sys

# если версия python ниже 3
# вывести сообщение и закрыть программу
if sys.version < '3.0':
                print("You need install python3")
                sys.exit()

Дальше следует функция, которая будет отправлять запрос на сервер и принимать ответ. Здесь используется модуль socket. Он предоставляет доступ к стандартному интерфейсу сокетов BSD (изначально разрабатывался для UNIX).

Модуль socket является низкоуровневым и в ряде случаев проще использовать функции из пакета urllib.

При работе с socket часто требуется указать семейство адресов и тип сокета. Для нашей небольшой программы важен протокол IPv4 (AF_INET). Типы сокетов представлены в таблице:

константаописание
SOCK_STREAMпоток байтов, обеспечивающий надёжность передачи данных (TCP)
SOCK_DGRAMдейтаграммы (UDP)
SOCK_RAWпростой сокет
SOCK_RDMдейтаграммы с надёжной доставкой

Для интернет-приложений, использующих IPv4, адреса определяются в виде кортежа (host, port):

('www.unix-lab.org', 80)

В блоке кода, представленном ниже, мы воспользуемся этим, чтобы соединиться с сервером. Для создания нового сокета понадобится употребить одну из функций модуля socket с таким же названием: socket.

socket(family, type [, proto])

где

  • family — определяет семейство адресов;
  • type — тип сокета;
  • proto — аргумент с именем протокола (обычно не передаётся).

Сокеты представлены экземплярами класса SocketType и обладают следующими методами:

методописание
connectустанавливает соединение с удалённым узлом
recvпринимает данные из сокета (макс. объём данных определяется аргументом bufsize)
sendпосылает данные через сетевое соединение, возвращает кол-во отправленных данных
closeзакрывает соединение

Исходя из сказанного выше, читателю должен быть понятен следующий блок кода:

def run_whois(server, query):
    # создать TCP-socket (IPv4)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # соединиться с сервером ('host', port)
    s.connect((server , 43))

    # отправить запрос на сервер
    # s.send(query + '\r\n') # для python2
    s.send((bytes(query, 'utf-8')) + b'\r\n')
    msg = ''
    while len(msg) < 10000:
        # получить данные от сервера
        # receive_data = s.recv(100) # для python2
        receive_data = str((s.recv(100)), encoding='utf-8')
        if(receive_data == ''):
            break;
        msg = msg + receive_data
    return msg

Следующая функция позволит получить данные от сервера whois-регистратора и обработать их.

def get_data(domain):    # получить объект(имя домена)
    # если введено http или www
    # перед именем домена, убрать их
    domain = domain.replace('http://', '')
    domain = domain.replace('www.', '')

    # получить доменную зону
    ext = domain[-3:].split('.')[-1]

    # обращаться к соответствующему whois-серверу зоны
    if(ext == 'org'):
        whois = 'whois.pir.org'
    elif(ext == 'ru' or ext == 'su'):
        whois = 'whois.tcinet.ru'
    else:
        whois = 'whois.iana.org' # сообщение для иных доменных зон

    # получить ответ от регистратора
    # (whois-server, имя домена)
    msg = run_whois(whois, domain)

    lines = msg.splitlines()        # разбиваем текст на сроки
    for line in lines:              # итерация по строкам
        if ':' in line:             # если есть знак :
            words = line.split(':') # разделить по нему строку
    return msg

И последнее: имя домена будет получено из агрумента командной строки при запуске программы. Оно передаётся функции get_data, и данные выводятся на экран.

try:
    domain_name = sys.argv[1]    # получить доменное имя из аргумента командной строки
    print(get_data(domain_name)) # передать доменное имя функции get_data
except IndexError:               # если программа запущена без аргумента
    print("enter domain name as a value!")

Данная программка не претендует на многое, но цели своей достигает; заодно знакомит потенциального читателя с частью такой огромной темы как работа с сетью и сокетами, а автору служит главным образом примером и напоминанием о различиях в обработке данных в разных версиях python’а. ⤧  Следующая запись Сниппеты в emacs