Scripting examples
本页提供 MikroTik RouterOS 的脚本示例,演示如何使用 RouterOS 脚本命令创建和修改文件、追加文本、检查 IP 变化、去除网络掩码以及解析主机名。
脚本示例
无法直接创建文件;不过,可以使用以下变通方法:
/file print file=myFile
/file set myFile.txt contents=""
向文件追加一行文本
没有直接向文件追加文本的方法;你可以存储旧内容,并追加一行带有额外文本的新行:
:local oldText [/file get myFile.txt contents as-string]
:local addText "test append"
:local newText ($oldText."\n".$addText)
/file set myFile.txt contents=$newText
检查接口上的 IP 是否已更改
一些运营商会分配动态 IP 地址。此脚本将新地址与当前地址进行比较。
:global currentIP;
:local newIP [/ip address get [find interface="ether1"] address];
:if ($newIP != $currentIP) do={
:put "ip address $currentIP changed to $newIP";
:set currentIP $newIP;
}
去除网络掩码
当你需要不带网络掩码的 IP 地址时(例如在防火墙中使用),此脚本很有用,因为 /ip address get [id] address 会同时返回地址及其网络掩码。
:global ipaddress 10.1.101.1/24
:for i from=( [:len $ipaddress] - 1) to=0 do={
:if ( [:pick $ipaddress $i] = "/") do={
:put [:pick $ipaddress 0 $i]
}
}
更简单的方式是:
:global ipaddress 10.1.101.1/24
:put [:pick $ipaddress 0 [:find $ipaddress "/"]]
解析主机名
许多用户希望能够在 RADIUS 服务器、防火墙规则等中使用 DNS 名称代替 IP 地址。
以下示例解析 RADIUS 服务器的 IP。
假设 RADIUS 服务器配置如下:
/radius
add address=3.4.5.6 comment=myRad
以下脚本解析服务器的 IP 地址,将结果与配置的值进行比较,如果不同则替换它:
/system script add name="resolver" source= {
:local resolvedIP [:resolve "server.example.com"];
:local radiusID [/radius find comment="myRad"];
:local currentIP [/radius get $radiusID address];
:if ($resolvedIP != $currentIP) do={
/radius set $radiusID address=$resolvedIP;
/log info "radius ip updated";
}
}
例如,将此脚本添加到调度器,使其每五分钟运行一次。
/system scheduler add name=resolveRadiusIP on-event="resolver" interval=5m
将 simple queue 统计信息写入多个文件
假设队列名使用 some text.1 格式,这样你就可以按点后的数字进行搜索。
:local entriesPerFile 10;
:local currentQueue 0;
:local queuesInFile 0;
:local fileContent "";
#determine needed file count
:local numQueues [/queue simple print count-only] ;
:local fileCount ($numQueues / $entriesPerFile);
:if ( ($fileCount * $entriesPerFile) != $numQueues) do={
:set fileCount ($fileCount + 1);
}
#remove old files
/file remove [find name~"stats"];
:put "fileCount=$fileCount";
:for i from=1 to=$fileCount do={
#create file
/file print file="stats$i.txt";
#clear content
/file set [find name="stats$i.txt"] contents="";
:while ($queuesInFile < $entriesPerFile) do={
:if ($currentQueue < $numQueues) do={
:set currentQueue ($currentQueue +1);
:put $currentQueue ;
/queue simple
:local internalID [find name~"\\.$currentQueue\$"];
:put "internalID=$internalID";
:set fileContent ($fileContent . [get $internalID target-address] . \
" " . [get $internalID total-bytes] . "\r\n");
}
:set queuesInFile ($queuesInFile +1);
}
/file set "stats$i.txt" contents=$fileContent;
:set fileContent "";
:set queuesInFile 0;
}
生成备份并通过电子邮件发送
此脚本生成备份文件并将其发送到指定的电子邮件地址。邮件主题包含路由器名称、当前日期和时间。
注意,使用此脚本之前必须配置 SMTP 服务器。有关配置选项,请参阅 /tool e-mail。
/system backup save name=email_backup
/tool e-mail send file=email_backup.backup to="me@test.com" body="See attached file" \
subject="$[/system identity get name] $[/system clock get time] $[/system clock get date] Backup"
警告
备份文件包含密码等敏感信息。因此,脚本或调度器必须具有 'sensitive' 策略才能访问生成的备份文件。
将字符串用作函数
:global printA [:parse ":local A; :put \$A;" ];
$printA
检查带宽并添加限制
此脚本检查接口上的下载是否超过 512 kbps;如果超过,脚本会添加一个将速度限制为 256 kbps 的队列。
:foreach i in=[/interface find] do={
/interface monitor-traffic $i once do={
:if ($"received-bits-per-second" > 0 ) do={
:local tmpIP [/ip address get [/ip address find interface=$i] address] ;
# :log warning $tmpIP ;
:for j from=( [:len $tmpIP] - 1) to=0 do={
:if ( [:pick $tmpIP $j] = "/") do={
/queue simple add name=$i max-limit=256000/256000 dst-address=[:pick $tmpIP 0 $j] ;
}
}
}
}
}
阻止访问特定网站
当你想在不使用 Web 代理的情况下阻止某些网站时,此脚本很有用。
此示例查看 DNS 缓存中的 "Rapidshare" 和 "youtube" 条目,并将 IP 添加到名为 "restricted" 的地址列表中。在开始之前,必须设置路由器以捕获所有 DNS 请求:
/ip firewall nat
add action=redirect chain=dstnat comment=DNS dst-port=53 protocol=tcp to-ports=53
add action=redirect chain=dstnat dst-port=53 protocol=udp to-ports=53
然后添加防火墙规则:
/ip firewall filter
add chain=forward dst-address-list=restricted action=drop
编写脚本并计划每 30 秒运行一次。
脚本代码:
:foreach i in=[/ip dns cache find] do={
:local bNew "true";
:local cacheName [/ip dns cache all get $i name] ;
# :put $cacheName;
:if (([:find $cacheName "rapidshare"] >= 0) || ([:find $cacheName "youtube"] >= 0)) do={
:local tmpAddress [/ip dns cache get $i address] ;
# :put $tmpAddress;
# if address list is empty do not check
:if ( [/ip firewall address-list find list="restricted" ] = "") do={
:log info ("added entry: $[/ip dns cache get $i name] IP $tmpAddress");
/ip firewall address-list add address=$tmpAddress list=restricted comment=$cacheName;
} else={
:foreach j in=[/ip firewall address-list find list="restricted"] do={
:if ( [/ip firewall address-list get $j address] = $tmpAddress ) do={
:set bNew "false";
}
}
:if ( $bNew = "true" ) do={
:log info ("added entry: $[/ip dns cache get $i name] IP $tmpAddress");
/ip firewall address-list add address=$tmpAddress list=restricted comment=$cacheName;
}
}
}
}
解析文件以添加 ppp secrets
此脚本要求文件内的条目采用以下格式:
username,password,local_address,remote_address,profile,service
例如:
janis,123,1.1.1.1,2.2.2.1,ppp_profile,myService
juris,456,1.1.1.1,2.2.2.2,ppp_profile,myService
aija,678,1.1.1.1,2.2.2.3,ppp_profile,myService
:global content [/file get [/file find name=test.txt] contents] ;
:global contentLen [ :len $content ] ;
:global lineEnd 0;
:global line "";
:global lastEnd 0;
:do {
:set lineEnd [:find $content "\r\n" $lastEnd ] ;
:set line [:pick $content $lastEnd $lineEnd] ;
:set lastEnd ( $lineEnd + 2 ) ;
:local tmpArray [:toarray $line] ;
:if ( [:pick $tmpArray 0] != "" ) do={
:put $tmpArray;
/ppp secret add name=[:pick $tmpArray 0] password=[:pick $tmpArray 1] \
local-address=[:pick $tmpArray 2] remote-address=[:pick $tmpArray 3] \
profile=[:pick $tmpArray 4] service=[:pick $tmpArray 5];
}
} while ($lineEnd < $contentLen)
检测新的日志条目
此脚本检查是否有新的日志条目添加到特定缓冲区。
在此示例中,使用 PPPoE 日志:
/system logging action
add name="pppoe"
/system logging
add action=pppoe topics=pppoe,info,!ppp,!debug
日志缓冲区如下所示:
[admin@mainGW] > /log print where buffer=pppoe
13:11:08 pppoe,info PPPoE connection established from 00:0C:42:04:4C:EE
以下脚本检测何时添加了新条目。
:global lastTime;
:global currentBuf [ :toarray [ /log find buffer=pppoe ] ] ;
:global currentLineCount [ :len $currentBuf ] ;
:global currentTime [ :totime [/log get [ :pick $currentBuf ($currentLineCount -1) ] time ] ];
:global message "";
:if ( $lastTime = "" ) do={
:set lastTime $currentTime ;
:set message [/log get [ :pick $currentBuf ($currentLineCount-1) ] message];
} else={
:if ( $lastTime < $currentTime ) do={
:set lastTime $currentTime ;
:set message [/log get [ :pick $currentBuf ($currentLineCount-1) ] message];
}
}
检测后,新条目保存在 message 变量中;之后你可以解析此变量以获取详细信息,例如 PPPoE 客户端的 MAC 地址。
允许将 ntp.org 池服务用于 NTP
此脚本解析两台 NTP 服务器的主机名,将结果与当前 NTP 设置进行比较,如果不同则更改地址。由于 RouterOS 不允许在 NTP 配置中使用主机名,因此需要此脚本。这里使用了两个脚本。第一个定义供第二个脚本使用的系统变量,第二个脚本执行实际工作:
# System configuration script - "GlobalVars"
:put "Setting system globals";
# System name
:global SYSname [/system identity get name];
# E-mail address to send notifications to
:global SYSsendemail "mail@my.address";
# E-mail address to send notifications from
:global SYSmyemail "routeros@my.address";
# Mail server to use
:global SYSemailserver "1.2.3.4";
# NTP pools to use (check www.pool.ntp.org)
:global SYSntpa "0.uk.pool.ntp.org";
:global SYSntpb "1.uk.pool.ntp.org";
# Check and set NTP servers - "setntppool"
# We need to use the following globals which must be defined here even
# though they are also defined in the script we call to set them.
:global SYSname;
:global SYSsendemail;
:global SYSmyemail;
:global SYSemailserver;
:global SYSntpa;
:global SYSntpb;
# Load the global variables with the system defaults
/system script run GlobalVars
# Resolve the two ntp pool hostnames
:local ntpipa [:resolve $SYSntpa];
:local ntpipb [:resolve $SYSntpb];
# Get the current settings
:local ntpcura [:pick [/system/ntp/client/get servers] 0];
:local ntpcurb [:pick [/system/ntp/client/get servers] 1];
# Define a variable so we know if anything's changed.
:local bChange 0;
# Debug output
:put ("Old: " . $ntpcura . " New: " . $ntpipa);
:put ("Old: " . $ntpcurb . " New: " . $ntpipb);
# Change servers if required
:if ($ntpipa != $ntpcura || $ntpipb != $ntpcurb) do={
:put "Changing NTP servers";
/system/ntp/client/set servers="$ntpipa,$ntpipb";
:set bChange 1;
}
# If we've made a change, send an e-mail to say so.
:if (($bChange = 1)) do={
:put "Sending e-mail.";
/tool e-mail send \
to=$SYSsendemail \
subject=($SYSname . " NTP change") \
from=$SYSmyemail \
server=$SYSemailserver \
body=("Your NTP servers have just been changed:\n\nPrimary:\nOld: " . $ntpcura . "\nNew: " \
. $ntpipa . "\n\nSecondary\nOld: " . $ntpcurb . "\nNew: " . $ntpipb);
}
调度器条目:
/system scheduler add \
comment="Check and set NTP servers" \
disabled=no \
interval=12h \
name=CheckNTPServers \
on-event=setntppool \
policy=read,write,test \
start-date=1970-01-01 \
start-time=16:00:00