mikrotik - RouterOS API client
Import with import "mikrotik.j" as mikrotik;. Connect to a MikroTik RouterOS
device over its binary API (not SSH) and run commands. The API is plain TCP
(8728) or api-ssl (8729 over TLS); its wire protocol is sentence-based - a
sentence is a run of length-prefixed words ending in a zero-length word. Built
on net (+ TLS), with an MD5 fallback via hash. Needs
the default jennifer binary. A !trap / !fatal reply throws
Error{kind: "mikrotik"}.
import "mikrotik.j" as mikrotik;
def s as mikrotik.Session init mikrotik.connect(mikrotik.options("192.168.88.1", "admin", "secret"));
def ifaces as list of map of string to string init mikrotik.print($s, "/interface");
def id as string init mikrotik.run($s, "/ip/address/add", {}); # (with attrs)
mikrotik.close($s);
Runnable: examples/modules/mikrotik_demo.j.
Why the API, not SSH
A real SSH client needs key exchange, host-key verification, and cipher / MAC negotiation - the whole crypto surface plus a heavy dependency, against the dependency-free, TinyGo-clean stance. The RouterOS API is the purpose-built, crypto-optional door: plaintext auth over plain TCP, or confidentiality via api-ssl (TLS), exactly like the mail clients.
Connecting
Login is plaintext (=name= / =password=, RouterOS 6.43+ and all v7); for
pre-6.43 routers the client automatically falls back to the MD5
challenge-response (which only needs hash.compute(b, "md5")).
def struct mikrotik.Options { host as string, port as int, user as string, password as string, tls as bool };
def struct mikrotik.Session { socket as net.Conn };
| Call | Returns | |
|---|---|---|
mikrotik.options(host, user, password) | Options | plain TCP, port 8728 |
mikrotik.optionsTLS(host, user, password) | Options | api-ssl (TLS), port 8729 |
mikrotik.withPort(o, port) | Options | copy with a different port |
mikrotik.connect(opts) | Session | connect and log in |
mikrotik.close(s) | close the connection |
Commands
A command is a menu path (/interface/print); attributes are a map of string to string sent as =key=value words. Each !re reply sentence folds into one
row map.
| Call | Returns | |
|---|---|---|
mikrotik.talk(s, command, attrs) | list of map of string to string | the general call - the !re reply rows |
mikrotik.print(s, path) | list of map of string to string | read sugar for path + "/print" |
mikrotik.run(s, command, attrs) | string | for add / set / remove - returns the !done =ret= (e.g. a new item id) |
# read
for (def iface in mikrotik.print($s, "/interface")) {
# $iface["name"], $iface["type"], $iface["running"]
}
# add (run returns the new item's id)
def attrs as map of string to string init {};
$attrs["address"] = "10.0.0.1/24";
$attrs["interface"] = "ether1";
def newId as string init mikrotik.run($s, "/ip/address/add", $attrs);
Scope
- Binary API, v6 and v7. The v7 REST API (HTTP + JSON) is a different, stateless shape and a possible second backend later; v1 ships the binary API.
- Synchronous
talk. Query words (?name=value) and.tag-multiplexed concurrent commands are follow-ons - each call runs to its!donebefore the next. !trapthrows. A command error surfaces asError{kind: "mikrotik"}(the trailing!doneis consumed first, so the session stays usable); a!fatal(connection closing) throws immediately.- String values. Attributes and reply fields are strings, exactly as the API carries them - parse numbers / booleans yourself.
See also
- net.md - the TCP / TLS transport (+
connectTLSfor api-ssl). - mqtt.md / amqp.md - the other hand-framed binary protocol clients.
- modules/index.md - the module catalog and import rules.