Найти сообщения содержащие указанный MAC
/log print where message~"A8:A1:59:7E:C6:6D"
Найти сообщения содержащие указанный MAC
/log print where message~"A8:A1:59:7E:C6:6D"
Настроил тут на Mikrotik IKEv2, у меня работает даже в sandbox, а у одного из сотрудников вылетает сабж. При этом в логе на Mikrotik ничего, может показаться что клиент даже не инициирует подключение, но мы то умные, идем в System-Logging и добавляем ipsec. Снова пробуем подключиться и сразу видим вот такую картину:
Наибанальнейшая задача, связанная с тем фактом, что Mikrotik подставляет расширение txt практически к любому файлу. Простой консольный вариант:
/tool fetch mode=ftp user=FTP_USER password=Parol src-path=$SrcFile dst-path=$DstFile
Для работы требуется включить FTP, для безопасности можно ограничить адресом 127.0.0.1:
add action=accept chain=input dst-address=127.0.0.1 dst-port=80,21 protocol=tcp
Также требуется создать пользователя с ограничением по адресу и связать с группой с правами FTP,read,write
/user group add name=ftp policy="ftp,read,write,!local,!telnet,!ssh,!reboot,!policy,!test,!winbox,!password,!web,!sniff,!sensitive,!api,!romon,!dude,!tikapp"
/user add address=127.0.0.1/32 group=ftp name=FTP_USER
А это простенькая функция:
# Example: $RenameCopyFile SrcFile="File.ovpn.txt" DstFile="File.ovpn" ItCopy=true
:local RenameCopyFile do={
do {
[/tool fetch mode=ftp user=User password=Parol url="ftp://127.0.0.1/$SrcFile" dst-path=$DstFile as-value]
} on-error={
:put ("Failed to copy/rename file from \"$SrcFile\"")
:put ("Check settings ftp. \r\nImportant: \r\n\tftp - enable, \r\n\tport 21 open from 127.0.0.1, \r\n\tcreate user with permisson: \r\n\t\tftp,\r\n\t\tread,\r\n\t\twrite \r\n\tand allowed address=127.0.0.1")
return 0
}
if ($ItCopy=false) do={
/file remove $SrcFile
:put ("Success to rename file to \"$DstFile\"")
} else {
:put ("Success to copy file to \"$DstFile\"")
}
}
Функция не делает всяких проверок на наличие файла и правил, полагаемся на пользователя. Также внимательный читатель обратит внимание на то, что в первом примере использовался scr-path, а в этом примере используется url, так сделано для того, чтобы скрыть вывод команды (as-value)
Параметр ItCopy указывает на то, что мы хотим - скопировать или переименовать/переместить файл. Если указать true, то исходный файл удален не будет. Т.о. можно скопировать файл размером более 4096
Задача банальная, но сначала она ввела меня в ступор, ибо copy в /file нету. А решение банальное - в set contents направить get contents
/file set myFile.txt contents=[/file get SourceFile.txt contents]
Также не стоит забывать про ограничение на размер переменной 4096 байта, а в данном примере мы как раз сталкиваемся с этим ограничением
Плюс к этому, файл приемник должен существовать. Оригинальная инструкция с сайта mikrotik:
/file print file=myFile
/file set myFile.txt contents=""
Ошибки тут нет, к файлам добавляется расширение txt и это не поправить.
Но на wapLTE получаю ошибку no such item, так как файл не успевает создаться до выполнения второй строки. Добавляем паузу
/file print file=myFile
delay 2
/file set myFile.txt contents=""
Таким образом наш скрипт будет выглядеть так:
:local FileName "MyFile.txt"
:local Contents ([/file get SourceFile.txt contents])
/file print file=$FileName
delay 2
if ([:len [/file find where name=$FileName]]>0) do={
/file set $FileName contents=$Contents
}else={
:put "File not found"
}
А как дописать в тот же файл?
/file set myFile.txt contents=([/file get myFile.txt contents] . "\r\nBlalalala")
но и здесь работает ограничение 4096, поэтому слить 2+ файла <4096 bite в один файл >4096 не получится
А как скопировать или сформировать большой файл?, ограничение 4096 байт распространяется только на размер переменной
Вот тут можно провернуть фокус execute + put
:local mergeFile "
:local contents [/file get MyFile.txt contents]
:put \$contents
:put \$contents
:put \$contents
:put \$contents
"
:execute script=$mergeFile file=test
Но и в этом примере есть ограничение - источник не может быть больше 4096, плюс к имени файла будет добавлено расширение txt (переименовываем файлы).
Если нужно просто скопировать большой файл, то можно выполнить трюк с переименовыванием, исправил скрипт 16/09/2023.
И еще очень важный момент, данный трюк выполняется отдельно, а родительская программа будет работать дальше, т.о. если используются глобальные переменные с последующим удалением, то требуется установить паузу перед удалением.
Есть wapLTE и симка, задача пересылать смс. Самый простой способ:
:local new_num 8985756575
:foreach message in=[/tool sms inbox print as-value] do={
:local idSMS ($message->".id")
:local phoneNumber ($message->"phone")
:local TextMessage ($message->"message")
:local FullMessage "Phone: $phoneNumber\nSMS: $TextMessage"
/log info message=$FullMessage
/tool sms send lte1 phone-number=$new_num message=$FullMessage
/tool sms inbox remove numbers=$idSMS
:delay 1000ms
}
Никакой универсальности, что получил, то переслал. Естественно UTF8 мимо крокодилит знаками вопроса. Для пересылки сообщений из банка, мне кажется такого достаточно.
Добавляем в планировщик, время ставим как удобно.
Если хочется раскодировать, то достаем кучу чая с печеньем и читаем этот пост, я использую его в другом месте, для пересылки всех писем за сутки. Для ежеминутного он очень тяжелый и может выдать ошибку о превышении размера SMS.
Есть вариант с перекодировкой проще и телеграм отправляет здесь, но смс кириллицей не отправляет
Внимание!!!
Пользователь указывается тот, из под которого будет инициировано подключение ssh к удаленному ресурсу, также следует учесть пользователя под которым будет работать задание в шедуллере Mikrotik. После чего закидываем (простым копипастом содержимого my.pub, там должна быть одна строчка) открытую часть на сервер где требуется авторизация со стороны Mikrotik в файл /home/username/.ssh/authorized_keys (/root/.ssh/authorized_keys - для авторизации под рутом - оч плохая идея)
Собственно все, теперь можно авторизоваться под ssh ключами:
Задача пинговать кастомные зоны на vpn клиентах (openvpn).
При помощи модифицированного скрипта подготовки ovpn файлов я формирую следующую конфигурацию:
client
dev tun
proto tcp-client
remote vpn.mysite.ru
nobind
persist-key
persist-tun
auth-nocache
ca [inline]
cert [inline]
key [inline]
askpass 1.cfg
auth-user-pass stdin
remote-cert-tls server
pull-filter ignore redirect-gateway
dhcp-option DNS 10.111.11.1
dhcp-option ADAPTER_DOMAIN_SUFFIX skzloc,lokihome
route 10.11.11.0 255.255.255.0 10.111.11.1
route 10.110.1.0 255.255.255.0 10.111.11.1
cipher AES-256-CBC
tls-cipher TLS-RSA-WITH-AES-256-CBC-SHA
auth SHA1
Задача из разряда объединение сетей, а точнее - через клиента получить доступ к сети самого клиента. Так как так мы решали задачу доступа сервера Zabbix к узлам, то и роль VPN сервера упала на сервер Zabbix. В качестве поставщика VPN выбрали OpenVPN. В качестве клиента выступает Mikrotik CRS326-24S+2Q+RM
Для понимания общей схемы, на коленке вот такую штуку нарисовал, сразу понятно, что косяк может возникнуть в любом месте
У pfSense есть забавная штука - экспорт конфигурации OpenVPN, такой штуки нет на Mikrotik. Я бы мог использовать pfSense или openSense, но они мне не нравятся, а в некоторых случаях сложны для настройки. Так как в одном из проектов мне волей-неволей придется создавать новых пользователей openVPN, я решил максимально автоматизировать процесс экспорта конфигурации и описал скрипт. Скрипт:
Порой есть задача - запросить данные от пользователя, оказывается в Mikrotik такое тоже возможно. Описал простенькую функцию с параметрами:
# Example:
# :global UserName ""
# $PromtInput QstUser="\r\nInsert new username" VarName="UserName" DefaultValue=UserX LenValue=4
:local PromtInput do={
:local readinput do={:return}
if ($LenValue>0) do={
:set $QstUser ("$QstUser. Minimum length $LenValue simbols")
}
if ([:len $DefaultValue]>0) do={
:set $QstUser ("$QstUser. \r\n(default - $DefaultValue)")
}
:put ("$QstUser:")
:local UserPromt [$readinput]
if ([:len $UserPromt]>0) do={
[:parse "global $VarName;:set $VarName $UserPromt"]
if (($LenValue>0) and [:len $UserPromt]<$LenValue) do={
:error message="You entered only $[:len $UserPromt] symbols instead of $LenValue minimum required. Stop program"
}
} else={
if ([:len $DefaultValue]>0) do={
[:parse "global $VarName;:set $VarName $DefaultValue"]
} else={
:error message="You didn't enter anything. Stop program"
}
}
}
Если добавить рекурсию с вопросом, то можно избежать выхода из программы при вводе неудовлетворяющему требованиям. Но мне не надо, поэтому я пас
Предположим ситуация - необходимо обработать N слов, каждое слово является позиционным параметром некоей функции, сколько слов может быть на входе мы не знаем, но предполагаем что не больше 10. Каким образом обработать параметры? Сначала я подумал о преобразовании текста в код в цикле и обработки его при помощи :parse или :execut как предлагает доблестный rextended:
:global variablename "test"
# Create a global variable using the name inside "variablename" and set the value (or update the value if is already defined)
[:parse ":global $variablename \"REX1\""]
# after "parse" the variable exist and can be displayed
:put $test
# Set a value of variable with name defined inside "variablename" (or simply apply previous "parse" command)
[:parse "global $variablename;:set $variablename \"REX2\""]
:put $test
# For read the value, of a variable with name defined inside "variablename", and put it inside another global or local declared variable:
:global testx [[:parse ":global $variablename; :return \$$variablename"]]
:put $testx
# For read the value, of a variable with name defined inside "variablename", simply for put the value on terminal:
:put [[:parse ":global $variablename; :return \$$variablename"]]
Но, в случае с позиционными параметрами, вариант не прокатил, чет думал-думал (внутренний диалог):
"Вот бы знать сколько их там, в bash то мы знаем"
"Да какая разница сколько их там, все равно цикл с формированием имени переменной не использовать"
"Тогда забей и юзай условной блок с :return"
"Нет, это решение громоздкое и не красивое!....Эврика!, рекурсия со сдвигом параметров!"
Решил я описать скрипт по логике которого, нужно было раскидывать файлы по папкам, и тут выясняется что нельзя взять и создать каталог О_О.
В интернетах предлагают такой вариант
/tool fetch dst-path=MyPath/xxx url="http://127.0.0.1/"
Или такой
/tool fetch dst-path=MyPath/xxx url="http://google.com/"
Но у меня не работает такое, в такой вариант прокатил
/tool fetch dst-path=MyPath/xxx url="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"
Чтобы файл не скачивался, вместо xxx ставим точку
/tool fetch dst-path=MyPath/. url="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"
Поддиректории через слеш
/tool fetch dst-path=MyPath/subFolder/. url="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"
Но такой вариант мне не нравится из-за ненадежности источника скачивания, и я нашел вариант через SMB
/ip smb shares add name=test directory=MyPath
/ip smb shares remove [/ip smb shares find where name=test]
Т.о. для создания структуры, можно описать таким образом
Дорабатывая старый проект я столкнулся с проблемой в топике. Нужно было отправить wol не только с нашего роутера, но и с роутера в другом широковещательном сегменте сети. Скрипт успешно отрабатывал после мытарств, но напрочь отказывался работать при запуске из блока on up профиля ppp. В итоге виновник был найден - разрешения, из-за этого мне пришлось напичкать скрипт выводами в лог (обновленный вариант выложил в старый пост) и описать функцию логирования. Что странно, на моменте тестирования скрипт выполнялся со всеми включенными разрешениями и под пользователем с полными правами, на обоих аппаратах, все равно пришлось установить галку "don't require permissions" в настройках скрипта!
Задача банальна - писать в лог тогда. когда мне это удобно + писать в вывод (на случай ручного запуска скрипта). Первый вариант был в другом скрипте, в новой старой задаче мне понадобилась эта штука, но пришлось доработать.
# Func loging. For debug. Error write forever, other only of WriteLog =>0 (0 1 2 - level logging), setup up of global var
# $TYPE - topics (error,info)
# $LEVEL - level logging
# 0 only error
# 1 main
# 2 all
# $MESSAGE - text message
# Example
# $Logging MESSAGE=("My text") TYPE="info" LEVEL=2
# for use in func use global context and declared WriteLog
# Exmaple
# :global WriteLog
# $Logging MESSAGE=("My text $codeExit") TYPE="info" LEVEL=2
:global WriteLog
:global Logging do={
:global WriteLog
:local TextMessage ("PlugUser => ".$MESSAGE)
:if ($LEVEL<=$WriteLog) do={
:if ($TYPE="info") do={ :log info message=($TextMessage) }
:if ($TYPE="error") do={ :log error message=($TextMessage) }
}
:put $TextMessage
}
Тут фокус в возможности указания уровня логирования. Не забываем в конце удалять глобальную переменную и правила использования функция и переменных в функциях тут
Вот такая странная тема. Мне нужно было передать 2 команды в ssh-exec со значениями из переменных. Собственно с первой командой проблем не было, а вторая либо не выполнялась, либо писала пустоту в лог (команда логирования). Собственно весь фокус в экранировании при использовании синтаксиса :log info message=("")
/system ssh-exec user=adm address=10.21.0.1 command=("tool wol mac=$macAddr interface=bridge1_LAN; :log info message=(\"$RemoteMessage\")")
Как видим, у нас 2 переменных - $macAddr и $RemoteMessage в двух командах, и оно прекрасно выполняется
/system ssh-exec user=vint address=10.21.0.1 command=("tool wol mac=$macAddr interface=bridge1_LAN; :log info message=(\"Send magic packet on mac:$macAddr, for user $patern\")")
Такой вариант тоже прокатывает, но сложнее читать без правильной подсветки
/system ssh-exec user=vint address=10.21.0.1 command=("tool wol mac=$macAddr interface=bridge1_LAN; :log info message=(Send magic packet on mac:$macAddr, for user $patern)")
А вот без кавычек не сработает, вернет пустоту
В Keepass можно настроить открытие той или иной программы по клику на URL, и передать в программу параметрами некоторые данные. Мне захотелось настроить это дело для WinBox. сам Winbox имеет порядковые параметры:
winbox64.exe ADDRESS USERNAME PASSWORD
Как видим, ничего сложного в открытии программы с предопределенными параметрами, теперь добавим это дело в настройки KeePass:
cmd://"%PROGRAMFILES%\Winbox\winbox64.exe" {BASE:RMVSCM} {USERNAME} {PASSWORD}
Предполагается что сам Winbox (x64) находится по пути "\Program Files\Winbox\" и назывется winbox64.exe
Все, теперь в поле URL пишем winbox:\\address и оно будет работать
Для доступа к конечному оборудованию (сервер ssh/rdp/https, сетевое оборудование и т.д. )использую как VPN так и белые списки (iptables and etc). Т.к. гарантировать работу сразу нескольких туннелей представляется сложным, я вынужден, в некоторых случаях (выход с неразрешенного ip), подключаться к конечной точке через промежуточную, подключенную через VPN. Порой хоуп получается тройной или даже четверной вложенности. По сути это получается что-то типа ssh-jump-server. Это очень неудобно для вариантов RDP или же банального веб интерфейса.
Последние два месяца я нахожусь за пределами физического расположения разрешенных IP адресов, и т.к. основной IP у меня белый динамический, я вынужден прописывать по новой каждый раз. Это противоречит цели белых списков, т.к. мы не знаем кому потом будет принадлежать этот ip, так еще и вечные трудозатраты на настройку.
Мне тут предложили использовать SSO и keykloak, но мне показалось что это не то что надо, плюс очень громоздко.
Есть у меня сервер, с воткнутым в него свистком, который принимал смс. По крону смски проверялись и выполнялись определенные операции при поступлении управляющих кодов. Последнее время модем начал глючить, да и баланс уже год не показывает и сервер состарился, а тут еще и wAP LTE освободился. Я точно знаю что можно с него (аппарат на базе R11e-LTE) читать и отправлять SMS, и даже USSD запросы.
Сижу туплю, что за ошибка, ведь в консоли этот фокус прокатил. Добавил:
:put [:typeof $MyVar]
получил, как и ожидал, ответ:
array
- так что ты тогда хочешь?! - негодовал я
В итоге увидел случайно, что я не дописал извлечение элемента массива, я написал так:
:put ($MyVar-"exit-code")
а надо:
:put ($MyVar->"exit-code")
Глаз на столько замылился, что спустя 100+ таких конструкций, перестал замечать
На bash мы можем заглянуть в диспетчер задач (ps) и найти процесс нашей программы, прежде чем ее запускать (здесь рассматривал). На Mikrotik же такого нету, приходится извращаться. Зачем это надо?, если один из экземпляров программы по какой то причине зависнет, а еще он использует глобальные переменные, то мы можем получить неожиданный результат, поэтому лучше избегать таких коллизий.
Сама идея проста - проверить некоторую глобальную переменную, которую создаем после проверки, но у Mikrotik свои заморочки и приходится изгаляться:
# ищем среди глобальных переменных. ошибки здесь не будет, либо "", либо id
# в отличии от поиска через get, там и ошибки, и "не моментальное заполнение" списка,
# т.е. первый экземпляр висит уже 10 сек, а переменные через get еще отсутствуют
:if ([/system script environment find where name=RunProgram]!="") do={
:log error ("There is another instance of the program running, exit")
:error message="There is another instance of the program running, exit"
}
# объявляем глобальную переменную
:global RunProgram true
...
...
...
# уничтожаем переменную
:set RunProgram
Есть более изящный вариант - проверка в текущих заданиях:
:local scriptname "MyScript"
:if ([:len [/system script job find script=$scriptname]] > 0) do={
:log error "There is another instance of the program running, exit"
:error message="There is another instance of the program running, exit"
}