Skip to content

Instantly share code, notes, and snippets.

@wiktorbgu
Last active April 27, 2025 17:03
Show Gist options
  • Save wiktorbgu/1f2dfe99837d8f2803483be95814d2e5 to your computer and use it in GitHub Desktop.
Save wiktorbgu/1f2dfe99837d8f2803483be95814d2e5 to your computer and use it in GitHub Desktop.
Mikrotik WireGuard anti DPI

Чуть подправил скрипт , чтобы лишний раз не бегал по клиентским пирам, которые подключаются к этому роутеру, а только где роутер как клиент.
Работает убойно! Proton и Warp пробивает)

Upd.: увеличил время в фильтре до 2м30с как защита от ложных срабатываний у медленных подключений.
Считаю выполнение скрипта раз в 2 минуты средним нормальным значением.
Так же добавил в скрипт закомментированную строку с возможность исключения какого-либо wg интерфейса из проверки.

For old ROS < 7.17: у пиров изменили свойство is-responder на responder! добавил закоментированную строку в скрипт.

Если при выполнении скрипта на этапе генерации трафика выходит ошибка в лог, то:
выполнить команду /system/device-mode/print
если получаем mode: advanced и при этом в выводе нету traffic-gen: yes,
выполняем команду
/system/device-mode/update traffic-gen=yes и следуем инструкциям в консоли.
Официальная справка по device-mode.

Скрипт добавляется по пути в меню System - Scheduler

:global Tx
:global Rx
/interface/wireguard/peers

# при частых ребутах отключается пир wg
# решение просто раскомментировать следующую строку и внести имя интерфейса чей пир нужно включить в любом случае, если выключен.
#:foreach y in=[find where disabled=yes and responder!=yes and interface="wireguard-warp"] do={set $y disabled=no}

# Далее идут варианты строки, которые взаимоисключающие т.е. сейчас активна третья строка, можете её закомментировать и раскомментировать одну из первых двух вараинтов по необходимости. К дополнительным вариантам даны комментарии для чего они нужны.
# Для версий ROS < 7.17
#:foreach i in=[find where disabled=no and is-responder!=yes] do={
# Исключить подключение wireguard-client по имени интерфейса чтобы скрипт его никогда не трогал
#:foreach i in=[find where disabled=no and responder!=yes and interface!="wireguard-client"] do={
:foreach i in=[find where disabled=no and responder!=yes] do={
  :local LocalTx [get $i tx]
  :local LocalRx [get $i rx]
  :local LastHandshake [get $i last-handshake]
  :if (([:tostr $LastHandshake] = "") or (($LastHandshake > [:totime "2m30s"]) and ($Rx->[:tostr $i] = $LocalRx))) do={
    :local rawHeader [:rndstr length=4 from=123456789abcdef]
    :local EndpointAddress [get $i endpoint-address]
    :local EndpointAddressIP $EndpointAddress
    :local EndpointAddressIP [get $i current-endpoint-address]
    :local name [get $i name]
    :local wgDstPort [get $i current-endpoint-port]
    :local interface [get $i interface]
    
    # Сбрасываем исходящий порт на уровне интерфейса
    /interface wireguard set $interface listen-port=0
    :local srcport [/interface/wireguard/get $interface listen-port];

    :log info ("WG name is $name, EndpointAddress $EndpointAddress , LastHandshake $LastHandshake, LastTx " . $Tx->[:tostr $i] . ", CurrentTx $LocalTx, LastRx " . $Rx->[:tostr $i] . ", CurrentRx $LocalRx")
    :log info ("WG Currentinterface $interface, srcport $srcport, EndpointAddressIP $EndpointAddressIP, DstPort $wgDstPort")
    :log info ("Generating spam for RKN")
    set $i disabled=yes
    /tool traffic-generator stream remove [find]
    /tool traffic-generator packet-template remove [find]
    :delay 1
    /tool/traffic-generator/packet-template/add header-stack=mac,ip,udp,raw ip-dst=$EndpointAddressIP name=packet-template-wg raw-header=$rawHeader special-footer=no udp-dst-port=$wgDstPort udp-src-port=$srcport
    :delay 1
    /tool traffic-generator stream add disabled=no mbps=1 name=stream1 id=3 packet-size=1450 pps=0 tx-template=packet-template-wg
    :delay 1
    /tool traffic-generator quick duration=4
    :delay 1

    :log info ("Starting WG $EndpointAddress")
    set $i endpoint-address=$EndpointAddress
    set $i disabled=no
  }
  :set ($Tx->[:tostr $i]) $LocalTx
  :set ($Rx->[:tostr $i]) $LocalRx
}

Настройки задания в планировщике

/system script
add dont-require-permissions=yes name=PushWG policy=read,write,policy,test,sniff,sensitive source=":global Tx\r\
\n:global Rx\r\
\n/interface/wireguard/peers\r\
\n\r\
\n# \EF\F0\E8 \F7\E0\F1\F2\FB\F5 \F0\E5\E1\F3\F2\E0\F5 \EE\F2\EA\EB\FE\F7\E0\E5\F2\F1\FF \EF\E8\F0 wg\r\
\n# \F0\E5\F8\E5\ED\E8\E5 \EF\F0\EE\F1\F2\EE \F0\E0\F1\EA\EE\EC\EC\E5\ED\F2\E8\F0\EE\E2\E0\F2\FC \F1\EB\E5\E4\F3\FE\F9\F3\FE \F1\F2\F0\EE\EA\F3 \E8 \E2\ED\E5\
\F1\F2\E8 \E8\EC\FF \E8\ED\F2\E5\F0\F4\E5\E9\F1\E0 \F7\E5\E9 \EF\E8\F0 \ED\F3\E6\ED\EE \E2\EA\EB\FE\F7\E8\F2\FC \E2 \EB\FE\E1\EE\EC \F1\EB\F3\F7\E0\E5, \E5\
\F1\EB\E8 \E2\FB\EA\EB\FE\F7\E5\ED.\r\
\n#:foreach y in=[find where disabled=yes and responder!=yes and interface=\"wireguard-warp\"] do={set \$y disabled=no}\r\
\n\r\
\n# \C4\E0\EB\E5\E5 \E8\E4\F3\F2 \E2\E0\F0\E8\E0\ED\F2\FB \F1\F2\F0\EE\EA\E8, \EA\EE\F2\EE\F0\FB\E5 \E2\E7\E0\E8\EC\EE\E8\F1\EA\EB\FE\F7\E0\FE\F9\E8\E5 \F2.\
\E5. \F1\E5\E9\F7\E0\F1 \E0\EA\F2\E8\E2\ED\E0 \F2\F0\E5\F2\FC\FF \F1\F2\F0\EE\EA\E0, \EC\EE\E6\E5\F2\E5 \E5\B8 \E7\E0\EA\EE\EC\EC\E5\ED\F2\E8\F0\EE\E2\E0\F2\
\FC \E8 \F0\E0\F1\EA\EE\EC\EC\E5\ED\F2\E8\F0\EE\E2\E0\F2\FC \EE\E4\ED\F3 \E8\E7 \EF\E5\F0\E2\FB\F5 \E4\E2\F3\F5 \E2\E0\F0\E0\E8\ED\F2\EE\E2 \EF\EE \ED\E5\EE\
\E1\F5\EE\E4\E8\EC\EE\F1\F2\E8. \CA \E4\EE\EF\EE\EB\ED\E8\F2\E5\EB\FC\ED\FB\EC \E2\E0\F0\E8\E0\ED\F2\E0\EC \E4\E0\ED\FB \EA\EE\EC\EC\E5\ED\F2\E0\F0\E8\E8 \E4\
\EB\FF \F7\E5\E3\EE \EE\ED\E8 \ED\F3\E6\ED\FB.\r\
\n# \C4\EB\FF \E2\E5\F0\F1\E8\E9 ROS < 7.17\r\
\n#:foreach i in=[find where disabled=no and is-responder!=yes] do={\r\
\n# \C8\F1\EA\EB\FE\F7\E8\F2\FC \EF\EE\E4\EA\EB\FE\F7\E5\ED\E8\E5 wireguard-client \EF\EE \E8\EC\E5\ED\E8 \E8\ED\F2\E5\F0\F4\E5\E9\F1\E0 \F7\F2\EE\E1\FB \F1\
\EA\F0\E8\EF\F2 \E5\E3\EE \ED\E8\EA\EE\E3\E4\E0 \ED\E5 \F2\F0\EE\E3\E0\EB\r\
\n#:foreach i in=[find where disabled=no and responder!=yes and interface!=\"wireguard-client\"] do={\r\
\n:foreach i in=[find where disabled=no and responder!=yes] do={\r\
\n :local LocalTx [get \$i tx]\r\
\n :local LocalRx [get \$i rx]\r\
\n :local LastHandshake [get \$i last-handshake]\r\
\n :if (([:tostr \$LastHandshake] = \"\") or ((\$LastHandshake > [:totime \"2m30s\"]) and (\$Rx->[:tostr \$i] = \$LocalRx))) do={\r\
\n :local rawHeader [:rndstr length=4 from=123456789abcdef]\r\
\n :local EndpointAddress [get \$i endpoint-address]\r\
\n :local EndpointAddressIP \$EndpointAddress\r\
\n :local EndpointAddressIP [get \$i current-endpoint-address]\r\
\n :local name [get \$i name]\r\
\n :local wgDstPort [get \$i current-endpoint-port]\r\
\n :local interface [get \$i interface]\r\
\n \r\
\n # \D1\E1\F0\E0\F1\FB\E2\E0\E5\EC \E8\F1\F5\EE\E4\FF\F9\E8\E9 \EF\EE\F0\F2 \ED\E0 \F3\F0\EE\E2\ED\E5 \E8\ED\F2\E5\F0\F4\E5\E9\F1\E0\r\
\n /interface wireguard set \$interface listen-port=0\r\
\n :local srcport [/interface/wireguard/get \$interface listen-port];\r\
\n\r\
\n :log info (\"WG name is \$name, EndpointAddress \$EndpointAddress , LastHandshake \$LastHandshake, LastTx \" . \$Tx->[:tostr \$i] . \", CurrentTx \$Loc\
alTx, LastRx \" . \$Rx->[:tostr \$i] . \", CurrentRx \$LocalRx\")\r\
\n :log info (\"WG Currentinterface \$interface, srcport \$srcport, EndpointAddressIP \$EndpointAddressIP, DstPort \$wgDstPort\")\r\
\n :log info (\"Generating spam for RKN\")\r\
\n set \$i disabled=yes\r\
\n /tool traffic-generator stream remove [find]\r\
\n /tool traffic-generator packet-template remove [find]\r\
\n :delay 1\r\
\n /tool/traffic-generator/packet-template/add header-stack=mac,ip,udp,raw ip-dst=\$EndpointAddressIP name=packet-template-wg raw-header=\$rawHeader speci\
al-footer=no udp-dst-port=\$wgDstPort udp-src-port=\$srcport\r\
\n :delay 1\r\
\n /tool traffic-generator stream add disabled=no mbps=1 name=stream1 id=3 packet-size=1450 pps=0 tx-template=packet-template-wg\r\
\n :delay 1\r\
\n /tool traffic-generator quick duration=4\r\
\n :delay 1\r\
\n\r\
\n :log info (\"Starting WG \$EndpointAddress\")\r\
\n set \$i endpoint-address=\$EndpointAddress\r\
\n set \$i disabled=no\r\
\n }\r\
\n :set (\$Tx->[:tostr \$i]) \$LocalTx\r\
\n :set (\$Rx->[:tostr \$i]) \$LocalRx\r\
\n}"
/system scheduler
add interval=2m name=PushWG on-event="/system/script/ run PushWG" policy=read,write,policy,test,sniff,sensitive start-time=startup
@Cykooz
Copy link

Cykooz commented Nov 12, 2024

:local LastHandshake [get $i last-handshake]

У меня это не работает как ожидается, т.к. хендшейки не проходят, скорее всего из-за блокировки. Из-за этого last-handshake в роутере у меня всегда 00:00:00. При этом сам WG-тунель работает нормально.

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

PS: На сервере у меня самый обычный WG, без доп. функций для обхода блокировок, может поэтому хендшейки от него не доходят до роутера. Сам сервер видит хендшейки от роутера.

@wiktorbgu
Copy link
Author

Не встречал такого, даже с заворачиванием хендшейков в другой туннель счетчики ходят.
Версия ROS последняя?
А пробовали открыть порт входящий в брандмауэре для интерфейса WG?

@Cykooz
Copy link

Cykooz commented Nov 12, 2024

Прошивка 7.16.1.
До блокировки WG хендшейки нормально "бегали". Я даже ориентировался по ним, что что-то не так с тунелем.
Сейчас у меня ещё есть тунель внутри России, который не блокируется - там всё нормально с хендшейками, даже не смотря на то что один из peer-ов сидит за провайдерским NAT-ом с серым IP. Ничего специального, вроде открытия портов, я не делал для этого.
К тому же, как понима, порт в роутере нет смысла открывать, он автоматом должен быть открыт иначе как же WG будет работать. Но для проверки я разрешил в фаерволе input на порт, который слушает WG интерфейс. Трафик в нём идёт, но хендшейки не фиксируются.

@Cykooz
Copy link

Cykooz commented Nov 12, 2024

При этом параметры Rx и Tx в статистике пира тоже по нулям.

@wiktorbgu
Copy link
Author

У меня ощущение, что он даже и не работает, если даже трафик не считает) можем попробовать разобраться, в телегу закиньте скринов

@Cykooz
Copy link

Cykooz commented Nov 12, 2024

Трафик идёт, но его видно только в статистике WG интерфейса, а в пире аналогичная статистика по нулям. Специально traceroute-ом проверял, что запросы идут через WG, а не напрямую в интернет.

@q000p
Copy link

q000p commented Dec 7, 2024

изображение

@q000p
Copy link

q000p commented Dec 7, 2024

На двух нижних работает статистика, на двух верхних - нет.

@skylevels
Copy link

skylevels commented Jan 22, 2025

Приветствую! Вышла ROS 7.17, на ней скрипт не отрабатывает, в логах просто: executing script from scheduler failed, please check it manually
выскакивает сразу после: traffic generator stream added by scheduler:wg-rkn (*1 = /tool traffic-generator stream add disabled=no id=3 mbps=1 name=stream1 packet-size=1450 pps=0 tx-template=packet-template-wg)

@Cykooz
Copy link

Cykooz commented Jan 22, 2025

@skylevels Полагаю что следует почитать про device-mode. В нем как раз по дефолту отключен трафик-генератор. Надо как-то его отдельно включать.

@skylevels
Copy link

skylevels commented Jan 22, 2025

@Cykooz Дело не в этом. Генератор трафика включен 100%. Поднимаю туннель на один и тотже ip адрес из разных городов. РКН блочит трафик, причем только от некоторых (иначе было бы подозрение на кривые руки). То-есть условие проверки скрипта благоприятные. Но вот на 3х микротах, где наблюдается эффект ТСПУ скрипт выкидывает ошибку. Везде версия 7.17 стабильная. Подозрение что в ROS что-то наковыряли, либо в скрипте ошибка =(

@wiktorbgu
Copy link
Author

ROS тут ни при чем....

@Cykooz
Copy link

Cykooz commented Jan 22, 2025

@skylevels тогда попробуйте запустить скрипт из терминала, так он хотя бы какие-то детали по ошибке покажет

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment