Как стать автором
Обновить

DN42 — большая BGP-песочница

Время на прочтение16 мин
Количество просмотров8.1K

DN42 - это сеть из VPN-туннелей с маршрутизацией по протоколу BGP. Участники устанавливают между собой соединения, используя различные туннельные технологии (Wireguard, OpenVPN, GRE, Tinc, ZeroTier и другие).

DN42 использует адреса в диапазоне 172.20.0.0/14 (для IPv4), fd00::/8 (для IPv6), а также номера автономных систем (AS) из приватного диапазона 4242420000-4242429999.

В настоящий момент (сентябрь 2023го) для аллокации свободно 314 IPv4-блоков (15% диапазона), ~72058 миллиардов /64-сетей (0.00006% диапазона), 1404 ASN (65% диапазона). ASN можно получить в диапазоне 4242420000-AS4242423999 (остальные блоки пока закрыты для регистрации).

В отличие от Интернет, в DN42 минимальный маршрутизируемый блок - это /29 (IPv4) и /64 (IPv6). Что позволяет делать dual-stack системы.

Для сравнения, в Интернет минимальный маршрутизируемый IPv4-блок - это /24, который стоит ~11000 EUR (покупка), ~200 EUR/месяц (аренда).

Зачем оно нужно?

  • Можно поэкспериментировать и изучить технологии маршрутизации.

    Основная польза от DN42 - это возможность получить опыт настройки туннелей и BGP-соединений. Именно так работает маршрутизация в Интернет.

  • Можно узнать как устроен Интернет и почувствовать себя провайдером.

    В DN42 есть регистр (registry), который очень схож с той же RIPE Database, набор внутренних сервисов и свой корневой домен .dn42 и корневые DNS-сервера.

Что для этого нужно?

  1. Иметь какое-нибудь устройство с доступом в Интернет. Любая Linux/BSD VM может быть DN42-роутером.

    В идеале, VM/Компьютер/Роутер должен быть подключен к сети 24/7 и иметь статические адреса.

  2. Разместить это устройство в сегменте, где разрешено делать сетевые туннели (Wireguard, GRE и так далее).

    Я использую дешевую VPS (2.50 евро в месяц) в Суоми.

  3. Иметь хотя бы начальные знания о сетях и маршрутизации.

Ключи и начальная настройка

Эти шаги можно делать как на вашем личном компьютере (что безопаснее), так и на VPS (если под рукой нет Linux/BSD машины). Кстати, использовать Windows-PC не получится, так как при создании объектов inet6num и route6 в названии файла используется :, а в Windows это не разрешено.

SSH

Скорее всего у Вас уже есть SSH ключи, но если нет, то генерируем их командой ssh-keygen:

ssh-keygen -t ecdsa -b 521

Она создаст пару ключей ~/.ssh/id_ecdsa (закрытый ключ) и /home/asm/.ssh/id_ecdsa.pub (публичный ключ).

PGP

PGP-ключи для настройки DN42 не обязательны, но желательны. Вот хорошая инструкция от GitHub.

Git

Также нам нужно будет установить git. DN42 Registry - это git-репозиторий.

Создание объектов в DN42 Registry

Настройка учётной записи и добавление ключей в Gitea

  • Первым делом идём в Registry и регистрируемся.

  • Затем идём в профиль и добавляем ключи.

В KeyName указать название ключа, в Content - содержимое файла ~/.ssh/id_ecdsa.pub

  • Также добавим и PGP-ключ

  • Если адрес электропочты PGP-ключа не совпадает с тем, что использовался при регистрации в Registry, то желательно подтвердить и его. Это можно сделать в настройках учетки

Создание объектов

Наконец-то приступаем к созданию объектов.

  • Для этого идём в Registry и жмём кнопку Fork.
    Это создаст форк проекта, который будет доступен по адресу

  • Клонируем наш форк

git clone git@git.dn42.dev:username/registry.git
cd registry
  1. Первым создаём объект person.

    Здесь и далее USERNAME, Username, username используются в качестве примера. Замените их на Ваши значения.

    vim data/person/USERNAME-DN42
    person:             username
    e-mail:             me@domain.tld
    nic-hdl:            USERNAME-DN42
    mnt-by:             USERNAME-MNT
    source:             DN42

    person — ваше имя пользователя (aka ник),
    email — адрес электропочты (желательно, тот который указан в PGP‑ключе),
    nic‑hdl — должно совпадать с названием файла,
    mnt‑by — ссылка на объект mntner (его мы сделаем следующим),
    source — DN42.

  2. Создаём объект mntner.

    vim data/mntner/USERNAME-MNT
    mntner:             USERNAME-MNT
    admin-c:            USERNAME-DN42
    tech-c:             USERNAME-DN42
    mnt-by:             USERNAME-MNT
    source:             DN42
    auth:               ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAAEVWYzitbGM5wyH07zY3iieXH28drL24rYpglGMlnH8QK4Tz+sCCg5LI/XpGd7At+liXWa90zQjAoYjk3q4Vi1+QFseJUC...
    auth:               pgp-fingerprint 88361AC....

    mntner - название объекта (должно совпадать с названием файла).
    admin-c - административный контакт. Ссылка на объект person.
    tech-c - технический контакт. Также ссылка на объект person.
    mnt-by - то же самое, что и поле mntner.
    source - DN42.
    auth - содержимое файла ~/.ssh/id_ecdsa.pub.
    auth - fingerprint pgp-ключа (если создавали).

  3. Для следующих объектов нам нужно выбрать номер автономной системы (ASN), IPv4 и IPv6 префиксы (сети).

    Чтобы найти свободные ASN и префиксы идём в FreeExplorer и выбираем.

    Обычно люди выбирают одну ASN, /27 IPv4-сеть (32-адреса) и /48 IPv6-сеть. Если у Вас маленькая сеть, то советую взять /28-ую сеть (16-адресов). Если наоборот, то /26 - её дадут без дополнительных вопросов. Всё что больше /26 (для IPv4) и /48 (для IPv6) потребует объяснения зачем Вам нужна такая большая сеть.

    Итак, выбираем. Опять же я взял случайные значения из FreeExplorer и их надо заменять на выбранные Вами.

    AS4242422076
    172.23.109.240/28
    fd46:b10:16::/48
  4. Возвращаемся в склонированный репозиторий и создаём объект для нашей ASN

    vim data/aut-num/AS4242422076
    aut-num:            AS4242422076
    as-name:            EXAMPLE-AS
    descr:              My Username Personal AS or another useful desciption
    admin-c:            USERNAME-DN42
    tech-c:             USERNAME-DN42
    remarks:            Peer with me at me@domain.tld or another human-oriented message
    mnt-by:             USERNAME-MNT
    source:             DN42
    

    as-name - название нашей автономной системы;
    descr - описание (для людей);
    admin-c, tech-c и mnt-by - ссылки на mntner-объект;
    remarks - необязательное поле для заметок (Обычно там указывается информации о способах peering);
    source - как и везде DN42.

  5. Дальше описываем блоки

    vim data/inetnum/172.23.109.240_28
    inetnum:            172.23.109.240 - 172.23.109.255
    cidr:               172.23.109.240/28
    netname:            EXAMPLE-NETWORK
    descr:              My Personal IPv4 Network
    remarks:            Peer with me at me@domain.tld
    country:            FI
    admin-c:            USERNAME-DN42
    tech-c:             USERNAME-DN42
    mnt-by:             USERNAME-MNT
    status:             ASSIGNED
    source:             DN42
    

    Название файла должно содержать нашу подсеть и маску (/ заменяется на _).

    inetnum - указывается диапазон возможных адресов (можно посчитать с помощью IP calculator);
    cird - подсеть в CIRD-нотации;
    netname - название сети;
    descr - описание для людей;
    remarks - то же самое что и для автономной системы (можно писать, а можно и нет).
    country - тоже необязательное поле;
    admin-c, tech-c и mnt-by - ссылки на mntner-объект;
    status - ASSIGNED (там есть и другие, но вроде нужно указывать именно ASSIGNED);
    source - как обычно, DN42.

  6. IPv6-блок практически тоже самое

    vim data/inet6num/fd46:b10:16::_48
    inet6num:           fd46:0b10:0016:0000:0000:0000:0000:0000 - fd46:0b10:0016:ffff:ffff:ffff:ffff:ffff
    cidr:               fd46:b10:16::/48
    netname:            EXAMPLE-NETWORK
    descr:              My Personal IPv6 Network
    remarks:            peer with me at me@domain.tld
    country:            FI
    admin-c:            USERNAME-DN42
    tech-c:             USERNAME-DN42
    mnt-by:             USERNAME-MNT
    status:             ASSIGNED
    source:             DN42
  7. Объекты для блоков мы создали, теперь самое время связать блоки с нашей автономной системой. Для этого есть объекты route и route6.

    vim data/route/172.23.109.240_28
    route:              172.23.109.240/28
    origin:             AS4242422076
    mnt-by:             USERNAME-MNT
    source:             DN42

    Тут тоже всё понятно. Единственное, в официальной инструкции сказано, что ещё нужен атрибут max-length, который должен быть равен маске сети. Этот атрибут говорит другим роутерам, что максимально возможный блок будет именно /28, а если мы попробуем анонсировать /29, то этот анонс не пройдёт валидацию.

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

    vim data/route6/fd46:b10:16::_48
    route6:             fd46:b10:16::/48
    origin:             AS4242422076
    mnt-by:             USERNAME-MNT
    source:             DN42
  8. Ещё есть объекты dns (для своего домена в .dn42-зоне) и organisation (для организации), но они необязательны и о них я напишу в другом посте.

Проверка, коммит, подпись и запрос на слияние (Pull Request)

На данный момент все необходимые объекты созданы и теперь нужно проверить, закоммитить и создать Pull Request.

  • Первым делом, отформатируем наши объекты

./fmt-my-stuff USERNAME-MNT
  • Затем проверим их на правильность и соответствие схеме

./check-my-stuff USERNAME-MNT
вывод команды check-my-stuff

[NOTE] ## Scan Started at 2023-09-12 15:36:45
CHECK data/mntner/USERNAME-MNT PASS MNTNERS: USERNAME-MNT
[NOTE] ## Scan Completed at 2023-09-12 15:36:46
[NOTE] ## Scan Started at 2023-09-12 15:36:46
CHECK data/aut-num/AS4242422076 PASS MNTNERS: USERNAME-MNT
[INFO] fd46:b10:16::/48
CHECK data/inet6num/fd46:b10:16::_48 PASS MNTNERS: USERNAME-MNT
CHECK data/inetnum/172.23.109.240_28 PASS MNTNERS: USERNAME-MNT
CHECK data/mntner/USERNAME-MNT PASS MNTNERS: USERNAME-MNT
CHECK data/person/USERNAME-DN42 PASS MNTNERS: USERNAME-MNT
CHECK data/route/172.23.109.240_28 PASS MNTNERS: USERNAME-MNT
CHECK data/route6/fd46:b10:16::_48 PASS MNTNERS: USERNAME-MNT
[NOTE] ## Scan Completed at 2023-09-12 15:36:47

  • Всё хорошо - можно коммитить

git add -A && git commit -am "Join DN42"
  • Теперь надо этот коммит подписать

./sign-my-commit --ssh --key ~/.ssh/id_ecdsa USERNAME-MNT
вывод команды sign-my-commit

Fetching dn42registry master
From git.dn42.dev:dn42/registry
branch master -> FETCH_HEAD
1 local commits found, no squash is required
Signing using SSH key
Detected git version >= 2.34, using git SSH signature
Using: 2048 SHA256:KJrAwld+1JfuT6zTN3t/fGVsNnIJq+Ltz9LkGdUj6kw /home/username/.ssh/id_ecdsa.pub (ECDSA)
[master d6b44bb97] Join DN42
Date: Tue Sep 12 17:38:42 2023 +0300
7 files changed, 49 insertions(+)
create mode 100644 data/aut-num/AS4242422076
create mode 100644 data/inet6num/fd46:b10:16::_48
create mode 100644 data/inetnum/172.23.109.240_28
create mode 100644 data/mntner/USERNAME-MNT
create mode 100644 data/person/USERNAME-DN42
create mode 100644 data/route/172.23.109.240_28
create mode 100644 data/route6/fd46:b10:16::_48
Verifying SSH signature in git
Good "git" signature for USERNAME-MNT with key SHA256:....
SSH signature verified ok

---

Remember to push your changes using: git push --force

---

  • Отправляем изменения в гит

git push --force
вывод команды git push

Enumerating objects: 364, done.
Counting objects: 100% (364/364), done.
Delta compression using up to 12 threads
Compressing objects: 100% (142/142), done.
Writing objects: 100% (333/333), 45.11 KiB | 45.11 MiB/s, done.
Total 333 (delta 230), reused 286 (delta 191), pack-reused 0
remote: Resolving deltas: 100% (230/230), completed with 28 local objects.
remote:
remote: Create a new pull request for 'username:master':
remote: https://git.dn42.dev/dn42/registry/compare/master...username:master
remote:
remote: . Processing 1 references
remote: Processed 1 references in total
To git.dn42.dev:username/registry.git

9c55ad3be...d6b44bb97 master -> master (forced update)

  • Идём по ссылке в сообщении, проверяем изменения, а также что коммит подписан и делаем New Pull Request

  • Дальше Ваш коммит проверят с помощью автоматической проверки.

    Если всё хорошо, то остаётся ждать когда Ваш PR сольют с основной веткой. Этот процесс может занять 1-2 дня. На практике проверено, что слияния происходят утром (в 9-10 EEST) и вечером (17-20 EEST)

    Если что-то пошло не так

    • Если валидатор указал на ошибку, то нужно её исправить и отправить изменения.

    vim data/path/to/file

    исправляем ошибку

    • Дальше коммитим

    git add -A && git commit -am "Join DN42"
    • Теперь у нас 2 коммита и их надо слить в один. Для этого выполняем:

./squash-my-commits
вывод команды squash-my-commits

Fetching dn42registry master
From git.dn42.dev:dn42/registry
branch master -> FETCH_HEAD
Rebasing local changes against the registry master
Current branch master is up to date.
Squashing 2 commits...
[master ac847fda0] squashed commit:
7 files changed, 49 insertions(+)
create mode 100644 data/aut-num/AS4242422076
create mode 100644 data/inet6num/fd46:b10:16::_48
create mode 100644 data/inetnum/172.23.109.240_28
create mode 100644 data/mntner/USERNAME-MNT
create mode 100644 data/person/USERNAME-DN42
create mode 100644 data/route/172.23.109.240_28
create mode 100644 data/route6/fd46:b10:16::_48

Remember to sign your commit: ./sign-my-commit FOO-MNT
and then push your changes using: git push --force

  • Как и до этого, коммит надо подписать и отправить.

./sign-my-commit --ssh --key ~/.ssh/id_ecdsa USERNAME-MNT
git push --force
вывод команды git push

Enumerating objects: 26, done.
Counting objects: 100% (26/26), done.
Delta compression using up to 12 threads
Compressing objects: 100% (17/17), done.
Writing objects: 100% (17/17), 2.88 KiB | 2.88 MiB/s, done.
Total 17 (delta 10), reused 0 (delta 0), pack-reused 0
remote:
remote: Visit the existing pull request:
remote: https://git.dn42.dev/dn42/registry/pulls/1234
remote:
remote: . Processing 1 references
remote: Processed 1 references in total
To git.dn42.dev:username/registry.git

d6b44bb97...82037bd0e master -> master (forced update)

Как видно из сообщения, новый PR создавать не надо и изменения уже отправлены в существующий запрос.

На этот раз обе проверки прошли успешно и остаётся только ждать

Подготовка сервера

Первое правило Бойцовского клуба dn42: всегда отключайте rp_filter.

Вообще-то, rp_filter штука полезная и блокирует пакет, если маршрут возврата пакета использует другой интерфейс, чем тот, с которого он прибыл.

Но как и в Интернет, так и в DN42 маршрутизация асимметричная, то пакеты могут идти по разным маршрутам. Вот почему rp_filter необходимо отключить.

vim /etc/sysctl.conf

Также включаем форвардинг между интерфейсами:

vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding = 1

Применяем налету

sysctl -p

Проверяем

sysctl -a | grep rp_filter
sysctl -a | grep forwarding

Находим пиринг-партнера

После того как наши изменения оказались в основной ветке (master), можно искать пиринг-партнера или сразу нескольких пиринг-партнеров.

Но я советую всё же подождать пару-тройку часов. Как и в Интернет, в DN42 есть механизм защиты и верификации маршрутов ROA (Route Origin Authorization).

ROA - это файл конфигурации вида

route 172.23.67.0/25 max 29 as 4242420022;
route 172.20.175.96/27 max 29 as 4242421508;
...

Он сообщает BGP-демону, что ASN 4242420022 может анонсировать префикс 172.23.67.0/25 или её подсети вплоть до /29. Данный файл генерируется dn42regsrv ROA Generator-ом и доступен для скачивания отсюда.

Большинство (IMHO) пиров скачивает этот файл по cronjob (или systemd timer) раз в 15-20 минут и подождать надо именно с целью того, чтобы информация о ваших объектах разошлась по сети.

Чтобы найти пиринг-партнера можно использовать сервис DN42 PeerFinder.

Он покажет наиболее близкие к вашей локации роутеры, но так как большинство (опять же IMHO) пирится вручную и надо писать людям на электропочту/телеграм/IRC, я бы советовал бы начать с автоматического пиринга.

Вот список сетей, которые предоставляют автоматический пиринг.

Лично мне больше всего понравился сервис сети Lutoma. Он предоставляет дружелюбный интерфейс и looking glass, который позволяет посмотреть состояние сессии со стороны Lutoma.

Автоматический пиринг

Процесс пиринга состоит из 3 шагов:

  • Верификация того, что Вы владеете AS, которую используете для пиринга

  • Создание туннеля

  • Создание BGP-сессии

Покажем как это выглядит на практике (на примере Lutoma и нашего сервера на ArchLinux).

Регистрация и Верификация AS

  • Открываем Peering Portal и жмём жёлтую кнопку "Sign up"

  • Вводим свой maintainer object USERNAME-MNTи получаем на электропочту ссылку для верификации.

Настройка туннеля Wireguard

Для автоматического пиринга Lutoma использует Wireguard-туннели (это самый популярный туннельный тип в DN42), поэтому нужно установить wireguard-tools

pacman -Sy wireguard-tools

Дальше нам надо сгенерировать ключи для шифрования в туннеле.

cd /etc/wireguard
wg genkey | (umask 0077 && tee 64719.pri) | wg pubkey > 64719.pub

Тут и далее я использую номер автономной сети пиринг-партнера в названии файлов конфигурации.

После успешной верификации и создания учётки можно, наконец, создавать туннель и настраивать BGP-cессию.

Для этого:

  • жмём Create Peering

  • выбираем подходящий Router и вводим название соединения. Что-то вроде myuserame (потом оно пригодится при отладке)

  • VPN Type - уже выбран.

  • В Wireguard endpoint - нужно вставить IP вашего роутера (это внешний IP, по которому роутер доступен в Интернете) и порт, на котором будет работать наш Wireguard. Также есть возможность ввести доменное имя, что по идее, позволяет устанавливать соединение с динамическим IP (DynDNS), но я такое не пробовал.

  • Далее Lutome нужен Ваш публичный ключ. Копируем его и вставляем в поле Wireguard public key.

cat 64719.pub

Заполняем секцию BGP:

  • вводим номер автономной системы 4242422076

  • В поле Internal IPv4 address нужно ввести один из IP из нашей DN42 подсети, например,172.23.109.249. У меня сделано таким образом: я разделил свою /28-ую сеть на две /29-ые. Первая часть (172.23.109.240/29) используется для LAN, вторая (172.23.109.248/29) - для пиринга.

  • В Link-local IPv6 address вводим любой адрес из диапазона fe80::/64 (например, fe80::4719).

  • Оставляем галочку на Multi-protocol BGP over IPv6 (Bird2 такое умеет).

  • В Link bandwidth выбираем пропускную способность своего Интернет соединения.

Cоздаём пиринг

Возвращаемся на сервер и настраиваем туннель.

vim /etc/wireguard/wg64719.conf
/etc/wireguard/wg64719.conf
[Interface]
PrivateKey = <Private_key_from_64719.pri>
ListenPort = 64719
Table = off

PostUp = /sbin/ip addr add dev %i 172.23.109.241/32 peer 172.22.119.1/32
PostUp = /sbin/ip addr add dev %i fe80::4719/128 peer fe80::acab/128
PostUp = sysctl -w net.ipv4.conf.%i.rp_filter=0
PostUp = sysctl -w net.ipv4.conf.%i.forwarding=1
PostUp = sysctl -w net.ipv6.conf.%i.autoconf=0
PostUp = sysctl -w net.ipv6.conf.%i.accept_ra=0
PostUp = sysctl -w net.ipv6.conf.%i.forwarding=1

[Peer]
Endpoint = de-fra.dn42.lutoma.org:43229
PublicKey = <Lutoma_Public_Key>
AllowedIPs = 172.20.0.0/14, fd00::/8, fe80::/64
PersistentKeepalive = 20

В PrivateKey вставляем наш приватный ключ из файла 64719.pri.

В Endpoint-e нужно вставить хост и порт из Вашей конфигурации.

Lutoma_Public_Key также берём из конфигурации.

Запускаем туннель

systemctl enable --now wg-quick@wg64719

После этого можно проверить соединение.

ping 172.22.119.1
ping fe80::acab%wg64719

Если оба адреса пингуются, то можно переходить к настройке BGP, если нет, то смотрим состояние с помощью команды

wg

Настройка BGP-сессии

В качестве BGP-демона в Linux/BSD можно использовать Bird/Quagga/FRRouting и другие. Я использую Bird2, если Вы планируете использовать другой демон, но у DN42, скорее всего, будет инструкция по его настройке.

Установка Bird2

pacman -S bird

Создаём структуру директорий

mkdir -p /etc/bird/{roa,peers}

ROA

Как я уже писал ранее ROA позволяет проверять соответствие ASN-prefix, это позволяет защититься от BGP hi-jacking.

Это можно и не делать, но я советую использовать ROA-проверку, тем более это несложно.

Для синхронизации ROA-конфигурации я использую curl, который запускается каждые 15 минут Systemd Timer-ом.

vim /etc/systemd/system/roa.service
/etc/systemd/system/roa.service
[Unit]
Description=Update DN42 ROA

[Service]
Type=oneshot
ExecStart=curl -sfSLR -o /etc/bird/roa/roa_v4.conf -z /etc/bird/roa/roa_v4.conf https://dn42.burble.com/roa/dn42_roa_bird2_4.conf
ExecStart=curl -sfSLR -o /etc/bird/roa/roa_v6.conf -z /etc/bird/roa/roa_v6.conf https://dn42.burble.com/roa/dn42_roa_bird2_6.conf
ExecStart=birdc configure

vim /etc/systemd/system/roa.timer
/etc/systemd/system/roa.timer

[Unit]
Description=Update DN42 ROA periodically

[Timer]
OnBootSec=2m
OnUnitActiveSec=15m
AccuracySec=1m

[Install]
WantedBy=timers.target

systemctl enable --now roa.timer

В итоге у нас должны появится два новых файла /etc/bird/roa/roa_v4.conf и /etc/bird/roa/roa_v6.conf

Bird2

Переходим к настройке Bird. Для начала я взял конфигурацию из документации.

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

Экспортируем (сообщаем пиринг-партнеру) все маршруты, которые имеем, но предварительно отсеиваем не DN42-cети.

bird.conf
################################################
#               Variable header                #
################################################

define OWNAS =  4242422076;
define OWNIP =  172.23.109.241;
define OWNIPv6 = fd46:b10:16::1;
define OWNNET = 172.23.109.240/28;
define OWNNETv6 = fd46:b10:16::/48;
define OWNNETSET = [172.23.109.240/28+];
define OWNNETSETv6 = [fd46:b10:16::/48+];

################################################
#                 Header end                   #
################################################

router id OWNIP;

protocol device {
    scan time 10;
}

/*
 *  Utility functions
 */

function is_self_net() {
  return net ~ OWNNETSET;
}

function is_self_net_v6() {
  return net ~ OWNNETSETv6;
}

function is_valid_network() {
  return net ~ [
    172.20.0.0/14{21,29}, # dn42
    172.20.0.0/24{28,32}, # dn42 Anycast
    172.21.0.0/24{28,32}, # dn42 Anycast
    172.22.0.0/24{28,32}, # dn42 Anycast
    172.23.0.0/24{28,32}, # dn42 Anycast
    172.31.0.0/16+,       # ChaosVPN
    10.100.0.0/14+,       # ChaosVPN
    10.127.0.0/16{16,32}, # neonetwork
    10.0.0.0/8{15,24}     # Freifunk.net
  ];
}

roa4 table dn42_roa;
roa6 table dn42_roa_v6;

protocol static {
    roa4 { table dn42_roa; };
    include "/etc/bird/roa_dn42.conf";
};

protocol static {
    roa6 { table dn42_roa_v6; };
    include "/etc/bird/roa_dn42_v6.conf";
};

function is_valid_network_v6() {
  return net ~ [
    fd00::/8{44,64} # ULA address space as per RFC 4193
  ];
}

protocol kernel {
    scan time 20;

    ipv6 {
        import none;
        export filter {
            if source = RTS_STATIC then reject;
            krt_prefsrc = OWNIPv6;
            accept;
        };
    };
};

protocol kernel {
    scan time 20;

    ipv4 {
        import none;
        export filter {
            if source = RTS_STATIC then reject;
            krt_prefsrc = OWNIP;
            accept;
        };
    };
}

protocol static {
    route OWNNET reject;

    ipv4 {
        import all;
        export none;
    };
}

protocol static {
    route OWNNETv6 reject;

    ipv6 {
        import all;
        export none;
    };
}

template bgp dnpeers {
    local as OWNAS;
    path metric 1;

    ipv4 {
        import filter {
          if is_valid_network() && !is_self_net() then {
            if (roa_check(dn42_roa, net, bgp_path.last) != ROA_VALID) then {
              print "[dn42] ROA check failed for ", net, " ASN ", bgp_path.last;
              reject;
            } else accept;
          } else reject;
        };

        export filter { if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then accept; else reject; };
        import limit 1000 action block;
    };

    ipv6 {
        import filter {
          if is_valid_network_v6() && !is_self_net_v6() then {
            if (roa_check(dn42_roa_v6, net, bgp_path.last) != ROA_VALID) then {
              print "[dn42] ROA check failed for ", net, " ASN ", bgp_path.last;
              reject;
            } else accept;
          } else reject;
        };
        export filter { if is_valid_network_v6() && source ~ [RTS_STATIC, RTS_BGP] then accept; else reject; };
        import limit 1000 action block;
    };
}

include "/etc/bird/peers/*.conf";

По факту, нужно только подставить в Header свои значения:

  • С OWNAS всё понятно - это номер автономной системы

  • В OWNIP указываем адрес роутер (я использую адрес LAN-адаптера).

  • С OWNIPv6 - то же самое, что и с OWNIP

  • В OWNNET и OWNNETv6 - указываем нашу IPv4-подсеть (и в IPv6-подсеть соответственно).

  • В OWNNETSET/OWNNETSETv6 - то же самое.

Добавим конфигурацию для нашего пиринг-партнера.

vim /etc/bird/peers/lutoma.conf
/etc/bird/peers/lutoma.conf

protocol bgp lutoma from dnpeers {
neighbor fe80::acab % 'wg64719' as 64719;
description "https://dn42.lutoma.org / hello@lutoma.org";
};

Взлетаем Запускаемся!

systemctl enable --now bird

Проверка состояния

Ждём 2-3 минуты и проверяем, что маршруты пришли:

ip route && ip -6 route

Если сессия установилась, то Вы увидите ~565 IPv4 и ~740 IPv6-маршрутов.

Поздравляю! Вы подключены к DN42. Можно даже пингануть какой-нибудь IP (корневой DNS server DN42, например):

ping -c 2 172.20.0.53
ping 172.20.0.53

PING 172.20.0.53 (172.20.0.53) 56(84) bytes of data.
64 bytes from 172.20.0.53: icmp_seq=1 ttl=63 time=24.7 ms
64 bytes from 172.20.0.53: icmp_seq=2 ttl=63 time=25.1 ms

--- 172.20.0.53 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 24.726/24.937/25.149/0.211 ms

Отладка

Если не всё так радужно и в маршрутной таблице почти пусто, то идём к Lutoma, где myuserame - это название нашего соединения.

Также смотрим и со своей стороны:

birdc show protocols lutoma
birdc show route

Настройка DNS

Пинговать и трейсить IP-адреса - это хорошо, но быстро наскучит. В DN42 есть же куча сервисов, которые доступны только изнутри.

Так как зона .dn42 является внутренней и корневые DNS-сервера Интернета о ней не знают, то использовать тот же Cloudflare DNS или Google DNS не получится. Вместо это можно использовать локальный DNS-демон dnsmasq, который все запросы к dn42-доменам будет адресовать к корневому DN42-серверу, а остальное к Cloudflare/Google/Quad9.

Установка и конфигурация dnsmasq

pacman -S dnsmasq
vim /etc/dnsmasq.conf
/etc/dnsmasq.conf
# Listen on this standard DNS port
port=53

# Never forward plain names (without a dot or domain part)
domain-needed

# Don't read /etc/hosts file
no-hosts

# Don't read /etc/resolv.conf or any other file.
# Use only the configuration provided by this file.
no-resolv

# Don't poll changes from external files (like /etc/resolv.conf)
no-poll

# Upstream DNS servers
server=2606:4700:4700::1111
server=2001:4860:4860::8844
server=1.1.1.1
server=8.8.8.8

# Force the upstream servers to be used in order
strict-order

# Increase the cachesize
cache-size=1500

# Don't store in cache the invalid resolutions
no-negcache

# Forward DN42
rebind-domain-ok=dn42
server=/dn42/172.20.0.53

# Reverse Forwards for DN42
server=/10.in-addr.arpa/172.20.0.53
server=/20.172.in-addr.arpa/172.20.0.53
server=/21.172.in-addr.arpa/172.20.0.53
server=/23.172.in-addr.arpa/172.20.0.53

А ещё dnsmasq умеет блокировать рекламу, но это совсем другая история.

Остаётся запустить dnsmasq и прописать его в качестве DNS-сервера по умолчанию.

systemctl enable --now dnsmasq
vim /etc/resolv.conf
/etc/resolv.conf

nameserver ::1
nameserver 2606:4700:4700::1111

Проверяем.

ping -c 2 asm.dn42
ping asm.dn42

PING asm.dn42(asm.ax (fd21:3087::1)) 56 data bytes
64 bytes from asm.ax (fd21:3087::1): icmp_seq=1 ttl=63 time=11.7 ms
64 bytes from asm.ax (fd21:3087::1): icmp_seq=2 ttl=63 time=11.8 ms

--- asm.dn42 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 11.702/11.747/11.793/0.045 ms

На этом предлагаю остановиться. Неохваченными остались следующие темы:

  • Multi-homing (пиринг с несколькими пиринг-партнерами).

  • BGP communities

  • Создание своего домена в зоне .dn42

  • Создание организации

  • Различные типы пиринга: Peer, Upsteam, Client

  • Anycast

  • Другие типы VPN (OpenVPN/GRE/ZeroTier)

  • 2+ сервера в DN42 и внутренняя маршрутизация

  • IXP

  • Настройка всяких Mikrotik-ов.

Если кому-то это будет интересно и полезно, то могу написать статью-продолжение.

Ну и конечно, Пиринг со мной.

Полезные ссылки

Теги:
Хабы:
Всего голосов 28: ↑28 и ↓0+28
Комментарии15

Публикации

Истории

Работа

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань