Automatically download RouterOS Packages for The Dude Network Monitor

We are a heavy user of Mikrotik hardware and the RouterOS operating system in general. We’ve found that managing device firmware upgrades across all of our clients to be cumbersome. While Mikrotik offers ‘The Dude’ (https://mikrotik.com/thedude) packages still have to be downloaded manually and then transferred to the Dude server.

As such we’ve written a small shell script which exports all firmware package URLs from https://mikrotik.com/download and makes them available at http://public.open-it.com.au/mikrotik/npk_urls.txt

This file is re-generated every half hour.

Using these raw URLs it is possible to write a script as per below, which RouterOS can periodically run in order to fetch all packages.

Notes:

  • All files are overwritten if existing on each run. This isn’t an issue for us as we have plenty of bandwidth available at our main site, however if anyone wants to implement a check I’d be happy to host it here.
  • Your Dude server requires internet access
  • All NPK files are signed by Mikrotik and theoretically, if malicious packages were provided / our hosting was compromised your hardware should reject them.

Feel free to message me regarding any amendments at https://www.linkedin.com/in/kyle-kemeridis-657066a8/

The following runs every half hour to generate the file, it’s that simple

curl https://mikrotik.com/download > page.html
cat page.html | grep -Eoi "(http|https)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?.npk" > /path/to/text/file.txt

Use the following script on your device running the Dude, update the path for file downloads appropriately if required.


/tool fetch url=http://public.open-it.com.au/mikrotik/npk_urls.txt;
if ( [/file get [/file find name=npk_urls.txt] size] > 0 ) do={
:global content [/file get [/file find name="npk_urls.txt"] contents] ;
:global contentLen [ :len $content ] ;
:global lineEnd 0;
:global line "";
:global lastEnd 0;
:do {
:set lineEnd [:find $content "\n" $lastEnd ] ;
:set line [:pick $content $lastEnd $lineEnd] ;
:set lastEnd ( $lineEnd + 1 ) ;
:if ( [:pick $line 0 1] != "#" ) do={
:local entry [:pick $line 0 ($lineEnd) ]
:if ( [:len $entry ] > 0 ) do={
/log info $entry;
/tool fetch url=$entry dst-path=disk1/dude-data/files/;
}
}
} while ($lineEnd < $contentLen - 1) } /file remove npk_urls.txt;

Terminal Friendly:

/system script
add dont-require-permissions=no name=download_ros_packages owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/tool fetch url=http://public.open-it.com.au/mikrotik/npk_urls.txt;\r\
\nif ( [/file get [/file find name=npk_urls.txt] size] > 0 ) do={ \r\
\n :global content [/file get [/file find name=\"npk_urls.txt\"] contents] ;\r\
\n :global contentLen [ :len \$content ] ; \r\
\n :global lineEnd 0;\r\
\n :global line \"\";\r\
\n :global lastEnd 0; \r\
\n :do {\r\
\n :set lineEnd [:find \$content \"\\n\" \$lastEnd ] ;\r\
\n :set line [:pick \$content \$lastEnd \$lineEnd] ;\r\
\n :set lastEnd ( \$lineEnd + 1 ) ; \r\
\n :if ( [:pick \$line 0 1] != \"#\" ) do={ \r\
\n :local entry [:pick \$line 0 (\$lineEnd) ]\r\
\n :if ( [:len \$entry ] > 0 ) do={\r\
\n/log info \$entry;\r\
\n/tool fetch url=\$entry dst-path=disk1/dude-data/files/;\r\
\n }\r\
\n }\r\
\n } while (\$lineEnd < \$contentLen - 1)\r\ \n }\r\ \n/file remove npk_urls.txt;\r\ \n\r\ \n"