Mikrotik RouterOSのスクリプトを書くのは簡単です

RouterOSは、Linuxベースのネットワークオペレーティングシステムです。 このオペレーティングシステムは、Mikrotik RouterBoardハードウェアルーターへのインストールを目的としています。 また、このシステムをPC(または仮想マシン)にインストールして、ルーターに変えることもできます。 最初は、OSの機能は非常に豊富で、いや、いや、箱から必要なチップがないことに驚くでしょう。 残念ながら、Linux環境へのアクセスは非常に限られているため、「Linuxの下にある」と「RouterOSにある」とはまったく同じではありません。 しかし、絶望しないでください! このシステムには、機能を拡張するためのいくつかのオプションがあります。 最初の-最も単純で最もネイティブな-は、組み込み言語でスクリプトを作成する機能です。

この記事では、例として、DNS名をIPリスト(アドレスリスト)に変換するスクリプトを検討します。

なぜ必要なのでしょうか? 多くのサイトでは、ラウンドロビンDNSを使用して負荷を分散しています(一部のサイトはこれだけではありません)。 そのようなサイトへのアクセスを制御する(ルーティングまたはファイアウォールルールを作成する)には、このドメイン名に対応するすべてのIPアドレスが必要です。 さらに、特定のDNSレコードの寿命(この場合はAレコードについて話している)の後のIPアドレスのリストは完全に新しく返される可能性があるため、情報を定期的に更新する必要があります。 残念ながら、RouterOSでルールを作成することはできません。
example.comのポート80ですべてのTCP接続をブロックする
example.comの代わりにIPアドレス必要ですが、すでに理解しているように、 example.comは1つではなく複数のIPアドレスに対応しています。 同じタイプのルールを作成して維持する手間を省くために、RouterOS開発者は次のようなルールを作成できるようにしました。
DenyThisという名前のリスト内の任意のアドレスへのポート80上のすべてのTCP接続をブロックする
残っている唯一のものは、このリストを自動的に作成することです。 まだ私の文章に飽きていない人は、ハブラカトに招待します。



スクリプトテキストをすぐに提供し、その後、段階的な分析を行います。
:local DNSList {"example.com";"non-exist.domain.net";"server.local";"hostname"} :local ListName "MyList" :local DNSServers ( [ip dns get dynamic-servers], [ip dns get servers ], 8.8.8.8 ) :foreach addr in $DNSList do={ :foreach DNSServer in $DNSServers do={ :do {:resolve server=$DNSServer $addr} on-error={:log debug ("failed to resolve $addr on $DNSServer")} } } /ip firewall address-list remove [find where list~$ListName] /ip dns cache all :foreach i in=[find type="A"] do={ :local bNew true :local cacheName [get $i name] :local match false :foreach addr in=$DNSList do={ :if (:typeof [:find $cacheName $addr] >= 0) do={ :set $match true } } :if ( $match ) do={ :local tmpAddress [/ip dns cache get $i address] :if ( [/ip firewall address-list find ] = "") do={ :log debug ("added entry: $[/ip dns cache get $i name] IP $tmpAddress") /ip firewall address-list add address=$tmpAddress list=$ListName comment=$cacheName } else={ :foreach j in=[/ip firewall address-list find ] do={ :if ( [/ip firewall address-list get $j address] = $tmpAddress ) do={ :set bNew false } } :if ( $bNew ) do={ :log debug ("added entry: $[/ip dns cache get $i name] IP $tmpAddress") /ip firewall address-list add address=$tmpAddress list=$ListName comment=$cacheName } } } }
      
      









スクリプトテキストは、/ system scriptsセクションにあるスクリプトリポジトリに追加する必要があります。

スクリプトは1行ずつ実行されます。 各行の構文は次のとおりです。

 [prefix] [path] command [uparam] [param=[value]] .. [param=[value]]
      
      



[prefix]-":"-グローバルコマンドの場合、コマンドラインは "/"文字で始まり、構成ルートに対して実行されます。プレフィックスがない場合があり、コマンドラインは現在の構成セクションに対して実行されます。

[path]-目的の構成セクションへのパス。コマンドが実行される前に遷移が発生します。

command-コマンドラインによって実行されるアクション。

[uparam]-名前のないコマンドパラメーター。

[param = [value]]-名前付きパラメーターとその値。



そのため、まず、スクリプト操作パラメーターを変数の形式で定義します。 変数はコマンドによって宣言されます:ローカルおよびグローバル、それぞれ、そのスコープ内でのみ使用可能なローカル変数、またはOS環境変数のリストに追加され、どこからでもアクセスできるグローバルを取得します。 ローカル変数は、スコープが実行されている間、グローバル変数-削除するまで存続します。



 :local DNSList {"example.com";"non-exist.domain.net";"server.local";"hostname"} :local ListName "MyList" :local DNSServers ( [ip dns get dynamic-servers], [ip dns get servers ], 8.8.8.8 )
      
      



DNSList変数には、操作したいドメインの配列が含まれています。 変数ListNameには、受信したアドレスリストと呼ばれる文字列が含まれています。 DNSServers変数-ルーターに登録された、または接続時にプロバイダーから受信したDNSサーバーアドレスの配列と、ルーターがドメインレコードに関する情報を取得するために使用されるDNSサービスを使用しない場合の「8」。



 :foreach addr in $DNSList do={ :foreach DNSServer in $DNSServers do={ :do {:resolve server=$DNSServer $addr} on-error={:log debug ("failed to resolve $addr on $DNSServer")} } }
      
      



「全員向け」サイクルでは、ドメインアレイを巡回し、異なるDNSが異なるIPを提供する場合に備えて、各DNSサーバーでIPアドレスを取得します。 建設業
 :do {command} on-error={command}
      
      



実行時エラーをキャッチします。 使用しない場合、存在しないアドレスまたは誤ったアドレスに対して解決エラーが発生すると、スクリプトが中断される可能性があります。



 /ip firewall address-list remove [find where list~$ListName]
      
      





/ ip firewall address-list configurationセクションに移動して、リスト名に$ ListName変数の値が含まれるすべてのエントリを削除しましょう。 角括弧の構築により、現在のコマンド内で別のコマンドを実行し、現在の結果をパラメーターとして転送できます。



 /ip dns cache all :foreach i in=[find type="A"] do={
      
      



/ ip dns cahe all configurationセクションに行きましょう。 これには、テーブル名-タイプ-データ-TTLの形式でルーターのDNSキャッシュが含まれています。 タイプによる選択を実行します-Aレコードのみが必要です。 そして、「全員向け」サイクルで選択結果を確認します。 これがスクリプトのメインサイクルになります。



 :local bNew true :local cacheName [get $i name] :local match false
      
      





各サイクルで更新される変数を作成しましょう。2つのフラグ-bNew(複製を除く)、一致、現在のキャッシュエントリがドメインのリストにあるかどうかを示します。 cacheName変数には、現在のキャッシュエントリ、つまりドメインのNameフィールドが含まれます。



 :foreach addr in=$DNSList do={ :if (:typeof [:find $cacheName $addr] >= 0) do={ :set $match true } }
      
      





ドメインのリストを調べて、それぞれについて、cacheName行にこのリストのドメイン形式の部分文字列が含まれているかどうかを確認します。
等値比較を使用しないのはなぜですか?
非常にシンプル-スクリプトロジックは、サブドメインをドメインと同じ方法で処理することを前提としています。 ソーシャルアカウントをブロックする場合、メインドメインだけでなく、たとえば、静的、画像、スクリプトを提供し、このサイトのサブドメインに配置されているサーバーもブロックすることは理にかなっています。 また、wwwのあるドメインとないドメインを別々にリストすることを避けるのに役立ちます。 これらのドメインが解決中にキャッシュにヒットしなかったという事実は怖いものではありません。 ブラウザがユーザーを解決するときにそこに到達できます(ただし、これにはユーザーのDNSクエリがRouterOSで処理される必要があります)。
その場合、一致フラグをtrueに設定します。



 :if ( $match ) do={ :local tmpAddress [/ip dns cache get $i address] :if ( [/ip firewall address-list find ] = "") do={ :log debug ("added entry: $[/ip dns cache get $i name] IP $tmpAddress") /ip firewall address-list add address=$tmpAddress list=$ListName comment=$cacheName } else={ :foreach j in=[/ip firewall address-list find ] do={ :if ( [/ip firewall address-list get $j address] = $tmpAddress ) do={ :set bNew false } } :if ( $bNew ) do={ :log debug ("added entry: $[/ip dns cache get $i name] IP $tmpAddress") /ip firewall address-list add address=$tmpAddress list=$ListName comment=$cacheName } } }
      
      





最後のステップで、現在のアドレスを追加する必要がある場合(一致がtrueに設定されている場合)、アドレスリストに追加します。 追加するエントリのコメントには、エントリが属するドメインが含まれます。 同時に、いくつかのチェックを実行します。 アドレスリストが空の場合、すぐに追加します。何かある場合は、そのIPアドレスのエントリがあるかどうかを確認し、ない場合は追加します。



アドレスのリストは定期的に更新する必要があります。 これを行うために、RouterOSにはタスクマネージャーがあります。 タスクは、コンソールまたはwinbox GUIから追加できます

 /system scheduler add interval=5m name=MyScript on-event="/system script run MyScript" policy=\ ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=may/08/2014 \ start-time=10:10:00
      
      







アドレス一覧を使用するシナリオは、ファイアウォールでルールを作成することに限定されません。 したがって、いくつかの例を示します。 コンソールで実行でき、winboxのマウスで追加できます。

ブラックリスト:

 /ip firewall filter add chain=forward protocol=tcp dst-port=80 address-list=DenyThis \ action=drop
      
      





これらのノードへの静的ルート

 /ip firewall mangle add action=mark-routing chain=prerouting dst-address-list=AntiZapret \ in-interface=bridge_lan new-routing-mark=RouteMe /ip route add distance=1 gateway=172.16.10.2 routing-mark=RouteMe
      
      





顧客情報の収集

 /ip firewall mangle add action=add-src-to-address-list address-list=FUPer chain=prerouting \ dst-address-list=Pron log=yes log-prefix=critical
      
      







ソースのリスト:

スクリプトのドキュメント

RouterOS開発者からの簡単な例

ユーザーが追加したスクリプト



UPD:特にturoneの要求により、スクリプトに変更を加え、DNSサーバーのアドレスがシステムから取得されるようにしました。

UPD 08/24/2016:RouterOSの新しいバージョン(6.36以降)では、アドレスリストでDNS名を指定できるようになったこと気付きました。 したがって、このスクリプトの価値は教育的なものにすぎません。



All Articles