Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 5
×

Скрипт автосинхронизации firewall Mikrotik с UA реестром запрещенных сайтов

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

По быстрому накодил скрипт для счастливых обладателей Mikrotik, дабы в автоматическом режиме синхронизировать (патчингом) его список адресов firewall с удаленным реестром uablacklist.net и по желанию, в случае изменений оповестить по мылу и конечно же в консоль. Хотя сомневаюсь, что он часто будет обновляться :) Делает простой reject icmp-host-unreachable для списка. Натравить можно в любое место, где есть файл-список IP, т.е если там будут лежать IP рекламных сетей... К сожалению, пока тот реестр не покрывает зеркала, по этому можно использовать и только локальную базу, без синхронизации, убрав url и дописав ручками IP в файл. Адреса в файле должны разделены символом \n (не \r\n)
P.S Осталось выиграть тендер на 2 млрд$ xD (dou.ua/forums/topic/20656)

 #Created by Dmitriy Mozgovoy on 24.05.2017.
   :local maxEntriesCount 1024;
   :local listName "UA-BLACKLIST"
   :local tempFile "ips.txt"
   :local apiPath "https://uablacklist.net/ips.txt";
   :local destMail "[email protected]";

   :if ( $apiPath!="") do={
     /log info "fetching UA blacklist registry ($apiPath)...";
     /tool fetch url=$apiPath dst-path=$tempFile 
   }
   :local counter 0;
   :local ipList [:toarray ""];
   :local added [:toarray ""];
   :local removed [:toarray ""];
   :local lineEnd 0;
   :local line "";
   :local lastEnd 0;
   :if ( [/file get [/file find name=$tempFile] size] > 0 ) do={
   :put "Analyzing...";
   /log info "Analyzing data in [$tempFile]..."
   :local rule [/ip firewall filter find dst-address-list=$listName]
   :if ([:len $rule]=0)  do={
     /log info "firewall rule not found. Adding...";
     /ip firewall filter add chain=forward dst-address-list="$listName" comment="rule for $listName" action=reject reject-with=icmp-host-unreachable place-before=0;
   }
   :local content [/file get [/file find name=$tempFile] contents] ;
   :local contentLen [ :len $content ] ;
   :do {
       :set $counter (counter+1);
       :set lineEnd [:find $content "\n" $lastEnd ] ;
       :if ($lineEnd < $lastEnd) do={
            :set $lineEnd $contentLen;
       }
       :set line [:pick $content $lastEnd $lineEnd] ;
       :set lastEnd ( $lineEnd + 1 ) ; 
        :if (  [:len $line] > 0 )  do={        
           :set $ipList ($ipList, $line);
           :if ( [:len [/ip firewall address-list find address=$line list=$listName]] =0 ) do={
                   /ip firewall address-list add list="$listName" address="$line";
                   :set $added ($added, $line);
                   #/log warning "New IP ($line) added to $listName";
           }
        } 
    } while ($lineEnd < $contentLen && $counter < $maxEntriesCount )
   }
/ip firewall address-list
:foreach x in=[find list=$listName] do={
   :local addr [get $x address];
   :local found false;
   :foreach ip in=$ipList do={
       :if ( $ip=addr ) do={
         :set found true;
      }
   }
  :if ( !found ) do={
     :set $removed ($removed, $addr);
     /ip firewall address-list remove $x;
     #/log warning "Remove IP ($addr) from $listName";
   }
}
:local newCount [:len $added];
:local removedCount [:len $removed];
:local body "";
:if ( $newCount>0 || $removedCount>0 ) do={
:local index 0;
:if ( $newCount > 0 ) do={
    :set $body ("Added new address to $listName (count: " . $newCount . ")\n [");
    :foreach ip in=$added do={
       :set $index ( $index+1 );
       :set $body ($body . " $ip ");
       :if ( $index < $newCount ) do={ 
           :set $body ($body. ",");
       }
   }
   :set $body ($body . "]");
}
:set $index 0;
:if ( $removedCount > 0 ) do={
    :set $body ($body . "\nRemoved address from $listName (count: " . $removedCount . ")\n [");
    :foreach ip in=$removed do={
       :set $index ( $index+1 );
       :set $body ($body . " $ip "); 
       :if ( $index < $removedCount ) do={ 
           :set $body ($body. ",");
       }
   }
   :set $body ($body . "]");
}
  /log warning ("$listName has been updated. $body");
 :if ($destMail!="") do {
   /tool e-mail send to=$destMail subject=("[" .[/system identity get name] . "] The $listName has been synchronized with registry in $tempFile ($apiPath). Found some changes") body=$body;
   /log info "Email has been sent to $destMail";
  }
  :beep frequency=600 length=200ms;
} else={
  /log info ("$listName has been synchronized. No changes were found");
}
:put "Done.";
👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Что-то у меня совсем не заполняется Address-list. Файл скачивается. Правило добавляется. И все на этом.

Рекомендую апдейт, вернее иную версию скрипта.

Источник вдохновения, а вернее почти все кроме замены адресов: forum.mikrotik.com...

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

2. Работает практически моментально по сравнению с аналогами.

3. Скрипт теперь универсален и кушает практически любые листы.

4. Изменен немного принцип действия.

Теперь листайте товары с таймаутом в сутки, а я советую запускать его раз в 6-12 часов для обновления таймаутов и добавления новых записей.

5. Испытуемые разделители не имеют значения.

Сам код:

{
/ip firewall address-list
:local update do={
:put “Starting import of address-list: $listname”
:if ($nolog = null) do={:log warning “Starting import of address-list: $listname”}

:local displayed true
:local maxretry 3
:local retrywaitingtime 120s
:local retryflag true
:for retry from=1 to=$maxretry step=1 do={
:if (retryflag) do={ :set $retryflag false; :set $sounter 0
:if (retry > 1) do={
:put “Source file changed. Retring after a $retrywaitingtime wait...”
:if ($nolog = null) do={:log warning “Source file changed. Retring after a $retrywaitingtime wait...”}
:delay $retrywaitingtime }

:local fetchResult [/tool fetch url=$url keep-result=no as-value]
:local filesize ($fetchResult->"total")
:local downsize ($fetchResult->"downloaded“)
:if ($filesize = 0 && $downsize > 0) do={ :set $filesize $downsize}

:local start 0
:local maxsize 64000; # reqeusted chunk size
:local end ($maxsize — 1); # because start is zero the maxsize has to be reduced by one
:local partnumber ($filesize / ($maxsize / 1024)); # how many chunk are maxsize
:local remainder ($filesize % ($maxsize / 1024)); # the last partly chunk
:if ($remainder > 0) do={ :set $partnumber ($partnumber + 1) }; # total number of chunks
:if ($heirule != null) do={:put “Using as extra filtering: $heirule”} else={:set $heirule “.”}
# remove the current list completely if “erase” is not present (default setting)
:if ($noerase = null) do={
:if ($timeout = null) do={:set $timeout 00:00:00; :do {:foreach i in=[/ip firewall address-list find list=$listname] do={/ip firewall address-list set list=("backup".$listname) $i }} on-error={} } else={
:do {:foreach i in=[/ip firewall address-list find list=$listname dynamic] do={/ip firewall address-list set list=("backup".$listname) $i }} on-error={} };
:put ("Conditional deleting all".$dynamic." entries in address-list: $listname")
:if ($nolog = null) do={:log warning ("Conditional deleting all".$dynamic." entries in address-list: $listname“)}
} else={:put “Entries not conditional deleted in address-list: $listname”}; # ENDIF ERASE
:for x from=1 to=$partnumber step=1 do={
# get filesize to be compared to the orignal one and if changed then retry
:local comparesize ([/tool fetch url=$url keep-result=no as-value]->"total")
:if ($comparesize = 0 && $downsize > 0) do={ :set $comparesize $downsize}

# fetching the chunks from the webserver when the size of the source file has not changed
# empty array when the source file changed. No processing is done till the next complete retry
:if ($comparesize = $filesize) do={:set $data ([:tool fetch url=$url http-header-field="Range: bytes=$start-$end" output=user as-value]->"data")} else={:set $data [:toarray “"]; :set $retryflag true}
#:if ($ownposix = null) do={
# determining the used delimiter in the list, when not provided in the config
# this only run once and so the impact on the import time is low
:local ipv4Posix “^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}”
:local ipv4rangePosix “^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}/[0-9]{1,2}”
:local domainPosix “^.+\\.[a-z.]{2,7}”
:local sdata $data;
# removes any lines at the top of the file that could interfere with finding the correct posix. Setting remarksign is needed
:while ([:pick $sdata 0 1] = $remarksign) do={ :set $sdata [:pick $sdata ([:find $sdata "\n“]+1) [:len $sdata]] }
:while ([:len $sdata]!=0 && $delimiter = null) do={ # The check on length of $sdata is for if no delimiter is found.
:local sline [:pick $sdata 0 [:find $sdata “\n”]]; :local slen [:len $sline];
# set posix depending of type of data used in the list
:if ($sline ~ $ipv4Posix) do={:set $posix $ipv4Posix; :set $iden “List identified as a IPv4 list”}
:if ($sline ~ $ipv4rangePosix) do={:set $posix $ipv4rangePosix; :set $iden “List identified as a IPv4 with ranges list”}
:if ($sline ~ $domainPosix) do={:set $posix $domainPosix; :set $iden “List identified as a domain list”}
:if ($sline ~ $posix) do={:put $iden}
:if ($sline ~ $posix) do={ # only explore the line if there is a match at the start of the line.
:do {:if ([:pick $sline 0 ($slen-$send)] ~ ($posix.“\$”) || $send > $slen) do={
:set $delimiter [:pick $sline ($slen-$send) ($slen-($send-1))]; :set $result true} else={:set $send ($send+1)}
:if ($result) do={ :set $extra [:pick $sline ($slen-$send) ($slen-($send-1))]
:if ( $extra = " " ) do={ :set $delimiter [:pick $sline ($slen-$send) ($slen-($send-2))] }
:if ( $extra = " " ) do={ :set $delimiter [:pick $sline ($slen-$send) ($slen-($send-3))] }
:if ( $extra = " " ) do={ :set $delimiter [:pick $sline ($slen-$send) ($slen-($send-4))] }
}; # EndIf result
} while (!$result); # EndDoWhile
}; #IF sline posix
:set $sdata [:pick $sdata ([:find $sdata "\n“]+1) [:len $sdata]]; # cut off the already searched lines
:if ($delimiter != null) do={:local sdata [:toarray “‘]} ; #Clearing sdata array ending the WhileDo loop
}; #WHILE END $sdata
:local sdata [:toarray ’”]
:if ([:len $delimiter] = 0) do={ :set $delimiter “\n”; :set $delimiterShow “New Line” } else={ :set $delimiterShow $delimiter }; # when empty use NewLine 20220529
#} else={:put “User defind Posix: $ownposix”; :set $posix $ownposix } ; # ENDIF ownposix = null
:if ($delimiter != null && $displayed ) do={:set $displayed false; :put "Using config provided delimiter: \"$delimiterShow\“"}
:if ($posix = null) do={:set $posix “.”}; # Use a match all posix if nothing is defined or found
:if (!retryflag) do={:put “Reading Part: $x $start — $end”}
:if ($timeout = null) do={:local timeout 00:00:00}; # if no timeout is defined make it a static entry.
# Only remove the first line only if you are not at the start of list

Коментар порушує правила спільноти і видалений модераторами.

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

Ну походу apiPath установить в пустую строку, тогда он не будет запрашивать обновление файла с сервера

:local apiPath "";
и будет использовать файл который уже есть, по пути в
:local tempFile "yourFileName.txt"
Если это для того чтобы много IP загрузить с файла, то сгодится, а по прямому назначению скрипт несколько утратил актуальность- в новой версии router os позволяет использовать доменные имена, а не только ip в адрес листе.

:local maxEntriesCount 1024;
:local listName „UA-BLACKLIST”
:local tempFile „UA-BLACKLIST.txt”
:local apiPath "";
в Files закинул файл UA-BLACKLIST.txt
нажимаю Run Script в логи пишет script,info Analyzing data... и висит
в чем косяк?
ну пока хоть так, дальше буду читать как сделать по доменному имени

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

я закидываю файл в Files и запускаю скрипт, ничего не добавляет в адрес лист, но правило в фильтрах создает

странно, я его скопировал со своей железяки под ROS 6.41.3, и файл ему совал, все добавляет... явно что то с вашим файлом, может какие спецсимволы там есть кроме перевода на новую строку?
Скармливал вот это...

213.180.204.188
213.180.204.193
213.180.204.200
213.180.204.207
213.180.204.242
213.186.33.40
217.20.155.13
217.69.139.200
217.69.139.201
vk.com
ok.ru
217.16.27.80
217.16.27.89
217.20.147.1

когда файл закидываю с инета, все нормально, а вот когда на МТ на котором инета нет пробую добавить файл,то после нажатия Run Script вот такое выбивает UA-BLACKLIST has been synchronized. No changes were found
прошивка 42.2
вот код

:local maxEntriesCount 1024;
:local listName „UA-BLACKLIST”
:local tempFile „ips.txt”
:local apiPath „‚;

:if ( $apiPath!=’”) do={
/log info „fetching UA blacklist registry ($apiPath)...”;
/tool fetch url=$apiPath dst-path=$tempFile
}
:local counter 0;
:local ipList [:toarray „‚];
:local added [:toarray ’”];
:local removed [:toarray „‚];
:local lineEnd 0;
:local line ’”;
:local lastEnd 0;
:if ( [/file get [/file find name=$tempFile] size] > 0 ) do={
:put „Analyzing...”;
/log info „Analyzing data in [$tempFile]...”
:local rule [/ip firewall filter find dst-address-list=$listName]
:if ([:len $rule]=0) do={
/log info „firewall rule not found. Adding...”;
/ip firewall filter add chain=forward dst-address-list="$listName" comment="rule for $listName" action=reject reject-with=icmp-host-unreachable place-before=0;
}
:local content [/file get [/file find name=$tempFile] contents] ;
:local contentLen [ :len $content ] ;
:do {
:set $counter (counter+1);
:set lineEnd [:find $content „\n” $lastEnd ] ;
:if ($lineEnd < $lastEnd) do={
:set $lineEnd $contentLen;
}
:set line [:pick $content $lastEnd $lineEnd] ;
:set lastEnd ( $lineEnd + 1 ) ;
:if ( [:len $line] > 0 ) do={
:set $ipList ($ipList, $line);
:if ( [:len [/ip firewall address-list find address=$line list=$listName]] =0 ) do={
/ip firewall address-list add list="$listName" address="$line„;
:set $added ($added, $line);
#/log warning „New IP ($line) added to $listName”;
}
}
} while ($lineEnd < $contentLen && $counter < $maxEntriesCount )
}
/ip firewall address-list
:foreach x in=[find list=$listName] do={
:local addr [get $x address];
:local found false;
:foreach ip in=$ipList do={
:if ( $ip=addr ) do={
:set found true;
}
}
:if ( !found ) do={
:set $removed ($removed, $addr);
/ip firewall address-list remove $x;
#/log warning „Remove IP ($addr) from $listName”;
}
}
:local newCount [:len $added];
:local removedCount [:len $removed];
:local body „‚;
:if ( $newCount>0 || $removedCount>0 ) do={
:local index 0;
:if ( $newCount > 0 ) do={
:set $body (‚Added new address to $listName (count: ’ . $newCount . ‚)\n [’);
:foreach ip in=$added do={
:set $index ( $index+1 );
:set $body ($body . ’ $ip ‚);
:if ( $index < $newCount ) do={
:set $body ($body. ’,”);
}
}
:set $body ($body . „]”);
}
:set $index 0;
:if ( $removedCount > 0 ) do={
:set $body ($body . „\nRemoved address from $listName (count: ” . $removedCount . „)\n [”);
:foreach ip in=$removed do={
:set $index ( $index+1 );
:set $body ($body . " $ip „);
:if ( $index < $removedCount ) do={
:set $body ($body. ”,„);
}
}
:set $body ($body . „]”);
}
/log warning („$listName has been updated. $body”);
:if ($destMail!="") do {
/tool e-mail send to=$destMail subject=("[" .[/system identity get name] . „] The $listName has been synchronized with registry in $tempFile ($apiPath). Found some changes”) body=$body;
/log info „Email has been sent to $destMail”;
}
:beep frequency=600 length=200ms;
} else={
/log info („$listName has been synchronized. No changes were found”);
}
:put „Done.”;

No changes were found

Так может правила на соответствующие адреса в списке уже добавлены прошлыми запусками? Вот и изменений нет...

удалил все правила, все ровно не хочет
эта строка так и должна быть? или что то изменять?
я ведь не через урл записываю
/tool fetch url=$apiPath dst-path=$tempFile

Когда apiPath пустая строка, тот блок кода не выполняется.
Ну блин, да как так то... Ну вот вывод дебага раскоментил:
pastebin.com/u0eeRRJi

ладно, буду дальше копать, пробовать
спасибо вам!

Все же на всякий случай добавлю, мало ли- в файле адреса разделены символом новой строки формата Unix т.е \n, а не windows (\r\n), юзать надо notepad++, а не встроенный текстовый редактор винды...

а роблять BGP blackhole

Ну может кто и юзает с гигантов, но кажется, на основании двух провайдеров, сначала была DNS блокировка, а сейчас пропускают пинги, но блотчат соединение на 80/443 (может еще куда), drop видно ибо таймаут, браузер висит... мелкие точно 99% рубят IP у себя.

В основном, скрипт для домашнего пользования, дабы не прописывать в host всех машин сети 127.0.0.1 vk.com, уж тем более с андроидами не мучатся. Хотя в реестре пока нет зеркал, а по факту провайдеры и их заблотчили, но как добавят...

Надо ломануть, добавить 127.0.0.1, и таким образом починить государство.

добавить 127.0.0.1

и... ничего не будет :)

Я не привожу пример что именно надо забанить, чтобы не нашёлся идиот желающий повторить. Кстати говоря, «не будет»- не спеши с выводами. Файрволл может оказаться что и на внутреннюю сеть накинут, если у кого недостаточно знаний. IPtables настроить то ещё искусство.

Файрволл может оказаться что и на внутреннюю сеть накинут

Ну да, если не localhost вписать, а любой локальный IP, то его заблокирует и в локалке. В автоматически созданном правиле желательно Out Interface указать, автоматом скриптом его влом определять, расчет что анархисты не захватят реестр ;)

Ну и отдельный момент: если ты не лицензированный провайдер, то зачем настраивать бан? Скиньтесь на VPN и будет вам счастье!

Скиньтесь на VPN и будет вам счастье!

Да зачем он мне? Мне ресурсы с блеклиста мало интересны, лишь бы остальные сайты с их счетчиками и прочей хренью не висели по пол минуты, может раньше яндекс карты еще как то были полезны, пока в гугл картах не было той же «линейки», но все ровно в 90% я юзал гугловские. Ну а сейчас из принципа не юзаю.

Потому что блеклист на этом не закончится. У Пети Однотурового шифер снесло окончательно, так что блеклистить будут всё что «не патриотично».

А мэйлрушечка в бане у меня давно была, ибо в отличие от Яндекса, совсем берега потеряли.

У Пети Однотурового шифер снесло окончательно, так что блеклистить будут всё что «не патриотично».

В это мне слабо верится, допускаю только расширение списка на чисто российские проекты. Но, если это случится, то тогда и будем говорить о «сносе крыше», а пока... Пока почти все логично, за исключением, что это надо было делать сразу, а вот 1С нужно было искать альтернативу, а не сегодня решили, а завтра нужно блотчить. Хотя там дали же право купившим ее использовать дальше, но по факту там большинство пиратки. Говорят, что есть какая то украинская альтернатива, то надо было инвестировать государству денег в него, да было бы 3 года на доработку, раз знали куда ветер дует. Либо уже тогда брать программные комплексы с ЕС, раз туда собрались, все ровно ведь когда то бы пришлось слезать с 1С бизнесу...

Чтоб не ждать по минуте таймауты и не драконить своих абонентов, можно отрулить всю запрещёнку на отдельный хост (выделить ip), повесить на него iptables и nginx, всё что по 443 порту рубить файерволом с «tcp-reset», на 80 порту на любой запрос либо отдавать всем пустой документ с нулевой длинной либо опять же рубить файерволом и не заморачиваться, всё остальное тупо рубить (pop3, imap, smtp и т.д.).

Підписатись на коментарі