Введение
Эта заметка о том, как настроить выборочный роутинг по нужным доменам на роутере Mikrotik с RouterOS 7.x, в частности на модели hAP ac^2.
Подключение к туннелю Wireguard
TIP
Как развернуть Wireguard на своем сервере можно прочитать здесь.
Получаем файл конфигурации Wireguard, он обычно выглядит примерно так:
[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
Проверяем что трафик ходит через интерфейс 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 то вы увидете следующую картину:
Для этого необходимо сразу поправить 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.
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
А клиенты должны получать IP адрес микротика в качестве единственного DNS сервера.
Добавляем правило фаерволла для блокировки 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.
Проверить, что адреса добавляются можно в IP - DNS - Static. Теперь при запросе домена из это списка он будет добавляться в Firewall - Address Lists.
Сделайте трассировку с клиента роутера до необходимого ресурса, маршрут должен проходить через туннель.
Настроим автозапуск скрипта в System - Scheduler - Add new
Так же это можно сделать одной командой:
/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