# SDK категоризации доменов

# Модуль категоризации доменов для C, C++

### Общие положения

Данная библиотека позволяет клиентам компании SkyDNS решать следующие основные задачи:

1. Находить категории заданного URL с помощью поиска в локальной базе данных, находящейся на конечном устройстве пользователя (ПК, маршрутизатор, встраиваемое устройство). В этом случае подключение к сети Интернет не нужно и никаких сетевых запросов не выполняется. Эта база данных называется локальной базой данных.
2. Находить категории заданного URL с помощью обращения по протоколу HTTPS к облаку компании SkyDNS. Поскольку в этом случае выполняется сетевой HTTPS-запрос, то для реализации этого функционала требуется, во-первых, работоспособное подключение к сети Интернет, и, во-вторых, наличие логина и пароля к соответствующему сервису SkyDNS. Но в этом случае наличие на компьютере пользователя локальной опорной базы данных не нужно.
3. Сохранять в локальном дисковом кэше категории URL, полученные из облака SkyDNS для последующего более быстрого доступа к ним. Данные, сохранённые в дисковом кэше, переживают перезагрузку компьютера и перезапуск приложения, использующего этот кэш.
4. Кэшировать в оперативной памяти компьютера полученные категории данного URL для ускорения последующего их поиска. Размеры кэша задаются при сборке решения.
5. Получать с сайта SkyDNS и устанавливать регулярные обновления к локальной базе данных тематических категорий сайтов. На текущий момент доступно только скачивание полностью базы данных (все категории ~1.6Гб, возможны более мелкие кастомные сборки)

Решение реализовано на языке программирования Си и предоставляет своим пользователям интерфейс в виде функций на этом языке программирования. Решение может быть также интегрировано в проект на языке Python (имеются примеры интеграции в Си и Python решения).

На текущий момент существует возможность выдачи категорий на английском и русских языках (задаётся на этапе компиляции библиотеки).

### Интеграция SDK в конечный продукт

SDK достаточно просто интегрировать в конечный программный продукт, разрабатываемый на языке программирования Си или Си++. Также существует возможность интегрировать его в конечное решение на Python.

Для использования библиотеки необходимо получить исходники библиотеки (тут [репозиторий](https://skydns.ru/downloads/url2cat-lib-stable.zip)), сконфигурировать библиотеку, собрать и установить.

#### Конфигурирование библиотеки url2cat

Для конфигурирования и сборки библиотеки используется утилита **cmake** (версии 3.15 или выше).

Также понадобятся библиотеки (для Ubuntu 18+): **openssl-1.1.1**, **sqlite3**.

1. Зайдите в каталог с исходниками библиотеки
2. Сконфигурируйте библиотеку используя команду:

```
cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release
> -DURL2CAT_SERVER=yes -DURL2CAT_DATABASE=yes -DURL2CAT_LOCALE=ru
> -DURL2CAT_LIBRARY=static
```

Изменяя следующие переменные можно настроить функции библиотеки:

- `URL2CAT_SERVER` - запросы к серверу SkyDNS (yes, no);
- `URL2CAT_DATABASE` - запросы к локальной БД (yes , no);
- `URL2CAT_LOCALE` - формат отображения категорий (ru, en);
- `URL2CAT_LIBRARY` - тип создаваемой библиотеки (static, shared);
- `URL2CAT_MAX_NUMBER_CATEGORY` - количество определяемых категорий (по умолчанию 5);
- `URL2CAT_HASH_TYPE` - тип хэша (MD5, SHA256, SHA512, по умолчанию MD5);
- `URL2CAT_HASH_LEN` - используемая длина хэша (full (хэш не обрезается перед поиском по базе), half (берётся 8 первых Байт хэша), по умолчанию half).

3. Соберите библиотеку используя команду:

```
cmake --build build_release
```

4. Скопируйте следующие файлы библиотеки в свой проект:

- `build_release/lib/liburl2cat.a` или `build_release/lib/liburl2cat.so`;
- `include/url2cat.h`.

#### Использование библиотеки в проекте

Вначале использования библиотеки нужно ее инициализировать с использованием структуры `s_url2cat_setting`. Структура имеет следующие поля:

- `cache_size` - размер кэша в байтах (если установлен 0 кэш не используется);
- `db_name` - имя базы данных;
- `db_download_scheme` - протокол для обновления БД;
- `db_download_host` - хост обновления БД;
- `db_download_port` - порт обновления БД;
- `db_download_path` - путь обновления БД;
- `db_download_user` - логин для обновления БД;
- `db_download_password` - пароль для обновления БД;
- `server_scheme` - протокол подключения к серверу SkyDNS;
- `server_host` - хост подключения к серверу SkyDNS;
- `server_port` - порт подключения к серверу SkyDNS;
- `server_path` - путь подключения к серверу SkyDNS;
- `server_user` - логин подключения к серверу SkyDNS;
- `server_password` - пароль подключения к серверу SkyDNS.

Для инициализации используется функция : `url2cat_init(s_url2cat_setting * setting)`

Для получения категории используется функция: `url2cat_category(char * url, size_t len_url, s_url2cat_category * * category, size_t * number_category)`

где `s_url2cat_category` структура, имеющая следующие поля:

- `type` - номер категории;
- `type_name` - название категории.

После использования библиотеки нужно ее деинициализировать используя функцию: `url2cat_deinit()`

При использовании библиотеки можно обновить БД используя функцию: `url2cat_database_update(s_url2cat_setting * setting)`

При использовании библиотеки можно отправить домен на перекатегоризацию используя функцию: `url2cat_recategory(char * url, size_t url_size, char * category_name, size_t category_name_size)`

Примечание. В каталоге `example/` исходников библиотеки url2cat есть примеры интеграции в простые решения на Си и Python.

### Приложения

#### Приложение 1. Справочник категорий

В настоящее время поддерживаются такие категории:

<table id="bkmrk-id-%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F-2-%D0%9D%D0%B5%D0%B8%D0%B7%D0%B2"><tbody><tr><td>id

</td><td>Категория

</td></tr><tr><td>2

</td><td>Неизвестные сайты

</td></tr><tr><td>3

</td><td>Malware

</td></tr><tr><td>4

</td><td>Phishing &amp; Typosquatting

</td></tr><tr><td>5

</td><td>Онлайн-реклама и баннеры

</td></tr><tr class="row-even"><td>6

</td><td>Наркотики

</td></tr><tr class="row-odd"><td>7

</td><td>Грубость, матершина, непристойность

</td></tr><tr class="row-even"><td>8

</td><td>Плагиат и рефераты

</td></tr><tr class="row-odd"><td>9

</td><td>Запаркованные домены

</td></tr><tr class="row-even"><td>10

</td><td>Агрессия, расизм, терроризм

</td></tr><tr class="row-odd"><td>11

</td><td>Прокси и анонимайзеры

</td></tr><tr class="row-even"><td>12

</td><td>Botnets &amp; C2C

</td></tr><tr class="row-odd"><td>13

</td><td>Сайты для взрослых

</td></tr><tr class="row-even"><td>14

</td><td>Алкоголь и табак

</td></tr><tr class="row-odd"><td>15

</td><td>Знакомства

</td></tr><tr class="row-even"><td>16

</td><td>Порнография и секс

</td></tr><tr class="row-odd"><td>17

</td><td>Астрология

</td></tr><tr class="row-even"><td>18

</td><td>Казино, лотереи, тотализаторы

</td></tr><tr class="row-odd"><td>20

</td><td>Торренты и P2P-сети

</td></tr><tr class="row-even"><td>21

</td><td>Файловые архивы

</td></tr><tr class="row-odd"><td>22

</td><td>Фильмы и видео онлайн

</td></tr><tr class="row-even"><td>23

</td><td>Радио и музыка онлайн

</td></tr><tr class="row-odd"><td>24

</td><td>Фотогалереи

</td></tr><tr class="row-even"><td>25

</td><td>Content Delivery Networks

</td></tr><tr class="row-odd"><td>26

</td><td>Чаты и мессенджеры

</td></tr><tr class="row-even"><td>27

</td><td>Форумы

</td></tr><tr class="row-odd"><td>28

</td><td>Компьютерные игры

</td></tr><tr class="row-even"><td>29

</td><td>Социальные сети

</td></tr><tr class="row-odd"><td>30

</td><td>Досуг и развлечения

</td></tr><tr class="row-even"><td>32

</td><td>Автомобили и транспорт

</td></tr><tr class="row-odd"><td>33

</td><td>Блоги и персональные сайты

</td></tr><tr class="row-even"><td>34

</td><td>Корпоративные сайты

</td></tr><tr class="row-odd"><td>35

</td><td>Интернет-магазины

</td></tr><tr class="row-even"><td>36

</td><td>Образование и учебные учреждения

</td></tr><tr class="row-odd"><td>37

</td><td>Финансы и финансовые учреждения

</td></tr><tr class="row-even"><td>38

</td><td>Правительство

</td></tr><tr class="row-odd"><td>39

</td><td>Здоровье и здравоохранение

</td></tr><tr class="row-even"><td>40

</td><td>Юмор

</td></tr><tr class="row-odd"><td>41

</td><td>Работа и найм

</td></tr><tr class="row-even"><td>42

</td><td>Войска и вооружения

</td></tr><tr class="row-odd"><td>43

</td><td>Политика, общество, закон

</td></tr><tr class="row-even"><td>44

</td><td>Новости и СМИ

</td></tr><tr class="row-odd"><td>45

</td><td>Некоммерческие организации

</td></tr><tr class="row-even"><td>46

</td><td>Порталы

</td></tr><tr class="row-odd"><td>47

</td><td>Религия и атеизм

</td></tr><tr class="row-even"><td>48

</td><td>Поисковые системы

</td></tr><tr class="row-odd"><td>49

</td><td>Компьютеры и Интернет

</td></tr><tr class="row-even"><td>50

</td><td>Спорт

</td></tr><tr class="row-odd"><td>51

</td><td>Наука и технологии

</td></tr><tr class="row-even"><td>52

</td><td>Туризм

</td></tr><tr class="row-odd"><td>53

</td><td>Дом, семья, хобби

</td></tr><tr class="row-even"><td>54

</td><td>Торговля и покупки

</td></tr><tr class="row-odd"><td>55

</td><td>Искусство

</td></tr><tr class="row-even"><td>56

</td><td>Веб-почта

</td></tr><tr class="row-odd"><td>57

</td><td>Недвижимость

</td></tr><tr class="row-even"><td>58

</td><td>Доски объявлений

</td></tr><tr class="row-odd"><td>59

</td><td>Бизнес, экономика, маркетинг

</td></tr><tr class="row-even"><td>60

</td><td>Сайты для детей

</td></tr><tr class="row-odd"><td>63

</td><td>Трекинг и Аналитика

</td></tr><tr class="row-even"><td>66

</td><td>Сryptojacking

</td></tr><tr class="row-odd"><td>67

</td><td>Интернет-библиотеки

</td></tr><tr class="row-even"><td>69

</td><td>Аниме

</td></tr><tr class="row-odd"><td>70

</td><td>DGA

</td></tr><tr class="row-even"><td>71

</td><td>Ransomware

</td></tr><tr class="row-odd"><td>72

</td><td>ИИ Чат-боты

</td></tr><tr class="row-even"><td>100

</td><td>Без контента

</td></tr></tbody></table>

Для зарубежного рынка добавлены категории:

<table id="bkmrk-id-%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F-19-chil"><tbody><tr class="row-odd"><td>id

</td><td>Категория

</td></tr><tr class="row-even"><td>19

</td><td>Child Sexual Abuse (IWF)

</td></tr><tr class="row-odd"><td>31

</td><td>German Youth Protection

</td></tr><tr class="row-even"><td>65

</td><td>Child Sexual Abuse (Arachnid)

</td></tr></tbody></table>

#### Приложение 2. Канонический вид домена (или URL’а)

Один URL может быть представлен не в одной уникальной форме, для представления одного ресурса, например, punny-код и кириллица в домене, висячий слеш, и т.д.

Было бы нерационально включать в базу категоризации все эти различные возможности, как минимум для некоторых интеграций базы, например, в небольшие бюджетные роутеры.

Потому, наиболее рациональной кажется схема, по которой URL’ы ресурсов в базе хранятся в каноническом виде, а значит, перед запросом списка категорий, URL требуется каноникализировать, то есть получить каноническое представление URL’а.

Единый указатель ресурса URL состоит из нескольких частей, но нас интересует только два из них:

- Доменное имя (`domain`);
- Путь (`path`).

Рассмотрим на примере случайного URL:

`directory.google.com/example/test.php?key=value&one=1`

где домен это:

`directory.google.com`

а это путь URL:

`/example/test.php?key=value&one=1`

Поскольку URL указывает на ресурс, он может быть записан в различных формах и различными способами. Для прямого поиска в базе надо привести все разнообразные формы URL указывающие на один ресурс к одному каноничному виду. Это очень важно для получения правильной категоризации запрашиваемого URL.

Мы используем стандартный вариант каноникализации URL из проекта [Google Safe Browsing](https://developers.google.com/safe-browsing/) с версией API больше 2. В этом проекте описаны техники для каноникализации идентификатора ресурса, с примерами и алгоритмами которого можно ознакомится на [странице](https://developers.google.com/safe-browsing/v4/urls-hashing#canonicalization).

Примеры каноникализации:

<table id="bkmrk-%D0%98%D1%81%D1%85%D0%BE%D0%B4%D0%BD%D1%8B%D0%B9-url-%D0%9A%D0%B0%D0%BD%D0%BE%D0%BD%D0%B8%D1%87"><tbody><tr class="row-odd"><td>Исходный URL

</td><td>Каноничный URL

</td></tr><tr class="row-even"><td>`http://evil.com/foo-bar-baz`

</td><td>`http://evil.com/foo`

</td></tr><tr class="row-odd"><td>`http://host/%25%32%35`

</td><td>`http://host/%25`

</td></tr><tr class="row-even"><td>`http://evil.com/foo-bar-baz`

</td><td>`http://evil.com/foo`

</td></tr><tr class="row-odd"><td>`http://test.com/kek/../`

</td><td>`http://test.com/`

</td></tr></tbody></table>

##### Каноникализация в контексте библиотеки url2cat

Описанным выше образом мы получим каноничную форму URL. Но из-за природы URL нельзя положиться на один URL. Для поиска наилучшего соответствия ему в базе требуется сформировать производные URL, путем поочередного отбрасывания частей первичного URL с левого и правого края.

Рассмотрим на примере случайного URL:

`directory.google.com/example/test.php?key=value&one=1`

Производные URL будут следующими:

`directory.google.com/example/test.php`

`directory.google.com/example/`

`directory.google.com/`

`google.com/example/test.php?key=value&one=1`

`google.com/example/test.php`

`google.com/example/`

`google.com/`

Получившиеся URL требуется проверить по базе.

#### Приложение 3. Локальная база

Один из способов получения категорий URL состоит в использовании локальной базы данных, которую предоставляет своим клиентам компания SkyDNS. Эта база данных ежедневно обновляется и потому всегда содержит актуальную информацию о сайтах сети Интернет. В настоящее время эта база данных поставляется в формате sqlite3.

##### Обновление базы

База распространяется в двух видах: файл-бинарник (sqlite3-база) и патч (набор sql-конструкций для приведения имеющейся sqlite3-базы в актуальное состояние).

Источник для получения базы в бинарном виде: `https://url2cat.skydns.ru/pubfilter/grandbase.db`.

Источник для получения базы в виде патчей: `https://url2cat.skydns.ru/api/v1/update/<user_version>`, где &lt;user\_version&gt; это PRAGMA параметр текущей базы. Внутри получаемого патча, первой строкой указывается новая версия этого параметра и если она совпадает с запрошенной, то обновления не требуется.

Посмотреть текущую версию базы (PRAGMA-параметр user\_version) можно командой (Linux):

```
xxd -l 4 -s 60 grandbase.db
```

Процесс обновления представляет из себя GET-запрос к указанному источнику с параметрами BASIC-авторизации.

##### Описание базы

**Таблица result**

Таблица «**result**» содержит хешированные записи URL и их категоризацию.

Схема базы данных:

<table id="bkmrk-%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%94%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-doma"><tbody><tr class="row-odd"><td>Название

</td><td>Данные

</td></tr><tr class="row-even"><td>**domain\_hash**

</td><td>хэш от домена

</td></tr><tr class="row-odd"><td>**path\_hash**

</td><td>хэш от пути

</td></tr><tr class="row-even"><td>**cat\_id**

</td><td>список категорий

</td></tr></tbody></table>

С первичным ключом по полям `domain_hash`, `path_hash`.

Данные в поле `cat_id` хранятся в виде blob массива, для стандартизации перечисляемого типа, где каждая категория хранится в виде unsigned short.

**Таблица cat**

Таблица «**cat**» содержит список записей с названиями и идентификаторами категорий. В зависимости от требований клиента база SkyDNS Octo может поставляться с различным числом категорий с более детальной категоризацией или уникальными именами категорий.

Схема базы данных:

<table class="docutils align-default" id="bkmrk-%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%94%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-loca"><tbody><tr class="row-odd"><td>Название

</td><td>Данные

</td></tr><tr class="row-even"><td>**locale**

</td><td>идентификатор локализации

</td></tr><tr class="row-odd"><td>**cat\_id**

</td><td>идентификатор категории

</td></tr><tr class="row-even"><td>**name**

</td><td>название категории

</td></tr></tbody></table>

C первичным составным ключом `locale`, `cat_id`.

Идентификаторы из поля `cat_id` таблицы «**result**» являются внешним ключом на эту таблицу. Поле `locale` содержит идентификатор локализации языка, на котором записано название категории в поле `name`. Поле `cat_id` содержит числовой идентификатор категории, данные `cat_id` не являются последовательными. Поле `name` содержит локализованные названия категорий.

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

#### Приложение 4. API категоризации

Другой способ получения категорий URL состоит в использовании API категоризации. Получение списка категорий осуществляется GET-запросом на URL одного из серверов авторизации с применением BASIC-авторизации.

##### Сервера API категоризации

SkyDNS:

`https://z.api.skydns.ru/` - анонимный бесплатный сервер

`https://x.api.skydns.ru/` - сервер с авторизацией

На бесплатных серверах ограничение в 10 запросов в минуту.

##### Запрос на категоризацию

Формат запроса, на примере бесплатного сервера SkyDNS:

`https://z.api.skydns.ru/domain/pornhub.com`

Ответом сервера будет json вида:

```
{
    "category": [13, 16, 64],
    "bad": true,
    "category_name": [
        "Сайты для взрослых", "Порнография и секс", "Реестр запрещенных сайтов"
    ]
}
```

# Модуль категоризации доменов для Python

#### Модуль skydns\_url2cat на языке программирования Python

Модуль skydns\_url2cat предоставляет функционал для доступа к базе данных с внутренней каноникализацией запросов.

Для работы с модулем его необходимо установить на каждую целевую систему. Установка производится с помощью [pip](https://en.wikipedia.org/wiki/Pip_(package_manager)). После установки будут доступны несколько команд:

- skydns-url2cat - для разовой проверки урла по заданной базе
- skydns-url2cat-update - для обновления базы через сервера ООО «СкайДНС»

#### Программный интерфейс

Пример использования модуля:

```
>>> import skydns_url2cat

>>> skydns_url2cat.init(path_to_skydns_db)
True
>>> skydns_url2cat.lookup('google.com')
('google.com/', (48,))
```

<p class="callout warning">База sqlite работает нестабильно на сетевых файловых системах.</p>

<p class="callout info">Даже для чтения базы требуются права на запись, это особенность используемого режима работы базы.</p>

#### Перечитывание базы

При создании сервиса проверки ресурсов по урловой базе выгоднее держать открытое соединение на блок операций, а не создавать подключение к базе на каждый запрос. Но это создает проблемы для обновления базы и для обхода этого необходимо включать перечитывание базы.

##### Автоматическое перечитывание

Для включения режима автоматического перечитывания базы, после инициализации модуля, необходимо вызвать метод <cite>auto\_refresh</cite>

```
>>> import skydns_url2cat

>>> skydns_url2cat.init(path_to_skydns_db)
True
>>> skydns_url2cat.auto_refresh()
>>> skydns_url2cat.lookup('google.com')
('google.com/', (48,))
```

После этого модуль будет самостоятельно отслеживать изменение файла и будет производить перечитывание самостоятельно.

#### Обновление

Обновление происходит с помощью запуска команды

```
$ skydns-url2cat-update <path_to_db> <username> <password>
```

При этом произойдет проверка доступности обновлений, скачивание и применение обновления к указанной базе.

Настроить периодический запуск скрипта можно при помощи cron.

#### Модуль skydns\_url2cat

*exception*`skydns_url2cat.reader.``DatabaseError`

*class*`skydns_url2cat.reader.``Reader`

Класс для чтения содержимого базы

`configure`(*path* *username=None*, *password=None*)

Настраивает объект, задает путь до базы данных и авторизационные данные

`lookup`(*url*)

Функция для получения категории урла

Возвращает кортеж из 2 элементов:

1. Урл который найден в базе
2. Список id категорий

Если урл не найден или невозможно разобрать, то первый элемент будет None.

<table id="bkmrk-exception%3A-urlparsee"><tbody valign="top"><tr class="field-odd field"><th class="field-name">Exception:</th><td class="field-body">UrlParseError</td></tr><tr class="field-even field"><th class="field-name">Параметры:</th><td class="field-body">**url** – str</td></tr><tr class="field-odd field"><th class="field-name">Результат:</th><td class="field-body">tuple</td></tr></tbody></table>

`lookup_with_names`(*url*)

Функция для получения категории урла. В отличие от метода lookup возвращает список имен категорий.

`category`(*i*)

Возвращает имя категории

`categories`()

Возвращает доступные категории

`languages`()

Возвращает доступные локализации

`category_for_lang`(*lang*, *i*)

Возвращает имя категории в заданной локализации

`categories_for_lang`(*lang*)

Возвращает категории в заданной локализации

`rollback`()

Инициализировать автоматические перечитывание