All posts by Omega-00

Making your router talk – MikroTik and Telegram Bot Scripting

While there are existing ways (SNMP/SMS) to run scripts on RouterOS via external means, I’ve been meaning to show off a system I built based around Telegram Messenger – as it’s a relatively common one, and has a flexible API for interfacing with.



I began this with the older MikroTik 4096 character variable limit in mind, intending to process 1 or 2 messages at a time, but found half way through that this no longer applies (yay) – so as many as 100 messages or more could be pulled down at the same time and churned through the processing script.

Because we’re running this based around a single-threaded processing script it’s not going to be the fastest implementation, but I’m hoping this is a good start for anyone looking to expand on the functions I’ve added here.

At present the system works as follows:

A scheduler entry called “telegram_bot” runs every 50 seconds by default. It’s designed not to hammer the telegram servers or exceed rate limits – but will be ramped up in the event messages are seen.

The scheduler runs the script “telegram_bot_main” which ensures all required functions are loaded and sets the BOTID (see: https://core.telegram.org/bots for how to create one) and your telegramID (an ID unique to each user). This will be used to determine if the messenger gets authenticated or unauthenticated access. The main script also updates the scheduler delay (which is set to 10 seconds when a message first arrives, and slowly increases back up to 50 seconds if no further updates are seen).

Important note: A function called “sendlog” is called throughout these scripts in order to allow easy debugging – this is the best place to define any logging/put/debugging options you want to spit out – and then off again when you want the script to run silently in the background.

If updates are found – these are processed through the “telegram_bot_processupdates” script which determines what to do next, until the list of updates has been completed – when a list of updates has been processed, a call is sent back to telegram to confirm the updateID of the last message processed – this is then used as an offset for the subsequent messages to be sent by telegram. You wouldn’t want to run 2 routers on the same BOT ID with this in place as it would mean only one router might see the message.

Updates are processed one message at a time, and if a message is detected to be from a group (for example someone has accidentally added the bot to a group chat) the bot will leave this chat by calling the “telegram_bot_leavechat” function.

If an update is detected to be from an authed user (matching the “telegramID” mentioned above) then the received command is run against the “telegram_bot_message_auth” script, otherwise against the “telegram_bot_message_unauth” script.

The authenticated one is pretty basic for now – it allows the user to run any existing script on the router including variables. Say for example you had a script/function that would send a copy of the router backup to an email address you could trigger this remotely.

The unauthenticated one is where I’ve had some fun for now – putting in a few basic commands that allow a remote user to trigger functions on the router. These are:

wifi: show current number of wireless registrations
internet: show current speed of ether1 on the router
blink: make a light on the router blink
beep: for devices that have it, make the router speaker beep
ping <ip address>: ping an IP address from the router and print back the latency

Now yes, these are very simple commands – but I’ve done this specifically so I can leave this bot open to the public to access and play with – the list of commands you could add is up to your imagination.

Once a command is issued – the script “telegram_bot_sendmessage” is called to issue a response to the user, with the result of their command – this is only attempted once and otherwise simply fails, but it would be possible to queue these up also and attempt to process in order.

I did for a short time toy with the idea of porting Zork to work on RouterOS before remembering I have a full-time job, a wife and much worse programming skills than routing ones.. 🙂

You can message my router by telegramming @AURouter_bot – note the first response will take up to a minute to appear, then subsequent ones will appear faster.

Scripts in their entirety here:

This can be copied and pasted into RouterOS v6.46:

Don’t forget to update the BOTID + TELEGRAM USER ID in telegram_bot_main or you won’t be able to retrieve updates, or you’ll only be responding to unauthed messages.

/system scheduler add interval=50s name=telegram_bot on-event=":local scriptname \"telegram_bot_main\"\r\
    \n#:if ([:len [/system script job find script=\$\"scriptname\"]] > 0) do={\r\
    \n#:log warning \"\$scriptname Already Running - killing old script before continuing\"\r\
    \n#:foreach counter in=[/system script job find script=\$\"scriptname\"] do={\r\
    \n#/system script job remove \$counter\r\
    \n#}\r\
    \n#}\r\
    \n/system script run \$scriptname" policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-time=startup
/system script
add dont-require-permissions=yes name=telegram_bot_main policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":global botID \"BOT_ID_STUFF_GOES_HERE\" \r\
    \n:global mychat \"YOURTELEGRAM_ID_GOES_HERE\"\r\
    \n:global urlStart \"https://api.telegram.org/bot\"\r\
    \n\r\
    \n#max updates to pull down at once\r\
    \n:local updatelimit 100\r\
    \n#set to 50s or less\r\
    \n:local maxpolldelay 50\r\
    \n\r\
    \n#Functions\r\
    \n:global processupdates [:parse [/system script get telegram_bot_processupdates source]]\r\
    \n:global messageauth [:parse [/system script get telegram_bot_message_auth source]]\r\
    \n:global messageunauth [:parse [/system script get telegram_bot_message_unauth source]]\r\
    \n:global sendmessage [:parse [/system script get telegram_bot_sendmessage source]]\r\
    \n:global sendlog [:parse [/system script get telegram_bot_log source]]\r\
    \n:global leavechat [:parse [/system script get telegram_bot_leavechat source]]\r\
    \n:global updateoffset [:parse [/system script get telegram_bot_updateoffset source]]\r\
    \n\r\
    \n\$sendlog msg=\"=====Beginning Cycle=====\"\r\
    \n\r\
    \n:global telegramdelay\r\
    \n:local telegramdelaycurrent [/system scheduler get [find name=telegram_bot] interval]\r\
    \n\r\
    \n:local fetchURL (\"/getUpdates\\\?limit=\" . \$updatelimit . \"&allowed_updates=message\")\r\
    \n\$sendlog msg=(\"GETURL: \" . \$fetchURL); :set fetchURL (\$urlStart . \$botID . \$fetchURL);\r\
    \n:local content [/tool fetch url=\$fetchURL as-value output=user]\r\
    \n\r\
    \n#if new message exists send to updateprocessingqueue\r\
    \n:if ((\$content->\"status\") = \"finished\" && [:len (\$content->\"data\")] > 33) do={\r\
    \n  :local contentdata (\$content->\"data\")\r\
    \n  \$processupdates updatecontent=(\$contentdata)\r\
    \n} else={\r\
    \n  \$sendlog msg=(\"Status: \" .(\$content->\"status\") . \" - No new data to process\")\r\
    \n  :if (\$telegramdelay < \$maxpolldelay) do={\r\
    \n    :set telegramdelay (\$telegramdelay + 10)\r\
    \n\t\$sendlog msg=(\"Increased delay to \" . \$telegramdelay . \"s\")\r\
    \n  }\r\
    \n}\r\
    \n\r\
    \n:if ([:pick \$telegramdelaycurrent 6 [:len \$telegramdelaycurrent]] != \$telegramdelay) do={\r\
    \n  /system scheduler set [find name=telegram_bot] interval=(\"00:00:\" . \$telegramdelay)\r\
    \n}"
add dont-require-permissions=no name=telegram_bot_sendmessage policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#Functions\r\
    \n:global sendlog \r\
    \n\r\
    \n\$sendlog msg=\"RUN: sendmessage\"\r\
    \n\r\
    \n:global urlStart\r\
    \n:global botID\r\
    \n:local content\r\
    \n:local fetchURL\r\
    \n\r\
    \n\$sendlog msg=(\"Sending message to \$chatid\")\r\
    \n\r\
    \n:set fetchURL (\"/sendmessage\\\?chat_id=\" . \$chatid . \"&text=\" . \$text)\r\
    \n\$sendlog msg=(\"GETURL: \" . \$fetchURL); :set fetchURL (\$urlStart . \$botID . \$fetchURL);\r\
    \n:set content [/tool fetch url=\$fetchURL as-value output=user]\r\
    \n\r\
    \n:if ((\$content->\"status\") = \"finished\") do={\r\
    \n  \$sendlog msg=\"Message sent successfully\"\r\
    \n} else={\r\
    \n  \$sendlog msg=\"Message sent failed\"\r\
    \n}\r\
    \n\$sendlog msg=\"END: sendmessage\""
add dont-require-permissions=no name=telegram_bot_message_unauth policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#Functions\r\
    \n:global sendmessage\r\
    \n:global sendlog\r\
    \n\r\
    \n\$sendlog msg=\"RUN: message_unauth\"\r\
    \n\r\
    \n:local unauthcmd 0;\r\
    \n:local tmsg\r\
    \n\r\
    \n##### Commands that can be run unauthenticated ####\r\
    \n\r\
    \n  :if (message = \"wifi\") do={:set unauthcmd 1;\r\
    \n    \$sendlog msg=\"Response: wifi\"\r\
    \n    :local registrations [:len [/caps-man registration-table find]]\r\
    \n    :set tmsg \"There are \$registrations wireless registrations\"\r\
    \n  }\r\
    \n  \r\
    \n  :if (message = \"internet\") do={:set unauthcmd 1;\r\
    \n    \$sendlog msg=\"Response: internet\"\r\
    \n    :local internetspeed\r\
    \n    /interface monitor-traffic ether1 once do={:set internetspeed ((\$\"rx-bits-per-second\"/1000) . \"kbps/\" . (\$\"tx-bit\
    s-per-second\"/1000) . \"kbps\")}\r\
    \n    :set tmsg \"Current internet bandwidth: \$internetspeed\"\r\
    \n  }\r\
    \n  \r\
    \n  :if (message = \"blink\") do={:set unauthcmd 1;\r\
    \n    \$sendlog msg=\"Response: blink\"\r\
    \n\t:blink\r\
    \n    :set tmsg \"Somewhere far away you're making a light blink.. aren't you fancy!\"\r\
    \n  }\r\
    \n  \r\
    \n  :if (message = \"beep\") do={:set unauthcmd 1;\r\
    \n    \$sendlog msg=\"Response: beep\"\r\
    \n\t:beep \r\
    \n    :set tmsg \"Keep that up and you're going to drive the network admin mad!\"\r\
    \n  }\r\
    \n  \r\
    \n  :if (message ~\"^ping \") do={:set unauthcmd 1;\r\
    \n    \$sendlog msg=(\"Response: ping specified host\")\r\
    \n    :local pingrx\r\
    \n    :local pingrtt\r\
    \n    :local pinghost [:pick \$message 5 [:len \$message]]\r\
    \n    :do {\r\
    \n      /tool flood-ping count=5 [\$pinghost] do={:set pingrtt (\$\"max-rtt\"); :set pingrx (\$\"received\");}\r\
    \n    } on-error={\r\
    \n      \$sendlog msg=(\"Ping command failed\")\r\
    \n      :set pingrx 0;\r\
    \n    }\r\
    \n    :if (\$pingrx > 0) do={\r\
    \n      :set tmsg (\"PONG: Max \" . \$pingrtt . \"ms from \" . \$pinghost . \" with \" . \$received . \"/5 responses\")\r\
    \n    } else={\r\
    \n      :set tmsg (\"PONG: No response from \$pinghost\")\r\
    \n    }\r\
    \n  }\r\
    \n  \r\
    \n##### Final command if no unathenticated command is matched ####\r\
    \n  \r\
    \n  :if (\$unauthcmd = 0) do={\r\
    \n    \$sendlog msg=\"Response: No valid unauth cmd\"\r\
    \n    :set tmsg \"Invalid command, try: wifi,internet,blink,ping <ip>,beep (all lower case)\"\r\
    \n  }\r\
    \n  \r\
    \n## Send message ##\r\
    \n  :if ([:len \$tmsg] > 0) do={\r\
    \n    \$sendlog msg=(\"Trigger sendmessage function for \$chatid with content: \$tmsg\")\r\
    \n    \$sendmessage chatid=(\$chatid) text=(\$tmsg)\r\
    \n  } else={\r\
    \n    \$sendlog msg=\"No response to send\"\r\
    \n  }\r\
    \n\r\
    \n"
add dont-require-permissions=no name=telegram_bot_log policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=\
    "#Comment this line out if you don't want logging to happen\r\
    \n:log info \"\$msg\""
add dont-require-permissions=no name=telegram_bot_processupdates policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#Functions\r\
    \n:global messageauth\r\
    \n:global messageunauth\r\
    \n:global sendmessage\r\
    \n:global sendlog\r\
    \n:global leavechat\r\
    \n:global updateoffset\r\
    \n\r\
    \n\$sendlog msg=\"RUN: processupdates\"\r\
    \n\r\
    \n:global mychat\r\
    \n:global urlStart\r\
    \n:global botID\r\
    \n:global telegramdelay\r\
    \n:local fetchURL\r\
    \n:local content\r\
    \n:local start 0\r\
    \n:local end 0\r\
    \n:local update \"string\"\r\
    \n:local message \"string\"\r\
    \n:local chatid \"string\"\r\
    \n:local chattype \"string\"\r\
    \n\r\
    \n:local nextupdatestart\r\
    \n\r\
    \n:local processcontent (\$updatecontent)\r\
    \n:local contentchunk\r\
    \n\$sendlog msg=(\"Process queue length: \" . [:len \$processcontent])\r\
    \n\r\
    \n:while ([:len \$processcontent] > 0) do={\r\
    \n  \$sendlog msg=(\"Proccess length remaining: \" . [:len \$processcontent])\r\
    \n\r\
    \n#Determine if multiple updates are present (update1)\r\
    \n  :set start [:find \$processcontent \"\\22update_id\\22:\"]\r\
    \n  :set start (\$start + 12)\r\
    \n  :set nextupdatestart ([:find \$processcontent \"\\22update_id\\22:\" \$start] -1)\r\
    \n  :if (\$nextupdatestart < 1) do={:set nextupdatestart [:len \$processcontent]}\r\
    \n  \$sendlog msg=(\"Start location: \$start | Next update start: \$nextupdatestart\")\r\
    \n  :set contentchunk [:pick \$processcontent (\$start - 14) (\$nextupdatestart)]\r\
    \n\r\
    \n#breakup contentchunk into component variables\r\
    \n  :set start [:find \$contentchunk \"\\22update_id\\22:\" 0]\r\
    \n  :set start (\$start + 12)\r\
    \n  :set end [:find \$contentchunk \",\" \$start]\r\
    \n  :set update ([:pick \$contentchunk \$start \$end])\r\
    \n  \r\
    \n  \$sendlog msg=(\"Update ID: \$update\")\r\
    \n  \r\
    \n  :set start [:find \$contentchunk \"\\22text\\22:\" 0]\r\
    \n  :set start (\$start  + 8)\r\
    \n  :set end [:find \$contentchunk \"\\22\" \$start]\r\
    \n  :set message [:pick \$contentchunk \$start \$end]\r\
    \n  \r\
    \n  \$sendlog msg=(\"Received Message: \$message\")\r\
    \n  \r\
    \n  :set start [:find \$contentchunk \"\\22id\\22:\"]\r\
    \n  :set start (\$start + 5)\r\
    \n  :set end [:find \$contentchunk \",\" \$start]\r\
    \n  :set chatid [:pick \$contentchunk \$start \$end]\r\
    \n  \r\
    \n  :set start [:find \$contentchunk \"\\22chat\\22:\"]\r\
    \n  :set start [:find \$contentchunk \"\\22type\\22:\"]\r\
    \n  :set start (\$start + 8)\r\
    \n  :set end [:find \$contentchunk \",\" \$start]\r\
    \n  :set chattype [:pick \$contentchunk (\$start) (\$end -2)]\r\
    \n \r\
    \n  \$sendlog msg=(\"From Chat ID: \$chatid - Type: \$chattype\")\r\
    \n  \r\
    \n#is a group\? Leave and update offset\r\
    \n:if (\$chattype != \"private\") do={\r\
    \n  \$leavechat leaveroom=(\"\$chatid\") leaveupdateid=(\$update)\r\
    \n} else={\r\
    \n#is authed user\?\r\
    \n  :if (\$chatid = \$mychat) do={\r\
    \n    \$sendlog msg=(\"Run message_auth for \$chatid\")\r\
    \n    \$messageauth message=(\$message) chatid=(\$chatid)\r\
    \n  } else={\r\
    \n    \$sendlog msg=(\"Run message_unauth for \$chatid\")\r\
    \n    \$messageunauth message=(\$message) chatid=(\$chatid)\r\
    \n  }\r\
    \n}\r\
    \n#Trim content \r\
    \n  :set \$processcontent [:pick \$processcontent (\$nextupdatestart) [:len \$processcontent]]\r\
    \n\r\
    \n#end of while loop\r\
    \n}\r\
    \n\r\
    \n#send update offset\r\
    \n\$updateoffset updateid=(\$update)\r\
    \n\r\
    \n:if (\$telegramdelay > 10) do={\r\
    \n  :set telegramdelay (10)\r\
    \n  \$sendlog msg=(\"Reset delay to minimum \" . \$telegramdelay . \"s\")\r\
    \n}\r\
    \n\r\
    \n\$sendlog msg=\"END: processupdates\""
add dont-require-permissions=no name=telegram_bot_message_auth policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#Functions\r\
    \n:global sendmessage\r\
    \n:global sendlog \r\
    \n\r\
    \n\$sendlog msg=\"RUN: message_auth\"\r\
    \n\r\
    \n:local authcmd 0;\r\
    \n:local tmsg\r\
    \n\r\
    \n\r\
    \n  :if ([:len [/system script find name=\$message]] > 0) do={\r\
    \n    \$sendlog msg=(\"Script: \$message run by \$chatid\")\r\
    \n    /system script run \$message\r\
    \n  } else={\r\
    \n    :if (\$message = \"List\") do={\r\
    \n      \$sendlog msg=\"listing scripts\"\r\
    \n      :local scriptnames\r\
    \n      :foreach counter in=[/system script find] do={\r\
    \n        :set scriptnames (\$scriptnames . \",\" . [/system script get \$counter name])\r\
    \n      }\r\
    \n      :local authmessage \"Scripts: \$scriptnames\"\r\
    \n      \$sendmessage chatid=\$chatid text=\$authmessage\r\
    \n    } else={\r\
    \n      \$sendlog msg=\"Unknown cmd\"\r\
    \n      \$sendmessage chatid=\$chatid text=\"Unknown cmd\"\r\
    \n    }      \r\
    \n  }"
add dont-require-permissions=no name=telegram_bot_leavechat policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#Functions\r\
    \n:global sendlog \r\
    \n:global updateoffset\r\
    \n\$sendlog msg=\"RUN: leavechat\"\r\
    \n\r\
    \n:global urlStart\r\
    \n:global botID\r\
    \n:local content\r\
    \n:local fetchURL\r\
    \n\r\
    \n:set fetchURL (\"/leaveChat\\\?chat_id=\" . \$leaveroom)\r\
    \n\$sendlog msg=(\"GETURL: \" . \$fetchURL); :set fetchURL (\$urlStart . \$botID . \$fetchURL);\r\
    \n:execute {:set content [/tool fetch url=\$fetchURL as-value output=user]}\r\
    \n\r\
    \n\$updateoffset updateid=(\$leaveupdateid)\r\
    \n"
add dont-require-permissions=no name=telegram_bot_updateoffset policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#Functions\r\
    \n:global sendlog \r\
    \n\$sendlog msg=\"RUN: updateoffset\"\r\
    \n\r\
    \n:global urlStart\r\
    \n:global botID\r\
    \n:global telegramdelay\r\
    \n:local fetchURL\r\
    \n:local content\r\
    \n\r\
    \n:local update (\$updateid + 1)\r\
    \n\r\
    \n#send update offset\r\
    \n:set fetchURL (\"/getUpdates\\\?offset=\" . \$update . \"&limit=1&allowed_updates=message\")\r\
    \n\$sendlog msg=(\"GETURL: \" . \$fetchURL); :set fetchURL (\$urlStart . \$botID . \$fetchURL);\r\
    \n:set content [/tool fetch url=\$fetchURL as-value output=user]\r\
    \n\r\
    \n:if ((\$content->\"status\") = \"finished\") do={\r\
    \n  \$sendlog msg=\"Update offset success\"\r\
    \n} else={\r\
    \n  \$sendlog msg=\"Update offset failed\"\r\
    \n}"

If you have any questions – or come up with some unique ideas for what you can do with something like this, share them here!

MikroTik Audience – review and teardown

I was fortunate enough to get my hands on a pair of MikroTik Audience devices to put through their paces. The Audience is a new device from MikroTik, and perhaps one of the first I’ve seen that is specifically targeted to a home environment, with the stylish exterior designed not just to be a wireless powerhouse but look suitable to be placed on a shelf and give a better connectivity experience to boot.

can’t do meshing with just one..

First impressions

MikroTik are hitting some home runs with design and professionalism recently. This seems like the next step in the evolution from wAP form factor and Wireless Wire kit we have the Audience – and upgrade to both router design and packaging, opening the Audiences is more akin to an apple unboxing than anything else to come out of Mikrotik. Sure it’s nice that the boxing is still relatively simple and recyclable, but it LOOKS like what you’d expect a high end home router to look like; and I’d have no trouble selling this to someone as an upgrade on whatever they’re using now (it really is, but we’ll get to this..).

Teardown

Because I’m a heartless bastard and I know so many Latvians worked for years to create this device, I had to take one of them apart straight away before powering it up. More importantly, I had to try and do this without breaking anything, because I have to put it back together and test it afterwards. Easier said than done, but possible!

Check out the gallery of photos below with instructions on how to disassemble the device, if you’re that way inclined.

Performance

Onto the performance, this device has quad core 716MHz CPU which can be pushed as high as 896MHz (if you’re the sort of person who feels the need to overclock your router) or as low as 488MHz if you plan on the heatsink being a paperweight. During my testing I was unable to max out CPU utilisation while performing any basic routing or wireless functions and as per MikroTik’s testing this should be capable of a few hundred megabits of IPSec encrypted traffic if you have need of it. There are 3 distinct wireless cards available:

  1. 2.4GHz dual chain card (antenna on the board -used for clients)
  2. 5GHz dual chain card (antenna on the board – used for clients)
  3. 5GHz quad chain card (antenna array mounted above board – used for mesh)

Technically there’s nothing stopping a power-user from re-configuring the second 5GHz wireless card as another access point for clients, and if you just had the one Audience device I would probably recommend this for the better MIMO performance – however it was designed with a specific goal in mind – which is meshing.

In my testing – the meshing radios were able to hold a reasonable connection (consistent 60Mbps throughput using btest) through 4 double brick walls and one wooden garage wall. I placed one unit in my lounge room and the second in the detached garage at the other end of the property (a distance of about 24M / 78 feet).

By comparison, previously I have used a set of (non MikroTik) Ethernet over power adapters to deliver 60~Mbps from my office to the ground floor of this house, due to a lack of Ethernet cabling, but switching to the audience units has given me a reliable 300Mbps over the mesh wireless link in the ‘factory’ configuration, or as high as 500Mbps (through 2 walls and up one level) when adjusting the configuration of the mesh radios to use an 80MHz channel.


Even without using the mesh functions I did not coverage around the house also increased noticeably with just the one unit. I suspect some of this is a byproduct of being able to locate the AP on top of furniture, and the antennas being well positioned for good ‘home’ coverage due to the router being stood upright (vs a hAP ac2 which can be mounted on a wall/inside a cupboard/stood on its side).

It’s worth noting at this point – using quickset to configure this device actually employs the use of CAPsMAN to configure each wireless radio (including those of any repeaters) which is the first I’ve seen a product making use of MikroTik own built-in wireless control system.

Negatives / Wishlist

I am sold on the Audience and suspect I will continue using it as my primary AP(s) at home until something better comes along, but that’s not to say I don’t have some gripes.

  1. Port density – yes it’s a pretty router designed to sit up on a bench.. but maybe a stackable switch module (in the same partner-approved style) wouldn’t go astray? Or just one more Ethernet port.. there’s room in there for 3!
  2. PoE out – given WISPs and FISPs are supporters of MikroTik I would have thought it made sense to include a PoE out/pass-through option of some kind – because hey if it can power the radio on the roof, or even another Audience AP nearby.. that’s a useful feature! But the hAP ac2 is also missing this function so I’m not as surprised.
  3. USB support (either internal or externally accessible) would have been useful – yes there’s an LTE version available but the device is targeted at the home market.. how are they going to use the SMB functions now?!

Conclusion

The MikroTik Audience is a well designed and thoroughly capable wireless home router at a price point enticing for gamers and power-users alike. While it lacks the physical connectivity options of some competing platforms, everything about the device makes it clear it wasn’t design to sit connected to a modem/radio or ONT gathering dust in the cupboard – it is well positioned to deliver on the promises of better wireless by providing a platform that looks and feels like part of a modern home and in light of this I can’t wait to see what comes next.

RouterOS Bridge and Vlan Configuration for CRS devices on v6.43.X

I’ve seen a few posts recently in the MikroTik forums and MikroTik Subreddit about the confusing nature of creating native (wirespeed) vlans on the CRS range of hardware and wanted to put together a template that gives you a good idea of how these work, and what the configuration of a few different port types looks like.

While I will go into more detail on this soon – the following (designed for a CRS328-24P-4S+RM) has:

  • PC Connected ports
  • PC Connected ports with support for an inline VoIP Phone
  • Tagged/Untagged ports for Access Point administration and wireless network passthrough
  • Untagged port for a server
  • Tagged Trunk ports for passing vlans between switches
  • Adding an IP address to an Admin vlan for access to the configured switch
Continue reading RouterOS Bridge and Vlan Configuration for CRS devices on v6.43.X

Automatic bypass of hotspot devices based on MAC Address

Recently I was doing some work for a hotel that supplies a ‘Smart TV’ device with Netflix and other functions in every room. These rooms are in turn all connected to a hotspot network and the TV’s all needed to be given internet access.

As this was (as sometimes occurs) an unexpected addition to the known requirements of the installation, it fell to me to come up with a way to add these – preferably without having to have someone walk around manually collect details for 300+ TV’s.

Continue reading Automatic bypass of hotspot devices based on MAC Address

Scriptlet: Bulk VPN connections on MikroTik with connection rate limiting

During my day job we use some MikroTik CHR deployments for (among other things) VPN session termination. The CHR’s are easy to spin up, offer a wide variety of VPN types, and for low traffic sessions can support upwards of 10,000 sessions on a single device.

It’s over 9000!

In the event of an outage though, you would run into a problem – those 10,000 sessions all want to re-establish at once.. and the CPU on the MikroTik quickly bottlenecks until it becomes unable to cope and begins to drop connections quickly becoming a vicious cycle.

We initially dealt with this by defining a hard limit on the number of new sessions per second, using 2 simple firewall rules and the connection limit classifier to keep these under 10 per second – however this meant that after an outage it would take at absolute minimum, over 15 minutes for all the sessions to come back online! So we came up with a better solution. Continue reading Scriptlet: Bulk VPN connections on MikroTik with connection rate limiting