metalnikovg.ru
MetalnikovG.ru

Выборочный роутинг на Mikrotik

Banner.png
Опубликовано
//
10 мин. чтения

Введение

Эта заметка о том, как настроить выборочный роутинг по нужным доменам на роутере Mikrotik с RouterOS 7.x, в частности на модели hAP ac^2.

Подключение к туннелю Wireguard

TIP

Как развернуть Wireguard на своем сервере можно прочитать здесь.

Получаем файл конфигурации Wireguard, он обычно выглядит примерно так:

peer1.conf
[Interface]
PrivateKey = $PRIVATE_KEY
Address = 10.10.10.2/24
DNS = 1.1.1.1, 1.0.0.1
MTU = 1280

[Peer]
PublicKey = $PUBLIC_KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = $IP:51820
PresharedKey = $PRESHARED_KEY

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

Создаем интерфейс wireguard1:

/interface wireguard
add comment=vpn listen-port=51820 mtu=1280 name=wireguard1 private-key="$PRIVATE_KEY"

Public Key для интерфейса генерируется автоматически

Создаем пир:

/interface wireguard peers
add allowed-address=::/0,0.0.0.0/0 endpoint-address=$IP endpoint-port=51820 interface=wireguard1 persistent-keepalive=25s preshared-key="$PRESHARED_KEY" public-key="$PUBLIC_KEY"

Добавляем созданный интерфейс в LAN лист:

/interface list member
add interface=wireguard1 list=LAN

Назначим созданному интерфейсу адрес и сеть:

/ip address
add address=10.10.10.2/24 comment="vpn network" interface=wireguard1 network=10.10.10.0

Подключаем NAT для интерфейса wireguard1:

/ip firewall nat
add action=masquerade chain=srcnat comment="nat for WG" out-interface=wireguard1

Проверяем, что значения Rx и Tx ненулевые в WireGuard - Peers

wg-peers

Проверяем что трафик ходит через интерфейс wireguard1:

/ping ya.ru interface wireguard1

Настройка маршрутизации и списков.

Создаем таблицу маршрутизации wg-mark:

/routing table
add comment="routing tables for vpn" disabled=no fib name=wg-mark

Создаем маршруты в туннель для этой таблицы:

/ip route
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=wireguard1 pref-src="" routing-table=wg-mark scope=30 suppress-hw-offload=no target-scope=10

Добавляем маршрутизацию внутрь сети wireguard. Это нужно например для того чтобы иметь доступ к админ панели wireguard (wg-easy) или другим сервисам которые доступны только внутри вашего туннеля.

/ip route
add comment="wg subnet" disabled=no distance=1 dst-address=10.2.0.0/24 gateway=wireguard1 pref-src="" routing-table=main scope=30 suppress-hw-offload=no target-scope=10

Вместо $WGSUBNET вставляем подсеть туннеля, например 10.2.0.0/24.

Создаем два правила для маркировки двух списков to-wg и vpn-domains:

/ip firewall mangle
add action=mark-routing chain=prerouting comment="to wg" dst-address-list=to-wg new-routing-mark=wg-mark passthrough=yes
/ip firewall mangle
add action=mark-routing chain=prerouting comment="vpn-domains" dst-address-list=vpn-domains new-routing-mark=wg-mark passthrough=yes

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

На этом почти все готово, но вы можете столкнуться с тем что некоторые ресурсы не будут открываться через туннель. А если открыть Wireshark то вы увидете следующую картину:

wireshark

Для этого необходимо сразу поправить MSS:

/ip firewall mangle
add action=change-mss chain=forward comment="Change mss-to wireguard" new-mss=clamp-to-pmtu out-interface=wireguard1 passthrough=yes protocol=tcp tcp-flags=syn tcp-mss=1381-65535

Теперь по идее все должно работать, можно проверить добавив вручную адрес 2ip.ru в адрес лист.

/ip firewall address-list
add address=2ip.ru comment=test-2ip list=to-wg

Если все настроено правильно сайт должен показать IP адрес VPS сервера. В принципе в этот список можно вручную добавлять нужные вам домены или адреса, но здесь нет поддержки Wildcard. Т.е. не получится перенаправить маршрут сразу всех субдоменов на пример *.example.com. Вариант этот использовать можно, но не во всех случаях, поэтому приступим к настройке альтернативных вариантов.

BGP

Border Gateway Protocol (BGP) - это протокол маршрутизации, который используется для обмена информацией между разными автономными системами (AS). В простых словах, BGP отвечает за маршрутизацию трафика между различными доменами и провайдерами в интернете. Важно понимать, что BGP работает на уровне маршрутизации между AS и принимает решения, основанные на путях и атрибутах маршрутов.

Известны два сервиса antifilter.download и antifilter.network, которые предоставляют услугу анонса заблокированных IP-адресов и подсетей. Они это делают, для того чтоб вы могли их заблокировать на роутере. Но для учебных целей их можно направить в туннель.

Оба сервиса имеют списки:

  • Всех IP-адресов, который надо заблокировать
  • Их суммаризация для сокращения количества префиксов
  • Блокируемые подсети

Чем отличаются?

  • У antifilter.download есть список community. Он создаётся из резолвинга доменов, которые добавили пользователи сервиса
  • antifilter.download более стабилен
  • У antifilter.network есть прикольная фича по выбору списков, не прибегая к фильтрации префиксов на роутере
  • У antifilter.network есть список с суммаризацией от /32 до /23 маски
  • antifilter.network имеет много других списков

У обоих проектов есть чаты, где вы можете задать свой вопрос. Но лично мне больше импонирует antifilter.download, потому что он более стабилен и имеет список который формирует комьюнити.

Настройка получения префиксов с Antifilter.download

Переходим к настройке получения префиксов из списка subent+ipsum+community от antifilter.download. Эти списки отдаются по умолчанию.

Требуется подставить переменные:

  • $YOUR_AS - ваша рандомная AS. Число в диапазоне 64512-65543, кроме 65432

  • $IP - ваш внешний IP-адрес для того, чтобы не пересекаться с другими пользователями

  • $INTERFACE - имя интерфейса, через который необходимо пустить трафик

/routing bgp template
add as=$YOUR_AS comment=antifilter.download disabled=no hold-time=4m input.filter=bgp_in .ignore-as-path-len=yes keepalive-time=1m multihop=yes name=antifilter routing-table=main
/routing bgp connection
add as=65141 comment=antifilter.download connect=yes disabled=no hold-time=4m input.filter=bgp_in .ignore-as-path-len=yes keepalive-time=1m listen=yes local.role=ebgp multihop=yes name=antifilter_bgp remote.address=45.154.73.71/32 .as=65432 router-id=$YOUR_IP routing-table=main templates=antifilter
/routing filter rule
add chain=bgp_in comment="full list antifilter" disabled=no rule="set gw $INTERFACE; accept;"

Проверить, что префиксы пришли, можно командой

/routing/bgp/session print

Значения prefix-count и messages должны быть не равны нулю.

Либо через winbox\веб-интерфейс. Routing - BGP - Sessions, у поднятой сессии раздел Stats.

bgp-Sessions

NOTE

Небольшое пояснение перед следующим абзацем. У antifilter.download есть community список, который составляют сами пользователи. Предложить добавить домен можно в чате Telegram. Также в BGP существует понятие community, применятся для маркировки части префиксов. В рассматриваемом контексте используется для разделения и использования разных списков. Не запутайтесь.

По умолчанию отдаются вместе subnet, ipsum и community списки.

Чтоб получать только список community, необходимо отредактировать filter rule:

/routing filter rule
add chain=bgp_in comment="only community list" disabled=no rule="set gw wireguard1; if (bgp-communities includes 65432:500) {accept} else {reject}"

Остальные BGP community можно посмотреть на сайте в разделе ЧаВо - "Какие комьюнити используются в BGP-фиде?".

TIP

Если необходимо получать несколько списков community, то правило будет выглядеть так: (bgp-communities includes 65432:500 || bgp-communities includes 65432:400)

В случае фильтрации будут прилетать все префиксы, но активны будут только из выбранного community.

Посмотреть можно в ip - route

/ip/route print

Dab - active, те, что используются для маршрутизации

DbI - inactive, те, что отфильтровались и для маршрутизации не используются

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

/ip route add dst-address=45.154.73.71/32 gateway=$INTERFACE

Автоматическое добавление списков доменов в DNS static

Некоторые домены в списке community, например те которые стоят за CloudFlare и у них постоянно меняется адрес, добавляются только в список доменов.

В версии 7.5 была добавлена интересная фича:

*) dns - added "address-list" parameter for static DNS entries (CLI only);
*) dns - added "match-subdomain" option for static entries (CLI only);

На CLI only можно уже не обращать внимание, так-как в последующих версиях это появилось и в winbox и в веб-интерфейсе.

NOTE

Для работы данной фичи микротик сам должен выступать в роли DNS сервера.

Для этого нужно поставить галочку в чекбоксе Allow Remote Request и указать upstream DNS сервер, в моем случае Adguard Home который работает по адресу 192.168.78.110, вы можете указать любой, например Cloudflare - 1.1.1.1

mkt-dns

А клиенты должны получать IP адрес микротика в качестве единственного DNS сервера.

mkt-dhcp

Добавляем правило фаерволла для блокировки DNS запросов из интернета, если вы конечно не хотите чтобы кто-то еще использовал ваш микротик в качестве DNS сервера.

/ip firewall filter
add action=drop chain=input comment="DNS reqest drop" dst-port=53 in-interface=ether1 log=yes log-prefix=query_in_drop protocol=udp

Добавляем домен в /ip/dns/static:

/ip dns static
add name=4pda.to type=FWD forward-to=1.1.1.1 address-list=vpn-domains match-subdomain=yes

Теперь когда от клиента поступит запрос на 4pda.to IP-адреса домена и его субдоменов при резолвинге будут складываться в address-list vpn-domains. В type должен быть FWD и обязательно к какому DNS-серверу перенаправлять запрос. Параметр match-subdomain добавляет IP-адреса субдоменов указанного домена в address-list.

IP-адреса в address-list будет жить, пока живёт запись в /ip/dns/cache, а там она живёт, пока не истечёт её TTL.

Тут есть проблема, что обязательно надо куда-то перенаправлять DNS запрос. Нельзя просто без перенаправления складывать в address-list. Ещё нельзя использовать вместе с DoH:

WARNING

Currently DoH is not compatible with FWD type static entries, in order to utilize FWD entries, DoH must not be configured.

Таким образом, если ваш провайдер блокирует/подменяет DNS-запросы можно:

Перенаправлять DNS-запросы в туннель. Нужен настроенный резольвер на IP-адресе гейта VPN-сервера или в его подсети. Использовать отдельный DNS-сервер, который развёрнут рядом с роутером.

Дальше все запросы к зарезолвенным IP-адресам направляются в туннель также с помощью mangle по примеру выше.

Для автоматизации можно использовать скрипт который выкачивает список доменов с https://community.antifilter.download/list/domains.lst и добавлять их в /ip/dns/static:

:log info "Starting download domains list script"
:global readfile do={
    :local url        $1
    :local thefile    ""
    :local filesize   ([/tool fetch url=$url as-value output=none]->"downloaded")
    :local maxsize    64512 ; # is the maximum supported readable size of a block from a file
    :local start      0
    :local end        ($maxsize - 1)
    :local partnumber ($filesize / ($maxsize / 1024))
    :local reminder   ($filesize % ($maxsize / 1024))
    :if ($reminder > 0) do={ :set partnumber ($partnumber + 1) }
    :for x from=1 to=$partnumber step=1 do={
         :set thefile ($thefile . ([/tool fetch url=$url http-header-field="Range: bytes=$start-$end" as-value output=user]->"data"))
         :set start   ($start + $maxsize)
         :set end     ($end   + $maxsize)
    }
    :return $thefile
}

{
/ip dns static
:local update do={
 :global readfile
 :local data
 :do {
 :set data [$readfile $url]
 } on-error={}
 :log error [:len $data]
 :if ([:len $data] > 0) do={
   :log info "Starting import of domains-list: $listname"
   :log info "Deleting all Dynamic entries in domains-list: $listname"
   # remove the current list completely
   :foreach i in=[/ip dns static find where comment="vpn-domains"] do={
      /ip dns static remove $i
   }
   :local n 0; # counter
   :log info "Imported file length $[:len $data] bytes"
   :while ([:len $data]!=0) do={
     :do {
       :local line [:pick $data 0 [:find $data "\n"]];
       :if ($line~"^.+\\.[a-z.]{2,7}") do={
        :set n ($n + 1)
        /ip dns static add address-list=$listname disabled=no forward-to=$dns match-subdomain=yes name=$line comment="vpn-domains" regexp="" ttl=1d type=FWD
       }; # if domain present
     } on-error={:log error $error}
   :set data [:pick $data ([:find $data "\n"]+1) [:len $data]]; # removes the just added domain from the data array
   }; # while
   :log info "Completed importing $listname added/replacing $n lines."
 } else={
   :log error "Failed to download domain list, no changes made."
 }
}; # do

$update url=("https://" . "community.antifilter.download/list/domains.lst") delimiter=("\n") listname=vpn-domains dns=1.0.0.1
}

Сразу запустим скрипт, нажав на кнопку Run Script.

mkt-script

Проверить, что адреса добавляются можно в IP - DNS - Static. Теперь при запросе домена из это списка он будет добавляться в Firewall - Address Lists.

Сделайте трассировку с клиента роутера до необходимого ресурса, маршрут должен проходить через туннель.

Настроим автозапуск скрипта в System - Scheduler - Add new

mkt-scheduler

Так же это можно сделать одной командой:

/system scheduler
add interval=23h name=ScheduleVpnDomainList on-event="/system script run VpnDomainList" policy=read,write,test
  • Policy такие же, как у скрипта.
  • Interval - раз во сколько времени. Например, раз в 23 часа: 23:00:00.
  • On Event - команда заауска панее скрипта.

Теперь скрипт будет запускаться раз в 23 часа и выгружать список доменов.

Как отключить роутинг?

  • при BGP - Routing - BGP - Connection, кнопка Disable у поднятого соединения.
  • при mangle+address-list - просто выключить mangle правило. ip - firewall - mangle, кнопка Disable для созданного ранее правила.

Заключение

Мы настроили выборочный роутинг на Mikrotik с помощью BGP, DNS Static и Address Lists + Mangle

← Предыдущая заметкаМониторинг Adguard в Grafana