Скрипт, який пише інший скрипт і налаштовує роутери

<img src=«habrastorage.org/files/043/80f/c8a/04380fc8a7fd40d6b3f66428ea7b8b7b.jpg» alt=«image» alt text"/>
Виробники мережевого устаткування потихеньку рухаються в бік універсального API для налаштування і збору показників: NETCONF, OpenConfig, існує для імпорту MIB, та ж налаштування за допомогою SNMP існує давно. Але я не буду торкатися цих високих матерій, а просто поділюся способом автоматизувати налаштування мережевого обладнання – на випадок масового відкриття філій, наприклад,
Для ілюстрації використовую D-Link DFL-800 в уявному центральному офісі та MikroTik RB951UI-2HnD на периферії. Зокрема, налаштуємо між ними тунель IPsec, раз вже мова про сценарій з новим філією.
Налаштування MikroTik
Найпростіше налаштовувати MikroTik з допомогою конфігураційного файлу, який представляє собою скрипт з набором консольних команд. Описуваний принцип налаштування підійде і для інших маршрутизаторів з аналогічним механізмом завдання параметрів.
Перш за все отримаємо конфігураційний файл вже налаштованого і працюючого MikroTik, з допомогою команди /export. Файл буде практично ідентичний бэкапу, але в ньому не буде імен користувачів і MAC-адрес.
Щоб застосувати конфігураційний файл на іншому роутері, частина параметрів потрібно змінити на унікальні. Для цього підійдуть можливості вбудованого в прошивку скриптової мови – зокрема, винесення індивідуальних налаштувань в змінні. Ось приклад скрипту з призначенням шлюзу за замовчуванням:
local Gate "10.1.3.1"

/ip route

:if ([:len [/ip route find distance=1]] = 0) do={add distance=1 gateway=$Gate;

} else={set [find distance=1] gateway=$Gate}

Спочатку була ідея створити універсальний скрипт, який можна застосовувати без скидання конфігурації. Тому в коді проводиться перевірка на наявність маршруту за замовчуванням, після чого він створюється з нуля або змінюється. Але від цієї ідеї довелося відмовитися, оскільки в свіжих прошивках в конфігурації за замовчуванням постійно додаються зміни. Передбачити все нереально, а при постійному оновленні скрипта втрачається сенс автоматизації.
Індивідуальні настройки роутера зручніше задавати не в текстовому файлі, а в GUI – тоді з налаштуванням маршрутизатора впораються навіть незнайомі зі специфікою пристрою люди. Те що потрібно для віддаленого офісу, який можуть обслуговувати працівники різної кваліфікації.
GUI я отрисовываю в скрипті, розробленому на AutoIT. В цей скрипт я також додав функцію перерахунку масок мережі (255.255.255.0 = /24) і порядкове заповнення конфігураційного файлу. Сам інструмент розробки для розв'язання задачі не принциповий – можна використовувати і щось більш звичне особисто вам.
<img src=«habrastorage.org/files/9f4/f4b/9d0/9f4f4b9d0f754870bd031afdbe1563e5.jpg» alt=«image» alt text"/>
Одержаний інтерфейс налаштування
Розберемо докладніше функцію, яка формує вікно.
Для роботи всіх функцій майбутнього конфігуратора потрібні такі бібліотеки, в основному з комплекту AutoIT:
  • RandomString для генерації ключа IPsec (в комплект не входить, авторAltlans;
  • GuiIPAddress форми для введення IP-адрес;
  • GUIConstantsEx для роботи GUI;
  • File-для роботи з файлом.
З принципами роботи з графічним інтерфейсом в AutoIT можна ознайомитися в офіційнійдокументації, я ж відразу перейду до результату:
$hgui = GUICreate("МикроТик" , 300, 600)

GUICtrlCreateLabel("введіть локальний адресу роутера",2,2)

$iploc1 = _GUICtrlIpAddress_Create($hgui, 10, 20)

GUICtrlCreateLabel("введіть локальну маску",2,55)

$iplocnet1 = _GUICtrlIpAddress_Create($hgui, 10, 75)

GUICtrlCreateLabel("введіть зовнішній адреса",2,115)

$ipext1 = _GUICtrlIpAddress_Create($hgui, 10, 135)

GUICtrlCreateLabel("введіть зовнішню маску",2,170)

$ipextnet1 = _GUICtrlIpAddress_Create($hgui, 10, 190)

GUICtrlCreateLabel("введіть шлюз",2,225)

$ipgate1 = _GUICtrlIpAddress_Create($hgui, 10, 245)

GUICtrlCreateLabel("введіть ДНС1",2,280)

$DNS11 = _GUICtrlIpAddress_Create($hgui, 10, 300)

GUICtrlCreateLabel("введіть ДНС2",2,335)

$DNS21 = _GUICtrlIpAddress_Create($hgui, 10, 355)

GUICtrlCreateLabel(", введіть ключ на ипсек",2,390)

$secret1 = GUICtrlCreateInput("",10, 410)

GUICtrlCreateLabel("введіть порти для банку через кому",2,445)

$ports1 = GUICtrlCreateInput("5000,8000",10, 480)

GUICtrlCreateLabel("введіть мак каси через:",2,515)

$mac1 = GUICtrlCreateInput("00:00:00:00:00:00",10, 535)

$OK_Btn = GUICtrlCreateButton("Поїхали", 75, 570, 70, 25)

_GUICtrlIpAddress_Set($iploc1, $iploc8)

_GUICtrlIpAddress_Set($ipext1, $ipext8)

_GUICtrlIpAddress_Set($iplocnet1, "255.255.255.0")

_GUICtrlIpAddress_Set($ipextnet1, "255.255.255.252")

if $secret8 = "" Then

GUICtrlSetData($secret1,_Crypto_GetRandomString(12,7))

Else

GUICtrlSetData($secret1,$secret8)

EndIf

GUISetState(@SW_SHOW)

While 1

$msg = GUIGetMsg()

Select

Case $msg = $GUI_EVENT_CLOSE

Exit

Case $msg = $OK_Btn

;при натисканні кнопки "Поїхали" зчитуємо значення змінних

$iploc=_GUICtrlIpAddress_Get($iploc1)

$iplocnet=_GUICtrlIpAddress_Get($iplocnet1)

$DNS1=_GUICtrlIpAddress_Get($DNS11)

$DNS2=_GUICtrlIpAddress_Get($DNS21)

$ipext=_GUICtrlIpAddress_Get($ipext1)

$ipextnet=_GUICtrlIpAddress_Get($ipextnet1)

$ipgate=_GUICtrlIpAddress_Get($ipgate1)

$secret=GUICtrlRead($secret1)

$ports=GUICtrlRead($ports1)

$mac=GUICtrlRead($mac1)

$iploc2=_GUICtrlIpAddress_GetArray($iploc1)

;в організації адреси банківських терміналів статичні

$ipterm1 = $iploc2[0] & "." &$iploc2[1] & "." &$iploc2[2] & ".210"

$ipterm2 = $iploc2[0] & "." &$iploc2[1] & "." &$iploc2[2] & ".220"

if $iploc = 0 or $iplocnet=0 or $DNS1=0 or $DNS2=0 or $ipext=0 or $ipextnet=0 or $ipgate=0 or StringLen($secret)=0 then

MsgBox(4160, "Information", "поля не заповнені")

else

GUIDelete()

ExitLoop

EndIf

EndSelect

WEnd

Далі логіка роботи програми наступна: новий текстовий файл порядково заповнюється отриманими значеннями за допомогою FileWriteLine. Отриманий скрипт-конфіг можна переносити на MikroTik.
Повний лістинг функції
#include <RandomString.au3>

#include <GuiIPAddress.au3>

#include <GUIConstantsEx.au3>

#include <File.au3>

_mikrot()

func _mikrot ($iploc8="", $secret8="", $ipext8="")

local $file = @TempDir &"\script.txt"

$hgui = GUICreate("МикроТик" , 300, 600)

GUICtrlCreateLabel("введіть локальний адресу роутера",2,2)

$iploc1 = _GUICtrlIpAddress_Create($hgui, 10, 20)

GUICtrlCreateLabel("введіть локальну маску",2,55)

$iplocnet1 = _GUICtrlIpAddress_Create($hgui, 10, 75)

GUICtrlCreateLabel("введіть зовнішній адреса",2,115)

$ipext1 = _GUICtrlIpAddress_Create($hgui, 10, 135)

GUICtrlCreateLabel("введіть зовнішню маску",2,170)

$ipextnet1 = _GUICtrlIpAddress_Create($hgui, 10, 190)

GUICtrlCreateLabel("введіть шлюз",2,225)

$ipgate1 = _GUICtrlIpAddress_Create($hgui, 10, 245)

GUICtrlCreateLabel("введіть ДНС1",2,280)

$DNS11 = _GUICtrlIpAddress_Create($hgui, 10, 300)

GUICtrlCreateLabel("введіть ДНС2",2,335)

$DNS21 = _GUICtrlIpAddress_Create($hgui, 10, 355)

GUICtrlCreateLabel(", введіть ключ на ипсек",2,390)

$secret1 = GUICtrlCreateInput("",10, 410)

GUICtrlCreateLabel("введіть порти для банку через кому",2,445)

$ports1 = GUICtrlCreateInput("5000,8000",10, 480)

GUICtrlCreateLabel("введіть мак каси через:",2,515)

$mac1 = GUICtrlCreateInput("00:00:00:00:00:00",10, 535)

$OK_Btn = GUICtrlCreateButton("Поїхали", 75, 570, 70, 25)

_GUICtrlIpAddress_Set($iploc1, $iploc8)

_GUICtrlIpAddress_Set($ipext1, $ipext8)

_GUICtrlIpAddress_Set($iplocnet1, "255.255.255.0")

_GUICtrlIpAddress_Set($ipextnet1, "255.255.255.252")

if $secret8 = "" Then

GUICtrlSetData($secret1,_Crypto_GetRandomString(12,7))

Else

GUICtrlSetData($secret1,$secret8)

EndIf

GUISetState(@SW_SHOW)

While 1

$msg = GUIGetMsg()

Select

Case $msg = $GUI_EVENT_CLOSE

Exit

Case $msg = $OK_Btn

$iploc=_GUICtrlIpAddress_Get($iploc1)

$iplocnet=_GUICtrlIpAddress_Get($iplocnet1)

$DNS1=_GUICtrlIpAddress_Get($DNS11)

$DNS2=_GUICtrlIpAddress_Get($DNS21)

$ipext=_GUICtrlIpAddress_Get($ipext1)

$ipextnet=_GUICtrlIpAddress_Get($ipextnet1)

$ipgate=_GUICtrlIpAddress_Get($ipgate1)

$secret=GUICtrlRead($secret1)

$ports=GUICtrlRead($ports1)

$mac=GUICtrlRead($mac1)

$iploc2=_GUICtrlIpAddress_GetArray($iploc1)

;в організації адреси банківських терміналів статичні

$ipterm1 = $iploc2[0] & "." &$iploc2[1] & "." &$iploc2[2] & ".210"

$ipterm2 = $iploc2[0] & "." &$iploc2[1] & "." &$iploc2[2] & ".220"

if $iploc = 0 or $iplocnet=0 or $DNS1=0 or $DNS2=0 or $ipext=0 or $ipextnet=0 or $ipgate=0 or StringLen($secret)=0 then

MsgBox(4160, "Information", "поля не заповнені")

else

GUIDelete()

ExitLoop

EndIf

EndSelect

WEnd

$temp1=_Subnet($iploc, $iplocnet)

$iplocnet=$temp1[1]&"/"&$temp1[6]

$temp1=_Subnet($ipext, $ipextnet)

$ipext=$ipext&"/"&$temp1[6]

If Not _FileCreate($file) Then

MsgBox(4096, "Error", "помилка створення тимчасового файлу:" & @error)

EndIf

FileOpen ( $file, 2)

FileWriteLine ( $file, "local locIP """&$iploc&""";")

FileWriteLine ( $file, "local Net """&$iplocnet&""";")

FileWriteLine ( $file, "local DNS1 """& $DNS1 & """;")

FileWriteLine ( $file, "local DNS2 """&$DNS2&""";")

FileWriteLine ( $file, "local IP """&$ipext&"""")

FileWriteLine ( $file, "local Gate """&$ipgate&"""")

FileWriteLine ( $file, "local MAC """&$mac&"""")

FileWriteLine ( $file, "local secret """&$secret&"""")

FileWriteLine ( $file, "local BankPorts """&$ports&""" ")

FileWriteLine ( $file, "local term1 """&$ipterm1&"""")

FileWriteLine ( $file, "local term2 """&$ipterm2&""" ")

FileWriteLine ( $file, '/interface set ether1 name=ether1-gateway;')

FileWriteLine ( $file, '/interface set ether2 name=ether2-master-local;')

FileWriteLine ( $file, '/interface set ether3 name=ether3-slave-local;')

FileWriteLine ( $file, '/interface set ether4 name=ether4-slave-local;')

FileWriteLine ( $file, '/interface set ether5 name=ether5-slave-local;')

FileWriteLine ( $file, '/interface ethernet set ether3-slave-local master-port=ether2-master-local;')

FileWriteLine ( $file, '/interface ethernet set ether4-slave-local master-port=ether2-master-local;')

FileWriteLine ( $file, '/interface ethernet set ether5-slave-local master-port=ether2-master-local;')

FileWriteLine ( $file, '/interface bridge add name=bridge-local disabled=no auto-mac=no protocol-mode=rstp;')

FileWriteLine ( $file, ':local bMACIsSet 0;')

FileWriteLine ( $file, ':foreach k in=[/interface find] do={:local tmpPort [/interface get $k name];')

FileWriteLine ( $file, ':if ($bMACIsSet = 0) do={:if ([/interface get $k type] = "ether") do={/interface bridge set "bridge-local" admin-mac=[/interface ethernet get $tmpPort mac-address];')

FileWriteLine ( $file, ':set bMACIsSet 1;}}')

FileWriteLine ( $file, ':if (!($tmpPort~"bridge" || $tmpPort~"ether1" || $tmpPort~"slave")) do={')

FileWriteLine ( $file, '/interface bridge port add bridge=bridge-local interface=$tmpPort;}} ')

FileWriteLine ( $file, '/interface wireless set [ find name=wlan1 ] band=2ghz-b/g/n channel-width=20/40mhz-Ce country=japan disabled=no distance=indoors mode=ap-bridge ssid=MikroTik wireless-protocol=802.11;')

FileWriteLine ( $file, '/interface wireless security-profiles')

FileWriteLine ( $file, 'set [ find default=yes ] authentication-types=wpa-psk group-ciphers=tkip \')

FileWriteLine ( $file, ' mode=dynamic-keys unicast-ciphers=tkip wpa-pre-shared-key=\')

FileWriteLine ( $file, 'MegaWiFiKey wpa2-pre-shared-key=MegaWiFiKey')

FileWriteLine ( $file, '/ipsec proposal set [ find default=yes ] auth-algorithms=md5 lifetime=1h')

FileWriteLine ( $file, '/ip pool')

FileWriteLine ( $file, 'add name=default-dhcp ranges=("$locIP". "1". "-". "$locIP". "00");')

FileWriteLine ( $file, '/ip, dhcp-server add address-pool=default-dhcp disabled=no interface=bridge-local name=default")

FileWriteLine ( $file, '/ip, dhcp-server add network address=$Net comment="default configuration" dns server="$locIP,8.8.8.8" gateway=$locIP netmask=24')

FileWriteLine ( $file, '/ip dns')

FileWriteLine ( $file, 'set allow remote-requests=yes servers=("$DNS1". ",". "$DNS2")')

FileWriteLine ( $file, '/ip firewall address-list')

FileWriteLine ( $file, ':if ([:len [/ip firewall address-list find list=local]] = 0) do={add address=$Net list=local;')

FileWriteLine ( $file, '} else={set [find list=local] address=$Net;}')

FileWriteLine ( $file, ':if ([:len [/ip firewall address-list find list=office]] = 0) do={add address=10.0.0.0/24 list=office;}') ;локальна мережа офісу

FileWriteLine ( $file, ':if ([:len [/ip firewall address-list find list=remote]] = 0) do={add address=1.2.3.4 list=remote comment=office1.domain.ru;')

FileWriteLine ( $file, 'add address=1.2.3.5 list=remote comment=office2.domain.ru;')

FileWriteLine ( $file, 'add address=10.0.0.0/24 list=remote;}')

FileWriteLine ( $file, '/ip address')

FileWriteLine ( $file, 'add address="$locIP/24" interface=bridge-local')

FileWriteLine ( $file, ':if ([:len [/ip address find interface=ether1-gateway]] = 0) do={add address=$IP interface=ether1-gateway;')

FileWriteLine ( $file, '} else={set [find interface=ether1-gateway] address=$IP;}')

FileWriteLine ( $file, '/ip route')

FileWriteLine ( $file, ':if ([:len [/ip route find distance=1]] = 0) do={add distance=1 gateway=$Gate;')

FileWriteLine ( $file, '} else={set [find distance=1] gateway=$Gate}')

FileWriteLine ( $file, ':delay 1000ms;')

FileWriteLine ( $file, '/ipsec peer')

FileWriteLine ( $file, '/ipsec proposal set default auth-algorithms=md5 enc-algorithms=3des')

FileWriteLine ( $file, ':if ([:len [/ipsec peer find lifetime=8h]] = 0) do={add address=1.2.3.4/32 lifetime=8h nat-traversal=yes secret=$secret enc-algorithm=3des hash-algorithm=md5 comment=office;')

FileWriteLine ( $file, '} else={set [/ipsec peer find lifetime=8h] address=1.2.3.5/32 nat-traversal=yes secret=$secret enc-algorithm=3des hash-algorithm=md5 comment=office;}')

FileWriteLine ( $file, '/ipsec policy')

FileWriteLine ( $file, '/ipsec proposal set default auth-algorithms=md5 enc-algorithms=3des')

FileWriteLine ( $file, ':if ([:len [/ipsec policy find dst-address=10.0.0.0/24]] = 0) do={add dst-address=10.0.0.0/24 sa-dst-address=188.93.243.170 sa-src-address=[/ip route get [find gateway=ether1-gateway] pref-src] src-address=$Net tunnel=yes comment=office proposal=default;')

FileWriteLine ( $file, '} else={set [find dst-address=10.0.0.0/24] sa-dst-address=1.2.3.4 sa-src-address =[/ip route get [find gateway=ether1-gateway] pref-src] src-address=$Net tunnel=yes comment=office;} ')

FileWriteLine ( $file, '/ip service')

FileWriteLine ( $file, 'set telnet disabled=yes')

FileWriteLine ( $file, 'set ftp disabled=yes')

FileWriteLine ( $file, 'set www port=80')

FileWriteLine ( $file, 'set api disabled=yes')

FileWriteLine ( $file, 'set api-ssl disabled=yes')

FileWriteLine ( $file, 'set www-ssl disabled=yes')

FileWriteLine ( $file, '/system clock manual')

FileWriteLine ( $file, 'set time-zone=+03:00')

FileWriteLine ( $file, '/system leds')

FileWriteLine ( $file, 'set 0 interface=wlan1')

FileWriteLine ( $file, '/system ntp client')

FileWriteLine ( $file, 'set enabled=yes primary-ntp=61.67.210.241 secondary-ntp=205.171.76.135')

FileWriteLine ( $file, '/system script')

FileWriteLine ( $file, ':if ([:len [/system find script name=ipsec]] != 0) do={')

FileWriteLine ( $file, 'remove ipsec')

FileWriteLine ( $file, '}')

;скрипт перемикання IPsec резервного провайдера.

;заодно keepalive і резолвер офісних адрес

;до купи перевірка на помилки

FileWriteLine ( $file, 'add name=ipsec policy=reboot,read,write,policy,test,password,sniff,sensitive \')

FileWriteLine ( $file, ' source=":local RemoteGw \"локальний адресу DFL\";\r\')

FileWriteLine ( $file, ' \n:local LocalGw [/ip route get [find gateway=\"bridge-local\"] pref-src];\')

FileWriteLine ( $file, ' \r\')

FileWriteLine ( $file, '\n:local currentIP [/ip route get [find gateway=\"ether1-gateway\"] pref-s')

FileWriteLine ( $file, ' rc];\r\')

FileWriteLine ( $file, ' \n:local Ip1 [:resolve office1.domain.ru];\r\')

FileWriteLine ( $file, ' \n:local Ip2 [:resolve office2.domain.ru];\r\')

FileWriteLine ( $file, ' \n### Check office IPs ###\r\')

FileWriteLine ( $file, ' \n:local Ip [/ip firewall address-get list [find comment=office1.dom\')

FileWriteLine ( $file, ' ain.ru] address];\r\')

FileWriteLine ( $file, ' \n:if (\$Ip!=\$Ip2) do={\r\')

FileWriteLine ( $file, ' \n/ip firewall address-list set [find comment=office1.domain.ru] addr\')

FileWriteLine ( $file, ' ess=\$Ip2;\r\')

FileWriteLine ( $file, ' \n}\r\')

FileWriteLine ( $file, ' \n:Ip set [/ip firewall address-get list [find comment=office2.domain\')

FileWriteLine ( $file, ' .ru] address];\r\')

FileWriteLine ( $file, ' \n:if (\$Ip!=\$Ip1) do={\r\')

FileWriteLine ( $file, ' \n/ip firewall address-list set [find comment=office2.domain.ru] addr\')

FileWriteLine ( $file, ' ess=\$Ip1;\r\')

FileWriteLine ( $file, ' \n}\r\')

FileWriteLine ( $file, ' \n### Check ipsec status ###\r\')

FileWriteLine ( $file, ' \n:local Status [/ping \$RemoteGw count=1 src-address=\$LocalGw];\r\')

FileWriteLine ( $file, ' \n### ipsec is down ###\r\')

FileWriteLine ( $file, ' \n:if (\$Status=0) do={\r\')

FileWriteLine ( $file, ' \n### ping Ip2 and Ip1 ###\r\')

FileWriteLine ( $file, ' \n:local StatusIp1 [/ping \$Ip1 count=2 src-address=\$currentIP];\r\')

FileWriteLine ( $file, ' \n:local StatusIp2 [/ping \$Ip2 count=2 src-address=\$currentIP];\r\')

FileWriteLine ( $file, ' \n:if (\$StatusIp1>0 or \$StatusIp2>0) do={\r\')

FileWriteLine ( $file, ' \n:if (\$StatusIp1>0) do={\r\')

FileWriteLine ( $file, ' \n### Ping Ip1 ok ###\r\')

FileWriteLine ( $file, ' \n/ipsec policy set [find sa-dst-address=\$Ip2] sa-dst-address \$Ip1;\r\')

FileWriteLine ( $file, ' \n/ipsec peer set [find address=\"\$Ip2/32\"] address \"\$Ip1/32\";\r\')

FileWriteLine ( $file, ' \n:log info (\"Reset tunnel: Status IP Office1: \$StatusIp1\");\r\')

FileWriteLine ( $file, ' \n} else={\r\')

FileWriteLine ( $file, ' \n### Ping Ip1 NOT ok ###\r\')

FileWriteLine ( $file, ' \n/ipsec policy set [find sa-dst-address=\$Ip1] sa-dst-address \$Ip2;\r\')

FileWriteLine ( $file, ' \n/ipsec peer set [find address=\"\$Ip1/32\"] address \"\$Ip2/32\";\r\')

FileWriteLine ( $file, ' \n:log info (\"Reset tunnel: Status IP Office2: \$StatusIp2\");\r\')

FileWriteLine ( $file, ' \n}\r\')

FileWriteLine ( $file, ' \n/ipsec installed-sa flush;\r\')

FileWriteLine ( $file, ' \n/ipsec remote-peers kill-connections;\r\')

FileWriteLine ( $file, ' \n:local Status [/ping \$RemoteGw count=2 src-address=\$LocalGw];\r\')

FileWriteLine ( $file, ' \n:if (\$Status=0) do={\r\')

FileWriteLine ( $file, ' \n:log info (\"check for misconfiguration\");\r\')

FileWriteLine ( $file, ' \n### Check local IP ###\r\')

FileWriteLine ( $file, ' \n:Ip set [/ipsec policy get [find comment=office] sa-src-address];\r\')

FileWriteLine ( $file, ' \n:if (\$Ip!=\$currentIP) do={\r\')

FileWriteLine ( $file, ' \n/ipsec policy set [find comment=office] sa-src-address=\$currentIP;\r\')

FileWriteLine ( $file, ' \n:log info (\"misconfiguration: policy, local address\");\r\')

FileWriteLine ( $file, ' \n}\r\')

FileWriteLine ( $file, ' \n### Check remote IP ###\r\')

FileWriteLine ( $file, ' \n:Ip set [/ipsec policy get [find comment=office] sa-dst-address];\r\')

FileWriteLine ( $file, ' \n:if (\$Ip!=\$Ip1 and \$Ip!=\$Ip2) do={\r\')

FileWriteLine ( $file, ' \n:if (\$StatusIp1>0) do={\r\')

FileWriteLine ( $file, ' \n/ipsec policy set [find comment=office] sa-dst-address=\$Ip1;\r\')

FileWriteLine ( $file, ' \n} else={/ipsec policy set [find comment=office] sa-dst-address=\$Ip2;\')

FileWriteLine ( $file, ' }\r\')

FileWriteLine ( $file, ' \n:log info (\"misconfiguration: policy, remote address\");\r\')

FileWriteLine ( $file, ' \n}\r\')

FileWriteLine ( $file, ' \n:Ip set [/ipsec peer get [find comment=office] address];\r\')

FileWriteLine ( $file, ' \n:if (\$Ip!=\$Ip1.\"/32\" and \$Ip!=\$Ip2.\"/32\") do={\r\')

FileWriteLine ( $file, ' \n:if (\$StatusIp1>0) do={\r\')

FileWriteLine ( $file, ' \n/ipsec peer set [find comment=office] address=\$Ip1;\r\')

FileWriteLine ( $file, ' \n} else={/ipsec peer set [find comment=office] address=\"\$Ip1/32\";}\r\')

FileWriteLine ( $file, ' \n:log info (\"misconfiguration: peer\");\r\')

FileWriteLine ( $file, ' \n}\r\')

FileWriteLine ( $file, ' \n} else={:log info (\"Ipsec tunnel status: OK\");}\r\')

FileWriteLine ( $file, ' \n} else={:log info (\"Ipsec tunnel status: Office is DOWN!\");}\r\')

FileWriteLine ( $file, ' \n} else={:log info (\"Ipsec tunnel status: OK\");}"')

;резолвер ntp, в нових прошивках неактуальний

FileWriteLine ( $file, ':if ([:len [/system find script name=ntp]] != 0) do={')

FileWriteLine ( $file, 'remove ntp')

FileWriteLine ( $file, '}')

FileWriteLine ( $file, 'add name=ntp policy=\')

FileWriteLine ( $file, 'ftp,reboot,read,write,policy,test,password,sniff,sensitive source=":local \')

FileWriteLine ( $file, 'ntp1 [:resolve pool.ntp.org];\r\')

FileWriteLine ( $file, '\n:local ntp2 [:resolve time.windows.com];\r\')

FileWriteLine ( $file, '\n:local Ip [/system ntp client get primary-ntp];\r\')

FileWriteLine ( $file, '\n:if (\$Ip!=\$ntp1) do={\r\')

FileWriteLine ( $file, '\n/system ntp client set primary-ntp=\$ntp1;\r\')

FileWriteLine ( $file, '\n}\r\')

FileWriteLine ( $file, '\n:Ip set [/system ntp client get secondary-ntp];\r\')

FileWriteLine ( $file, '\n:if (\$Ip!=\$ntp2) do={\r\')

FileWriteLine ( $file, '\n/system ntp client set secondary-ntp=\$ntp2;\r\')

FileWriteLine ( $file, '\n}"')

FileWriteLine ( $file, '/system scheduler')

FileWriteLine ( $file, ':if ([:len [/system scheduler find name=ipsec-test]] = 0) do={')

FileWriteLine ( $file, 'add interval=3m name=ipsec-test on-event="/system run script ipsec" policy=\')

FileWriteLine ( $file, 'reboot,read,write,policy,test,password,sniff,sensitive')

FileWriteLine ( $file, ' }')

FileWriteLine ( $file, ':if ([:len [/system scheduler find name=ntp]] = 0) do={')

FileWriteLine ( $file, 'add interval=1d name=ntp on-event="/system run script ntp" policy=\')

FileWriteLine ( $file, 'reboot,read,write,policy,test,password,sniff,sensitive')

FileWriteLine ( $file, ' }')

FileWriteLine ( $file, '/ip nat firewall')

FileWriteLine ( $file, 'add chain=srcnat comment=ipsec dst-address-list=office out-interface=\')

FileWriteLine ( $file, 'ether1-gateway src-address-list=local')

FileWriteLine ( $file, 'add action=masquerade chain=srcnat comment=bank1 src-address=$term1 dst-port=$BankPorts out-interface=ether1-gateway protocol=tcp disable=yes')

FileWriteLine ( $file, 'add action=masquerade chain=srcnat comment=bank2 src-address=$term2 dst-port=$BankPorts out-interface=ether1-gateway protocol=tcp disable=yes')

FileWriteLine ( $file, 'add action=masquerade chain=srcnat comment="outbound icmp" out-interface=\')

FileWriteLine ( $file, 'ether1-gateway protocol=icmp')

FileWriteLine ( $file, 'add action=masquerade chain=srcnat comment="default configuration" disabled=\')

FileWriteLine ( $file, 'yes out-interface=ether1-gateway')

FileWriteLine ( $file, '/ip firewall filter')

FileWriteLine ( $file, 'add chain=input comment="remote admin" dst-port=80,22,8291 src-address-list=remote in-interface=\')

FileWriteLine ( $file, 'ether1-gateway protocol=tcp')

FileWriteLine ( $file, 'add chain=input comment=icmp protocol=icmp')

FileWriteLine ( $file, 'add chain=input comment="established, related" connection-state=established')

FileWriteLine ( $file, 'add chain=input connection-state=related')

FileWriteLine ( $file, 'add action=drop chain=input comment="drop other" in-interface=ether1-gateway')

FileWriteLine ( $file, 'add chain=forward comment="established, related" connection-state=established')

FileWriteLine ( $file, 'add chain=forward connection-state=related')

FileWriteLine ( $file, 'add action=drop chain=forward comment="drop other" connection-state=invalid')

FileWriteLine ( $file, '/ip, dhcp-server lease')

FileWriteLine ( $file, ':if ([:len [/ip, dhcp-server lease find address=("$locIP". "1")]]>0) do={')

FileWriteLine ( $file, 'set [/ip, dhcp-server lease find address=("$locIP". "1")] address=("$locIP". "1") mac-address=$MAC;}')

FileWriteLine ( $file, ':if ([:len [/ip, dhcp-server lease find address=("$locIP". "1")]] = 0) do={add address=("$locIP". "1") mac-address=$MAC;}')

FileWriteLine ( $file, '/user')

FileWriteLine ( $file, 'set [find name=admin] password=MegaPassW0rd')

fileclose($file)

run("notepad "&$file)

EndFunc

;функція для перерахунку підмереж.

Func _Subnet($sIp, $sNetmask)

Dim $netmaskbinary

Dim $subnetaddarray[5]

Dim $invmaskarray[5]

Dim $broadcastaddarray[5]

Dim $sSubnetinfo[7]

Dim $subnetadd

Dim $invmask

Dim $broadcastadd

; Reads IP and Netmask to an array

$iparray = StringSplit($sIp, ".")

$netmaskarray = StringSplit($sNetmask, ".")

; Validates IP address

For $i = 1 To 4

If Number($iparray[$i]) < 0 Or Number($iparray[$i]) > 255 Then

SetError(1)

Return (-1)

EndIf

Next

; Converts netmask into a decimal

$netmaskdec = ($netmaskarray[1] * 16777216) + ($netmaskarray[2] * 65536) + ($netmaskarray[3] * 256) + $netmaskarray[4]

; Converts decimal netmask into binary (ex. 11111111111111111100000000000000)

While $netmaskdec <> 0

$binmod = Mod($netmaskdec, 2)

$netmaskbinary = $binmod & $netmaskbinary

$netmaskdec = Int($netmaskdec / 2)

WEnd

; Determines the "slash" value of the netmask

$maskslash = StringInStr($netmaskbinary, "0", 1) - 1

; Validates the "slash" value and value netmask

If StringInStr(StringRight($netmaskbinary, 32 - $maskslash), "1") Then

If $netmaskarray[4] = "255" Then

$maskslash = 32

Else

SetError(1)

Return (-1)

EndIf

EndIf

; Creates arrays conatining subnet address, wilcard, and broadcast addresses

For $i = 1 To $iparray[0]

$subnetaddarray[$i] = BitAND($iparray[$i], $netmaskarray[$i])

$invmaskarray[$i] = BitNOT($netmaskarray[$i] - 256)

$broadcastaddarray[$i] = BitOR($subnetaddarray[$i], $invmaskarray[$i])

Next

; Creates strings conatining subnet address, wilcard, and broadcast addresses

$subnetadd = $subnetaddarray[1] & "." & $subnetaddarray[2] & "." & $subnetaddarray[3] & "." &$subnetaddarray[4]

$invmask = $invmaskarray[1] & "." & $invmaskarray[2] & "." & $invmaskarray[3] & "." & $invmaskarray[4]

$broadcastadd = $broadcastaddarray[1] & "." & $broadcastaddarray[2] & "." & $broadcastaddarray[3] & "." & $broadcastaddarray[4]

If $maskslash = 32 Then

$iprange = $iparray[1] & "." & $iparray[2] & "." & $iparray[3] & "." & $iparray[4]

$hosts = 1

Else

; Determines the IP range for this subnet

$iprange = $subnetaddarray[1] & "." & $subnetaddarray[2] & "." & $subnetaddarray[3] & "." & $subnetaddarray[4] + 1 & _

"-" & $broadcastaddarray[1] & "." & $broadcastaddarray[2] & "." & $broadcastaddarray[3] & "." & $broadcastaddarray[4] - 1

; Calculates number of available hosts on this subnet

$hosts = ($invmaskarray[4] + 1) * ($invmaskarray[3] + 1) * ($invmaskarray[2] + 1) * ($invmaskarray[1] + 1) - 2

EndIf

$sSubnetinfo[1] = $subnetadd

$sSubnetinfo[2] = $broadcastadd

$sSubnetinfo[3] = $invmask

$sSubnetinfo[4] = $iprange

$sSubnetinfo[5] = $hosts

$sSubnetinfo[6] = $maskslash

Return ($sSubnetinfo)

EndFunc

Func _SameSub($sIp, $sSubadd, $sBroadadd)

Dim $iparray[5]

Dim $subaddarray[5]

Dim $broadaddarray[5]

$iparray = StringSplit($sIp, ".")

$subaddarray = StringSplit($sSubadd, ".")

$broadaddarray = StringSplit($sBroadadd, ".")

For $i = 1 To 4

If Number($iparray[$i]) < 0 Or Number($iparray[$i]) > 255 Then

SetError(1)

Return (-1)

EndIf

If Number($subaddarray[$i]) < 0 Or Number($subaddarray[$i]) > 255 Then

SetError(1)

Return (-2)

EndIf

If Number($broadaddarray[$i]) < 0 Or Number($broadaddarray[$i]) > 255 Then

SetError(1)

Return (-3)

EndIf

Next

$ipint = ($iparray[1] * 16777216) + ($iparray[2] * 65536) + ($iparray[3] * 256) + $iparray[4]

$subaddint = ($subaddarray[1] * 16777216) + ($subaddarray[2] * 65536) + ($subaddarray[3] * 256) + $subaddarray[4]

$broadaddint = ($broadaddarray[1] * 16777216) + ($broadaddarray[2] * 65536) + ($broadaddarray[3] * 256) + $broadaddarray[4]

If $ipint > $subaddint And $ipint < $broadaddint Then

Return (1)

Else

Return (0)

EndIf

EndFunc

Залишилося виконати на MikroTik одержаний скрипт після скидання конфігурації, будь-яким зручним способом: через /system script, використовувати збережений файл і скинути конфігурацію так, як показано на малюнку:
<img src=«habrastorage.org/files/cec/677/1c5/cec6771c51224a5fa7a517ddda4eb847.jpg» alt=«image» alt text"/>
Тепер для налаштування нового MikroTik досить запустити програму, вказати індивідуальні настройки в GUI, отримати скрипт налаштування і передати його маршрутизатора. Залишилося довести до розуму налаштування маршрутизатора в передбачуваному центральному офісі.
Параметри D-Link DFL
Налаштування DFL зручніше проводити через консоль. Такий тип установки теж піддається автоматизації, наприклад з використанням інструменту Plink від творця Putty.
Концепцію передачі команд у відкрите консольне не можна назвати ідеальною, але у випадку з D-Link DFL можна використовувати його власні "скрипти". В якості прикладу розглянемо функцію, яку використовую у парі з раніше описаною. Якщо MikroTik потрібно налаштовувати з нуля, то на DFL достатньо створити тунель IPsec і включити його в групу інтерфейсів для застосування правил вбудованого брандмауера.
<img src=«habrastorage.org/files/1b2/cfb/d8f/1b2cfbd8fc1048288be4f484c65fb745.jpg» alt=«image» alt text"/>
Вікно налаштувань помітно простіше, адже DFL в нашому випадку не потрібно налаштовувати з нуля
Для доступу до маршрутизатора по SSH знадобиться Plink, а також Pscp для передачі файлів – досить просто прописати в скрипті шляху до виконуваних файлів.
local $_plink_loc = "\\server\share\plink.exe"

local $scploc="\\server\share\pscp.exe"

При роботі Plink і Pscp є особливість: якщо використовується парольний авторизація, то при першому підключенні або заміні обладнання з'явиться запит про внесення відбитка в реєстр. Обійти запит можна передачею "Y" в консольне вікно.
$_plinkhandle = Run(@comspec & " /c " & $_plink_loc & " -ssh admin@" & $_plinkserver &" -pw MegaPass","",@SW_HIDE,7)

sleep (500)

StdinWrite($_plinkhandle, "y"& @CR)

DFL працює з об'єктами на рівні груп. Так як не можна додати об'єкт до групи без перерахування всіх її членів, я генерую на DFL створює групу скрипт, забираю його у вигляді файлу і зраджую. Створити скрипт можна такою командою:
script -create InterfaceGroup VPNs -name=vpns.sgs

Результат можна забрати з SCP. Файл я переименовываю у script.sgs і додаю в нього інші команди для створення нових об'єктів, після чого імпортують результат на D-Link по SCP і застосовую конфігурацію.
script -execute -name=script.sgs

Після застосування конфігурації вже непотрібний скрипт можна видалити командою
script -remove -name=script.sgs

Повний лістинг функції
func _dfl($lanip8="",$PSK8="",$ipext8="")

local $file = @TempDir &"\script.sgs"

local $file1 = @TempDir &"\script1.sgs"

if FileExists($file) then

FileDelete($file)

EndIf

if FileExists($file1) then

FileDelete($file1)

EndIf

;шляху до програм. при бажанні можна закомпилировать всередину

local $_plink_loc = "\\server\share\plink.exe"

local $scploc="\\server\share\pscp.exe"

Local $_plinkserver = "адреса DFL"

local $magazname

local $magaznumber

local $lanip

local $ipext

local $PSK

$hgui = GUICreate("налаштування DFL" , 300, 270)

GUICtrlCreateLabel("введіть локальний адресу роутера магаза",2,2)

$lanip1 = _GUICtrlIpAddress_Create($hgui, 10, 20)

GUICtrlCreateLabel("введіть зовнішній адреса",2,45)

$ipext1 = _GUICtrlIpAddress_Create($hgui, 10, 65)

GUICtrlCreateLabel(", введіть ключ на ипсек",2,90)

$secret1 = GUICtrlCreateInput("",10, 110)

GUICtrlCreateLabel("введіть назву магазину транслітом",2,130)

$name1=GUICtrlCreateInput("",10, 150)

GUICtrlCreateLabel("введіть номер магазину (77 або NN88)",2,170)

$number1=GUICtrlCreateInput("",10, 190)

$OK_Btn = GUICtrlCreateButton("Поїхали", 75,230 , 70, 25)

if $PSK8 = "" Then

GUICtrlSetData($secret1,_Crypto_GetRandomString(12,7))

Else

GUICtrlSetData($secret1,$PSK8)

EndIf

_GUICtrlIpAddress_Set($ipext1, $ipext8)

_GUICtrlIpAddress_Set($lanip1, $lanip8)

GUISetState(@SW_SHOW)

While 1

$msg = GUIGetMsg()

Select

Case $msg = $GUI_EVENT_CLOSE

Exit

Case $msg = $OK_Btn

$lanip=_GUICtrlIpAddress_Get($lanip1)

$ipext=_GUICtrlIpAddress_Get($ipext1)

$PSK=GUICtrlRead($secret1)

$magazname=GUICtrlRead($name1)

$magaznumber=GUICtrlRead($number1)

$lanip2=_GUICtrlIpAddress_GetArray($lanip1)

;перевірки на дурня 

if $lanip = 0 or $ipext=0 or StringLen($PSK)=0 then

MsgBox(4160, "Information", "поля не заповнені")

else

if StringRegExp($magazname,"[0-9a-zA-Z_]") =0 then

MsgBox(4160, "Information", "ім'я транслітом!")

Else

if $lanip2[3]<>1 Then

MsgBox(4160, "Information", "локальний адресу роутера на .1 повинен кінчатися!")

Else

GUIDelete()

ExitLoop

EndIf

EndIf

EndIf

EndSelect

WEnd

$_plinkhandle = Run(@comspec & " /c " & $_plink_loc & " -ssh admin@" & $_plinkserver &" -pw MegaPass","",@SW_HIDE,7)

sleep (500)

;DFL іноді змінюються. погодимося з оновленням ключів в реєстрі.

;Краще звичайно міняти ключі в реєстрі або використовувати сертифікати, але...

StdinWrite($_plinkhandle, "y"& @CR)

sleep (500)

StdinWrite($_plinkhandle, "script -remove -name=vpns.sgs "& @CR)

sleep (500)

StdinWrite($_plinkhandle, "script -remove -name=script.sgs "& @CR)

sleep (500)

;потрібно буде включити користувача в групу - заберемо її.

StdinWrite($_plinkhandle, "script -create InterfaceGroup VPNs -name=vpns.sgs "& @CR)

sleep (500)

StdinWrite($_plinkhandle, "Exit " & @CR)

sleep (250)

ProcessClose("plink.exe")

RunWait(@comspec & " /c " & $scploc & " -pw MegaPass admin@"&$_plinkserver&":script/vpns.sgs " & $file,"",@SW_HIDE,7)

$line = FileReadLine($file,1)

local $lannet=StringMid($lanip,1,StringLen($lanip)-1)&"0/24"

FileOpen ( $file, 2)

FileWriteLine ( $file, "cc AddressFolder VpnAdresses")

FileWriteLine ( $file, "add IP4Address Pool"&$magaznumber&"_"&$magazname&" Address="&$lannet&" -silent")

FileWriteLine ( $file, "add IP4Address Ip"&$magaznumber&"_"&$magazname&" Address="&$ipext&" -silent")

FileWriteLine ( $file, "add IP4Address Router"&$magaznumber&"_"&$magazname&" Address="&$lanip&" -silent")

FileWriteLine ( $file, "cc ..")

FileWriteLine ( $file, "add PSK Key_"&$magaznumber&"_"&$magazname&" Type=ASCII PSKAscii="&$PSK&" Comments="&$PSK&" -silent")

;для нових DFL синтаксис зміниться

FileWriteLine ( $file, "add IPsecTunnel Magaz_"&$magazname&" LocalNetwork=InterfaceAddresses/lannet RemoteNetwork=VpnAdresses/Pool"&$magaznumber&"_"&$magazname&" RemoteEndpoint=VpnAdresses/Ip"&$magaznumber&"_"&$magazname&" IKEAlgorithms=High IPsecAlgorithms=High AuthMethod=PSK PSK=Key_"&$magaznumber&"_"&$magazname&" PFS=PFS KeepAlive=Manual KeepAliveSourceIP=VpnAdresses/Router_Main KeepAliveDestinationIP=VpnAdresses/Router"&$magaznumber&"_"&$magazname&" index=57 -silent")

$line=StringReplace ( $line, "add", "set" ,1,1 )

$line=StringReplace ( $line, " -silent", "" ,1,1 )

$line=StringReplace ( $line, " -force", "" ,1,1 )

$line=_StringInsert($line, ", "& "Magaz_"&$magazname, -1)

FileWriteLine ( $file, $line)

FileCLose($file)

FileCopy($file,$file1)

RunWait(@comspec & " /c " & $scploc & " -pw MegaPass " & $file1 & " admin@"&$_plinkserver&":script/script.sgs","",@SW_HIDE,7)

$_plinkhandle = Run(@comspec & " /c " & $_plink_loc & " -ssh admin@" & $_plinkserver &" -pw QfJatp123","",@SW_HIDE,7)

sleep (500)

StdinWrite($_plinkhandle, "script -execute -name=script.sgs "& @CR)

sleep (250)

StdinWrite($_plinkhandle, "activate "& @CR)

sleep (10000)

StdinWrite($_plinkhandle, "commit "& @CR)

sleep (250)

StdinWrite($_plinkhandle, "exit "& @CR)

sleep (250)

ProcessClose("plink.exe")

EndFunc

до Речі, в процесі виявилося рішення для резервного копіювання конфігурації.
Пасхалка: резервне копіювання D-Link DFL
У процесі налагодження докорінно структури DFL виявилися два файлу: full.bak та config.bak. Нескладно здогадатися, що це повний бекап системи і копія конфігурації. Для створення повноцінної резервної копії пристрою достатньо підключитися по SCP і скопіювати обидва файлу. В цьому ж скрипті резервного копіювання можна написати щось на кшталт політики зберігання – видаляти файли старше двох тижнів.
#include <Date.au3>

#Include <File.au3>

Local $_plinkserver = "адреса dfl"

local $scploc="\\server\share\pscp.exe"

local $path=@ScriptDir&"\"

$date1=@YEAR&@MON&@MDAY

local $file = $path &"config-"&$date1&".bak"

$handle=Run(@comspec & " /c " & $scploc & " -pw MegaPass admin@"&$_plinkserver&":config.bak " & $file,"",@SW_HIDE,7)

sleep (500)

StdinWrite($_plinkhandle, "y"& @CR)

sleep (500)

$file = $path &"full-"&$date1&".bak"

RunWait(@comspec & " /c " & $scploc & " -pw MegaPass admin@"&$_plinkserver&":full.bak " & $file,"",@SW_HIDE,7)

;чистимо старі бекапи

;якщо бекапів немає, то краще нічого не чистити

if FileExists($path &"full-"&$date1&".bak") and FileExists($file = $path &"config-"&$date1&".bak") Then

$files = _FileListToArray($path, ".*.bak", 1,True)

$date=@YEAR&"/"&@MON&"/"&@MDAY

$newdate=_DateAdd("D",-14,$date)

$formatdate=StringSplit($newdate,"/")

$newdate=$formatdate[1]&$formatdate[2]&$formatdate[3]&@HOUR&@MIN&@SEC

If IsArray($files) Then

For $i = 1 To UBound($files) - 1

$aTime = FileGetTime( $files[$i], 0, 1)

If $aTime < $newdate Then 

FileDelete($files[$i])

EndIf

Next

EndIf

EndIf

<img src=«habrastorage.org/files/e56/3d9/562/e563d95629e0446582c83c8292bae3c3.jpg» alt=«image» alt text"/>
Скрипт успішно бэкапит будь-які моделі DFL.
Разом
Звичайно, ці два способи налаштування не претендують на кращі практики, а хтось навіть назве їх милицями. Для невеликих і разових змін конфігурації простіше використовувати SNMP або спеціальний API від виробника. Але навіть винахід свого велосипеда заощадила масу часу на прохання допомогти з налаштуванням від раніше не працювали з Mikrotik колег. Знову ж таки, менше шанс помилитися.
Якщо вам доводилося використовувати такі способи спрощеної налаштування для інших пристроїв – поділіться рецептами з колегами!
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.