因為有一些需求, 有一台 RouterBoard 得一直換 MAC address . 花了一點時間研究了一下 RouterOS script , 讓指定的 interface 換上 rand 的mac address . 從網路上找到現成的 code 可以產生出 rand mac address , 但真要拿來用, 卻有不小的機率出現 failure: invalid mac address … 研究了一下 mac address 的規則, 看不出啥端倪, 索性就修改了下這個現成的 code , 並弄成一個 function , 可以自己一直試到成功為止. 同時也設下了一個重試的上限 . 紀錄如下, 也歡迎有需求的人直接享用 .
:global gainmac
:global lastmac 0
:global funGainMac do={
# modified from https://forum.mikrotik.com/viewtopic.php?t=91229
# Generate random-ish MAC address
# Tested on RouterOS v6.49.7
#to call global function , need to declare in function .
:global funGainMac
:global gainmac
:global lastmac
# if firewall rules can't be found, add them
if ( [ :len [ /ip firewall filter find comment~"fwrnum" ] ] = 0 ) do={
:for i from=1 to=12 do={
/ip firewall filter add action=passthrough chain=input random="$i" comment="fwrnum$i";
}
}
#delay 1500ms to wait for the rand rule above be ready
:delay 700ms
# MAC characters array
:local macTable A,B,C,D,E,F,0,1,2,3,4,5,6,7,8,9
# length of MacTable array
:local macTableLen [ :len $macTable ];
# variable that will hold our mac address
:local mac;
# generate 12 mac address characters
:for i from=1 to=12 do={
# get packet number from each firewall rule
:local v [/ip firewall filter get [find comment="fwrnum$i"] packets ];
# add $i*$i value to $v
:set v ( $v + ( $i * $i ) );
# add time values, last value of minutes, and both seconds values
:local t ( [ :pick [/system clock get time] 4 5 ] . [ :pick [/system clock get time] 6 8 ] );
# reverse values, increasing frequency of first number change
:set t ( [ :pick $t 2 ] . [ :pick $t 1 ] . [ :pick $t 0 ] );
# add time seed to $v
:set v ( $v + $t );
# if packet number is greater than 100, just grab last 2 digits, as they change most frequently
if ( $v >= 100 ) do={
:set v [ :pick $v ( [ :len $v ] - 2 ) [ :len $v ] ];
}
# reverse the two digits, increasing frequency of variable change
:set v ( [ :pick $v 1 ] . [ :pick $v 0 ] );
# while the value is greater than or equal to the length of the macTable array
while ( $v >= $macTableLen ) do={
# subtract 15, one less than macTable length, so as to create a rainbow effect so to speak
:set v ( $v - 15 );
}
# create mac starting at the end, get mac char from macTable based on our value
:set mac ( [ :pick $macTable $v ] . $mac );
# add mac address colons at appropriate spots
if ($i = 2 || $i = 4 || $i = 6 || $i = 8 || $i = 10) do={
:set mac ( ":" . $mac );
}
}
# remove firewall rules
/ip firewall filter remove [ find comment~"fwrnum" ];
:local fNotToChang 0
if ( $mac = $lastmac) do={
$funGainMac
:set fNotToChang 1
}
if ( $fNotToChang = 0 ) do={
:set gainmac $mac
:set lastmac $mac
}
}
:global funSetMac do={
:global funGainMac
:global funSetMac
:global gainmac
:local mac
$funGainMac
:set mac $gainmac
# show mac address
#:put $mac;
#:put [/interface ethernet set ether5-slave-local mac-address=$mac];
#[/interface ethernet set $strEth mac-address=$mac];
:do {
[/interface ethernet set $strEth mac-address=$mac];
} on-error={};
:local newmac [/interface ethernet get [find where name="$strEth"] mac-address];
#:put $newmac;
:local strMsg
if ($mac = $newmac) do={
#:put "$strEth change MAC ok !!";
:set strMsg ", $strEth change MAC ok !!"
}
:local b $1;
:set b ($1-1);
:put "$b, mac=$mac, mac of Eth = $newmac $strMsg" ;
if ($b > 0 and $mac != $newmac ) do={
$funSetMac strEth=$strEth $b
}
}
:global funSetMacBridge do={
:global funGainMac
:global funSetMacBridge
:global gainmac
:local mac
$funGainMac
:set mac $gainmac
# show mac address
#:put $mac;
:do {
[/interface bridge set $strEth auto-mac=yes];
[/interface bridge set $strEth auto-mac=no];
[/interface bridge set $strEth auto-mac=no admin-mac=$mac ];
} on-error={};
:local newmac [/interface bridge get [find where name="$strEth"] admin-mac];
#:put $newmac;
:local strMsg
if ($mac = $newmac) do={
#:put "$strEth change MAC ok !!";
:set strMsg ", $strEth change MAC ok !!"
}
:local b $1;
:set b ($1-1);
:put "$b, mac=$mac, mac of Eth = $newmac $strMsg" ;
if ($b > 0 and $mac != $newmac ) do={
$funSetMacBridge strEth=$strEth $b
}
}
#call funSetMac , arg0=define interface name , arg1= times to retry
$funSetMacBridge strEth="bridge" 15
:put "-----------------------";
$funSetMac strEth="ether5" 15
:put "-----------------------";
$funSetMac strEth="ether4" 15
:put "-----------------------";
$funSetMac strEth="ether3" 15
:put "-----------------------";
$funSetMac strEth="ether2" 15
:put "-----------------------";