Skip to content

WinBox Native connection

Danik edited this page Jun 16, 2026 · 7 revisions

WinBox Native (M2) Connection 🆕 4.x ⚠️ Alpha-preview

🆕 New in tik4net 4.x — not yet publicly released. Like every non-API transport it ships on the upcoming 4.x line; only the binary Api / ApiSsl transports are stable. See Connection types & capabilities.

Alpha-preview. This transport is the newest and least battle-tested in tik4net. The API/field mapping is reconstructed from the WinBox .jg catalog and covers common tables, but exotic tables/verbs may need a PathOverride/FieldOverride, and details may still change. For production use prefer the API or, on the WinBox channel, the WinBox CLI transport. Bug reports and mapping fixes are welcome.

WinBox Native (TikConnectionType.WinboxNative) connects over the encrypted WinBox channel on TCP port 8291 — the same port and crypto as the WinBox application — but instead of driving a terminal it issues structured M2 protocol calls (the binary key–value messages WinBox itself uses). CRUD maps directly to the native getall / get / set / add / remove / move handlers, so there is no CLI screen-scraping involved.

Authentication is identical to WinBox CLI: EC-SRP5 + AES-128-CBC (legacy MD5 fallback for RouterOS < 6.43). The difference is purely above the channel: native M2 vs. a mepty terminal.

using System.Linq;
using tik4net;

using (var conn = ConnectionFactory.OpenConnection(
    TikConnectionType.WinboxNative, "192.168.4.1", "admin", ""))
{
    var ifaces = conn.LoadAll<tik4net.Objects.Interface.Interface>().ToList();
    foreach (var i in ifaces)
        conn.CreateCommandAndParameters("/interface/set", ".id", i.Id, "comment", "managed").ExecuteNonQuery();
}

Via TikConnectionSetup — the recommended way, because its configure callback runs before the connection opens, which is exactly where the mapping overrides below must be set:

var setup = new TikConnectionSetup("192.168.4.1", "admin", "");

using (var conn = setup.CreateWinboxNativeConnection(c =>
{
    c.PathOverride("/ppp/secret", new[] { 27, 101 });
    c.CatalogCachePath = @"C:\ProgramData\myapp\winbox-cache";
}))
{
    // ...
}

// async
using (var conn = await setup.CreateWinboxNativeConnectionAsync())
{
    // ...
}

Direct construction also works (set the properties below, then Open):

using tik4net.WinboxNative;

var conn = new WinboxNativeConnection { ConnectTimeout = 10000 };
conn.Open("192.168.4.1", "admin", "");

Why a native mode at all?

The CLI transports (Telnet / MAC-Telnet / WinBox CLI) parse print as-value text. Native M2 avoids the terminal entirely: it is faster, has no prompt/echo/paging edge cases, and is closer to how the WinBox GUI talks to the router. The trade-off is the mapping problem described next.

The mapping problem: API names ↔ WinBox keys

The MikroTik API addresses things by text: a path like /ip/firewall/filter and field names like src-address or connection-state. The WinBox M2 protocol addresses the same things by numbers: a handler array like [20,3] and integer field keys like 0xFE0009. To make the O/R mapper work unchanged, WinboxNativeConnection must translate API path → handler and API field name → numeric key (and back) — and that mapping is genuinely awkward for two reasons:

  1. The numbers are version-volatile. Handler minors and field keys shift between RouterOS releases as menus and fields are added. Hard-coding them would rot.
  2. WinBox stores GUI labels, not API names. The catalog calls a window "DNS Static Entry" (API /ip/dns/static), "Firewall Rule" (API /ip/firewall/filter), "Resources" (API /system/resource). WinBox never stores the API leaf, so the two cannot be derived from each other mechanically in every case.

How tik4net solves it

The design splits the mapping by stability, so the volatile half is always read live and only the stable (text) half is shipped:

What Stability Source
Handler number, field key / type / read-only volatile (changes per version) read live from the version-matched .jg catalog the router serves, fetched once over the same WinBox channel and cached
API field name ↔ label stable text a normalizer (lower-case, spaces→-) over the live labels, + a small built-in alias dictionary for irregular labels
API path ↔ handler stable text → volatile number the menu tree in the live .jg (handler is always live); a small built-in alias bridges irregular paths to their menu label
Protocol constants (getall cmd, .id, comment, disabled keys) fixed hard-coded

So: handler/field numbers are never hard-coded — they come from the router's own .jg for its version. Only the English text bridge is shipped (a hard-coded dictionary), and it is the thing that carries across versions. Typed values (IP addresses, MACs, enums, interface references) are encoded/decoded from the .jg field type — e.g. an IP packs to a u32, an interface reference resolves to/from the target object's name.

When the mapping can't be resolved

If a field name or path can't be resolved (an unusual label, or a table the built-in dictionary doesn't cover), the connection throws a guiding exception rather than guessing:

  • unknown pathTikNoSuchCommandException ("no M2 handler mapping for path … — add a PathOverride or use a WinboxCli connection")
  • unknown fieldWinboxFieldResolutionException ("cannot resolve API field … — add a FieldOverride or use a WinboxCli connection")

You resolve these per session with the overrides below.

Session overrides

Both overrides take priority over the live catalog and the built-in dictionary, and are keyed on stable text so they survive router upgrades.

using tik4net.WinboxNative;

var conn = new WinboxNativeConnection();

// 1) Map an API path to a WinBox handler [major, minor] when the built-in alias doesn't cover it.
conn.PathOverride("/ppp/secret", new[] { 27, 101 });

// 2) Map an API field name to its numeric M2 key for a given path.
conn.FieldOverride("/ip/hotspot/user", "mac-address", 0x1);

conn.Open("192.168.4.1", "admin", "");

Tip — finding the numbers. The .jg catalogs WinBox caches under %APPDATA%\MikroTik\WinBox\<version>\*.jg (and the copy tik4net caches under CatalogCachePath) are plain JavaScript object literals: a window's path:[a,b] is the handler, and a field's id:'s10006' encodes the key (0x10006) and type (s=string). Match the window/field by its label to read off the numbers.

Catalog cache location

The fetched .jg set is cached per router version so it isn't downloaded on every connect:

var conn = new WinboxNativeConnection
{
    CatalogCachePath = @"C:\ProgramData\myapp\winbox-cache"  // default: %TEMP%\tik4net
};

Files land in <CatalogCachePath>\<routerVersion>\*.jg. Only the base roteros.jg is required; the feature plugins (ppp.jg, hotspot.jg, dhcp.jg, …) are optional and only present for packages the router actually has — calling into a path whose plugin is absent yields TikNoSuchCommandException ("no such command"), exactly like the router would answer.

Error handling

Native errors are surfaced with the router's own message and translated to the same exception types as the API/CLI transports, so existing error-handling code keeps working:

Router result tik4net exception
already have such address / already-exists TikAlreadyHaveSuchItemException
object doesn't exist / unresolvable .id TikNoSuchItemException
unmapped path / missing plugin TikNoSuchCommandException
other M2 errors TikCommandUnexpectedResponseException (message includes the router's error string)

Capability

CRUD and Listen — native reports Crud | Listen, so the callback-based async APIs work in addition to the synchronous CRUD ones:

bool hasCrud   = conn.Supports(TikConnectionCapability.Crud);   // true
bool hasListen = conn.Supports(TikConnectionCapability.Listen); // true

ExecuteAsync / LoadAsync / LoadListenAsync are supported and cover three shapes:

Call shape Example How native does it
Streaming monitor /tool/torch, /tool/profile, /ping, /interface/monitor-traffic starts a .jg monitor window and polls it every autorefresh ms over the normal M2 channel (WinBox has no server push — webfig polls too); each polled record is pushed to your row callback
Async list cmd.LoadAsync<Interface>(...) on a /print runs the read on a background thread, emits each row, then completes
Change listen conn.LoadListenAsync<Interface>(onChange, onDeleted, …) polls the table and diffs snapshots by .id; a changed row fires onChange, a vanished .id fires onDeleted (config fields only — runtime counters are ignored so it doesn't fire on every tick)

Cancel a running async command with Cancel() / CancelAndJoin(), or by closing the connection (a close mid-stream stops cleanly without surfacing an error). TikConnectionCapability.Streaming (ExecuteListWithDuration) is not reported — use the API transport for that.

Note: a few monitor windows label fields differently from the API (e.g. /ping takes address where WinBox calls it Ping To). tik4net ships these aliases, but an exotic monitor may still need a FieldOverride(...); the thrown exception names the field and key to add.

Native vs. WinBox CLI — which to use?

Both use the same encrypted WinBox channel (TCP 8291, EC-SRP5 + AES). They differ above the channel:

WinBox Native (WinboxNative) WinBox CLI (WinboxCli)
How CRUD works structured M2 calls (no terminal) drives the RouterOS CLI via the mepty terminal
Field mapping API ↔ M2 keys via the live .jg + dictionary none — uses CLI text directly
Coverage broad, but exotic tables/verbs may need an override every command the CLI accepts
Speed no prompt/echo/paging overhead terminal round-trips
Best when you want clean structured CRUD on common tables you need a command the native mapping doesn't cover yet, or full CLI parity

WinBox CLI is the fallback whenever native mapping is incomplete for your workload: it accepts any command the router's CLI does, at the cost of text parsing. The two are interchangeable at the ITikConnection level, so switching is a one-line change to the TikConnectionType / factory call.

Acknowledgements

The WinBox M2 protocol mapping was reconstructed from the official webfig /jsproxy client (master*.js, which speaks the same M2 protocol in JSON) and the community reverse-engineering work referenced on WinBox-CLI-connection.

See also

Clone this wiki locally