-
Notifications
You must be signed in to change notification settings - Fork 98
MAC Telnet connection
🆕 New in tik4net 4.0 — first released as
v4.0.0-alpha. Alpha: API and behaviour are stable for testing but may still change before the final 4.0 release. See Connection types & capabilities.
MAC-Telnet (TikConnectionType.MacTelnet) connects to a MikroTik router over UDP port 20561 using
the MikroTik MAC-layer protocol — without requiring an IP route to the router. This is useful for:
- Recovery — accessing a router that has no reachable IP address
- Bootstrap — configuring a freshly reset device before assigning it an address
- Local-only access — devices isolated to a management VLAN without routing
Authentication uses EC-SRP5 (Elliptic-Curve Secure Remote Password), the same mechanism as WinBox. After auth the session carries a plain VT100 terminal (unencrypted). tik4net drives it with the same CLI layer used by the Telnet transport, so all CRUD operations work identically.
Enable the MAC Telnet server on the router:
/tool/mac-server set allowed-interface-list=all
Or restrict to a specific interface list:
/tool/mac-server set allowed-interface-list=management
The router's MAC address is discovered automatically via MNDP (see MNDP) — no manual configuration needed as long as the router responds to MNDP broadcasts on your subnet.
using tik4net;
using tik4net.MacTelnet;
// MNDP discovers the router MAC automatically (takes up to 5 s)
using (var conn = ConnectionFactory.OpenConnection(
TikConnectionType.MacTelnet, "192.168.4.1", "admin", ""))
{
var ifaces = conn.LoadAll<tik4net.Objects.Interface.Interface>().ToList();
Console.WriteLine($"Found {ifaces.Count} interfaces");
}MNDP discovery waits up to 5 seconds for the router to respond. If you already know the router's MAC
address, skip the wait by setting RouterMac on the connection object:
var conn = new MacTelnetConnection { RouterMac = "AA:BB:CC:DD:EE:FF" };
conn.Open("192.168.4.1", "admin", "");
// or via TikConnectionSetup:
var setup = new TikConnectionSetup("192.168.4.1", "admin", "");
using (var conn2 = setup.CreateMacTelnetConnection(routerMac: "AA:BB:CC:DD:EE:FF"))
{
// ...
}var setup = new TikConnectionSetup("192.168.4.1", "admin", "");
// MNDP-based (default)
using (var conn = setup.CreateMacTelnetConnection())
{
// ...
}
// async
using (var conn = await setup.CreateMacTelnetConnectionAsync(routerMac: "AA:BB:CC:DD:EE:FF"))
{
// ...
}The login waits for the RouterOS shell prompt up to ConnectTimeout (default 15 s), separately from
the per-command ReceiveTimeout (default 30 s). Lower it when you wrap Open in your own connect-retry
loop so a stuck login fails fast enough to retry:
var conn = new MacTelnetConnection { RouterMac = "AA:BB:CC:DD:EE:FF", ConnectTimeout = 10000 };
conn.Open("192.168.4.1", "admin", "");
// via TikConnectionSetup (its ConnectTimeout flows into the connection):
var setup = new TikConnectionSetup("192.168.4.1", "admin", "") { ConnectTimeout = TimeSpan.FromSeconds(10) };
using (var conn2 = setup.CreateMacTelnetConnection(routerMac: "AA:BB:CC:DD:EE:FF")) { /* ... */ }CRUD and Listen — MAC-Telnet reports Crud | Listen, like all CLI transports, so the callback-based
async APIs work in addition to synchronous CRUD. A terminal has no server push, so the async commands are
emulated by polling a one-shot snapshot on a background worker:
| Call shape | Example | How it works |
|---|---|---|
| Streaming monitor |
/interface/monitor-traffic, /tool/profile
|
re-issues :put [… <once> as-value] (snapshot modifier per command) every ~500 ms and pushes each polled record to your row callback |
| Finite command |
/ping, /tool/traceroute
|
runs once (its own count/duration bounds it), emits the rows, completes |
| Change listen | conn.LoadListenAsync<Interface>(onChange, onDeleted, …) |
polls the table and diffs by .id — a changed row fires onChange, a vanished .id fires onDeleted
|
| Async list |
cmd.LoadAsync<Interface>(…) on a /print
|
runs the read on a background thread, emits each row, completes |
bool hasCrud = conn.Supports(TikConnectionCapability.Crud); // true
bool hasListen = conn.Supports(TikConnectionCapability.Listen); // trueTikConnectionCapability.Streaming (ExecuteListWithDuration) is not reported — use the API transport
for that. Interactive-only commands (notably /tool/torch, which repaints a VT100 screen with no
as-value snapshot) surface a guiding error through the async error callback; use the API for those. Polling
over the MAC layer is slower than over TCP — prefer the SSL API for high-rate monitoring
when an IP route is available.
- The router's MAC address is resolved via MNDP (UDP 5678). If your host has multiple NICs, tik4net prefers the one on the same subnet as the router — this avoids picking Hyper-V or VPN virtual adapters.
- SESSIONSTART is sent as a subnet broadcast; DATA and ACK packets use unicast to the router's IP.
- The session is unencrypted after EC-SRP5 auth — suitable for local management networks only.
- MAC-Telnet is deprecated in newer RouterOS versions in favour of SSH, but remains functional.
The MAC-Telnet implementation builds on protocol research by the MikroTik reverse-engineering community:
- subixonfire/winbox-terminal-protocol (MIT) — primary reference for Curve25519 EC-SRP5 authentication math and AES-128/HMAC stream key derivation.
-
winbox_terminal_client.py (same community) —
gen_stream_keysand custom HKDF expand algorithm. - KC.MacTelnet — C# reference implementation that confirmed the big-endian encoding of the 22-byte MAC-layer header fields (session_key, client_type); a subtle protocol detail that caused silent session rejection when encoded as little-endian.
- MNDP — router discovery without a connection
- SSL-connection — encrypted API connection
- Roadmap-4x — transport roadmap