«SwOS non ha un’API, si gestisce solo dal browser.» È quello che dice la documentazione ufficiale, ed è vero… a metà. Vale per gli smart switch MikroTik che montano SwOS — la serie CRS3xx e affini. Perché quando apri la web interface di uno switch MikroTik della serie CRS3xx in SwOS, quella pagina non è generata dallo switch: è JavaScript statico che, dietro le quinte, legge e scrive una manciata di file sul dispositivo via HTTP. Quei file sono l’API. Non documentata, un po’ ruvida, ma c’è — e con essa puoi configurare VLAN, leggere i contatori, automatizzare i backup, tutto da riga di comando.
In questo articolo apriamo quel canale a mano, decodifichiamo il formato byte per byte, configuriamo una VLAN via POST, e mettiamo l’API grezza a confronto con quello che lo stesso switch espone via SNMP. Alla fine rilasciamo dojo.swos, una piccola libreria Python che incapsula tutto.
I «b-file»: l’API che non sapevi di avere
La web UI di SwOS parla con lo switch tramite file con estensione .b, serviti via HTTP con Digest authentication (niente HTTPS). Una GET legge, una POST scrive. Il primo da guardare è sys.b:
$ curl --digest -u admin: http://192.0.2.10/sys.b
{upt:0x0000d32c,cip:0x3c000d0a,mac:'e48d8c000001',brd:'…',
sid:'…',id:'53574f53',ver:'322e3136',temp:0x00000027,
fan1:0x00000b6d,allp:0x03ff,ip:0x0158090a, … }
Somiglia a JSON ma non lo è. Le regole di codifica sono poche e, una volta capite, tutto si apre:
| Elemento | Come è scritto | Esempio | Significa |
|---|---|---|---|
| Numero | esadecimale 0x.., lunghezza pari |
0x00000027 |
39 (°C) |
| Stringa | coppie esadecimali ASCII, apici singoli | '53574f53' |
SWOS |
| Bitmask porte | un numero, bit 0 = porta 1 | 0x03ff |
porte 1–10 |
| Array | parentesi quadre | [0x02,0x07] |
[2, 7] |
| Indirizzo IP | intero little-endian | 0x0158090a |
10.9.88.1 |
Applichiamole a sys.b: id:'53574f53' è la stringa esadecimale di «SWOS» (l’identity); ver:'322e3136' è «2.16»; temp:0x00000027 sono 39 °C; fan1:0x00000b6d sono 2925 giri/min della ventola; allp:0x03ff è la bitmask delle dieci porte. E i due indirizzi: cip:0x3c000d0a, letto al contrario byte a byte, è l’IP che lo switch ha preso in DHCP; ip:0x0158090a è l’IP di fallback statico. Il little-endian è la trappola che frega tutti la prima volta.
Leggere lo stato delle porte
link.b è lo stato dei collegamenti. I nomi delle porte arrivano come stringhe esadecimali, i flag come bitmask:
$ curl --digest -u admin: http://192.0.2.10/link.b
{en:0x03ff, lnk:0x0001, …
nm:['506f727431','506f727432', … '5346502b31','5346502b32']}
en:0x03ff: tutte e dieci le porte abilitate. lnk:0x0001: solo il bit 0 è acceso, quindi link attivo unicamente sulla porta 1 (l’unico cavo collegato). E nm è l’array dei nomi: 506f727431 → «Port1», … 5346502b31 → «SFP+1». Nessun MIB, nessuna libreria: solo curl e la tabella qui sopra.
Configurare una VLAN… via POST
Qui SwOS sorprende: la stessa URL che leggi in GET la scrivi in POST. La tabella VLAN sta in vlan.b. Di fabbrica è vuota:
$ curl --digest -u admin: http://192.0.2.10/vlan.b
[]
Creiamo la VLAN 10 sulle porte 2 e 3. Le porte membro sono una bitmask: porta 2 = bit 1, porta 3 = bit 2 → 0x0006. La postiamo:
$ curl --digest -u admin: -X POST \
--data-binary "[{vid:0x000a,mbr:0x0006}]" \
http://192.0.2.10/vlan.b
$ curl --digest -u admin: http://192.0.2.10/vlan.b
[{nm:'',mbr:0x0006,vid:0x000a,piso:0x00,lrn:0x01,mrr:0x00,igmp:0x00}]
Lo switch ha accettato la scrittura e ci ha restituito l’entry completa, rivelando tutti i campi: vid (VLAN id), mbr (porte membro), nm (nome), piso (isolamento), lrn (learning), mrr (mirror), igmp (snooping). Due dettagli preziosi scoperti provando:
- SwOS fa merge per chiave: puoi postare solo i campi che cambi. Un
POSTdi{id:'...'}susys.bcambia l’identity e lascia intatto tutto il resto. - La config è immediata e live. Una VLAN o un isolamento sbagliato sulla porta da cui stai amministrando ti taglia fuori. Prova sempre su porte senza cavo, e ricordati Actions → Save Config: la scrittura modifica la config corrente, ma SwOS non la rende persistente al reboot finché non salvi.
Monitorare: i contatori grezzi
!stats.b è una miniera: per ogni porta, array di byte e pacchetti ricevuti/trasmessi, unicast/multicast/broadcast, persino l’istogramma per dimensione del frame (p64, p128, …) e i frame con FCS errato. Tutto in esadecimale, tutto per-porta. È la materia prima per un grafico di traffico fatto in casa, senza dipendere da nient’altro che curl.
L’altra faccia: SNMP
Lo stesso switch, se abiliti SNMP (anche quello si fa con un POST a snmp.b), espone i suoi dati in forma standard e già leggibile:
$ snmpwalk -v2c -c public 192.0.2.10 1.3.6.1.2.1.1
sysDescr.0 = STRING: CRS3xx SwOS v2.16
sysName.0 = STRING: SWOS
sysObjectID.0 = enterprises.14988 (MikroTik)
$ snmpwalk -v2c -c public 192.0.2.10 ifOperStatus
ifOperStatus.1 = up(1)
ifOperStatus.2 = down(2) …
Sono gli stessi fatti dei b-file, ma vestiti di MIB: sysDescr contiene modello e versione (che nei b-file erano brd+ver in esadecimale), ifOperStatus.1 = up è il bit 0 di lnk:0x0001, ifInOctets sono gli stessi byte di rb in !stats.b. Due facce, un solo switch:
| b-file (API nascosta) | SNMP | |
|---|---|---|
| Lettura | sì (grezza, esadecimale) | sì (standard, leggibile) |
| Scrittura/config | sì (VLAN, porte, SNMP…) | no (read-only) |
| Copertura | tutto ciò che vede la GUI (temp, ventole, PoE…) | sistema, interfacce, bridge |
| Strumenti | curl + un parser |
qualsiasi NMS (Prometheus, LibreNMS, ntopng) |
| Standard | no, reverse-engineering | sì (RFC) |
Ma attenzione a cosa SNMP non ti dà, verificato a mano su uno switch reale. Lo stack SNMP di SwOS implementa la BRIDGE-MIB di base (tabella MAC, mappa porte) ma non la Q-BRIDGE-MIB delle VLAN (1.3.6.1.2.1.17.7 → «No Such Object»): crei pure una VLAN via b-file, in SNMP resta invisibile. Niente nemmeno la POWER-ETHERNET-MIB (1.3.6.1.2.1.105): PoE e consumi non escono via SNMP standard. Quello che invece c’è, nella MIB enterprise MikroTik, è la temperatura (…14988.1.1.3.11.0, in decimi di grado) e il monitoraggio DDM degli SFP. Morale: VLAN, PoE, ventole e tensioni del PSU si leggono (e si scrivono) solo dai b-file; SNMP copre sistema, interfacce, traffico, MAC e temperatura.
Una mappa di OID pronti all’uso
Se vuoi agganciare lo switch a Prometheus, LibreNMS o a un semplice snmpget in cron, questi sono i rami che SwOS espone davvero (community di default public, SNMP v2c):
| Cosa | OID | Esempio |
|---|---|---|
| Descrizione (modello+versione) | 1.3.6.1.2.1.1.1.0 |
CRS3xx SwOS v2.16 |
| Identity | 1.3.6.1.2.1.1.5.0 |
SWOS |
| Uptime | 1.3.6.1.2.1.1.3.0 |
timeticks |
| Nome porta | 1.3.6.1.2.1.2.2.1.2.N |
Port1 |
| Stato porta (up/down) | 1.3.6.1.2.1.2.2.1.8.N |
up(1) |
| MAC della porta | 1.3.6.1.2.1.2.2.1.6.N |
hex |
| Byte rx/tx (32 bit) | …2.2.1.10.N / .16.N |
counter |
| Byte rx/tx (64 bit) | 1.3.6.1.2.1.31.1.1.1.6.N / .10.N |
counter64 |
| Velocità (Mbps) | 1.3.6.1.2.1.31.1.1.1.15.N |
1000 |
E qui i rami fuori standard, nella MIB enterprise MikroTik (1.3.6.1.4.1.14988) — le cose che un NMS generico non cerca da solo ma che vale la pena aggiungere:
| Cosa | OID | Nota |
|---|---|---|
| Temperatura | …14988.1.1.3.11.0 |
in decimi di grado: 380 = 38,0 °C |
| Numero di serie | …14988.1.1.7.3.0 |
stringa |
| Versione SwOS | …14988.1.1.7.4.0 |
2.16 |
| Diagnostica SFP (DDM) | …14988.1.1.19.1.1 |
temp, tensione, potenza Tx/Rx del modulo |
E le assenze, dette con franchezza perché contano: niente carico CPU (SwOS non implementa la HOST-RESOURCES-MIB: 1.3.6.1.2.1.25 → «No Such Object» — su RouterOS invece hrProcessorLoad c’è), niente VLAN, niente PoE, niente ventole o tensioni del PSU via SNMP. Per quei dati, e per scrivere qualunque cosa, si torna ai b-file. Confidiamo che una futura versione di SwOS allarghi la copertura SNMP — intanto la si completa dall’altra porta.
La regola pratica: SNMP per monitorare (lo agganci a un sistema di metriche in cinque minuti), b-file per configurare (è l’unico modo di scrivere senza aprire il browser).
La libreria: dojo.swos
Decodificare esadecimale a mano è istruttivo una volta; dalla seconda diventa lavoro. Così abbiamo scritto dojo.swos, il primo mattone delle librerie dojo.*: incapsula il formato b-file, la Digest auth e il little-endian, e ti dà oggetti pronti. Esiste in due versioni gemelle, Python e PHP — stessa logica, stessi metodi.
from dojo.swos import SwOS
sw = SwOS("192.0.2.10") # admin / password vuota (default SwOS)
s = sw.system()
print(s["identity"], s["version"], s["temp_c"], "°C")
# SWOS 2.16 39 °C
for p in sw.ports():
print(p["name"], "UP" if p["link"] else "down")
# Port1 UP / Port2 down / …
# configurare una VLAN (occhio alla porta di gestione!)
sw.set_vlans([{"vid": 10, "ports": [2, 3], "name": "lab"}])
# e la verifica incrociata: scrivi col b-file, rileggi via SNMP
sw.set_snmp(location="sala-rack")
# snmpget … sysLocation.0 = STRING: sala-rack
La libreria copre lettura di sistema, porte, VLAN, RSTP, SNMP, tabella MAC e contatori, e la scrittura sicura di identity, SNMP e VLAN. Un get()/post() grezzo resta disponibile per qualunque .b. In PHP è identica, con il namespace Dojo\Swos:
use Dojo\Swos\SwOS;
$sw = new SwOS("192.0.2.10");
echo $sw->system()["identity"]; // -> SWOS
$sw->setVlans([["vid" => 10, "ports" => [2, 3]]]);
Si installa dall’indice del dojo: ognuno ha il suo indirizzo personale (lo trovi nella pagina della libreria o nella tua area iscritti), così nessuno può spacciare un pacchetto dojo-* omonimo.
# Python
pip install --index-url https://mikrotikdojo.com/pypi/<il-tuo-indirizzo>/simple/ dojo-swos
# PHP
composer config repositories.dojo composer https://mikrotikdojo.com/composer/<il-tuo-indirizzo>/
composer require dojo/swos
Si installa dal repository del dojo, riservato a chi è nel dojo: entra gratis.
Licenza MIT. La pagina della libreria mostra le due versioni (Python e PHP) con impronta SHA-256, marca temporale e changelog.
Se invece devi scriptare un router con RouterOS, e non uno switch SwOS, c’è la libreria cugina dojo.ros, che parla l’API di RouterOS (binaria o REST) da Python e PHP.
Due cose da sapere prima di iniziare
- Le credenziali SwOS sono separate da RouterOS. Sugli switch dual-boot, la password che usi in RouterOS non vale in SwOS: il default SwOS è utente
admincon password vuota. Il realm della Digest auth è il nome del modello. (Prima cosa da cambiare su una rete vera.) - Entrare in SwOS è protetto dal device-mode. Su una CRS3xx dual-boot, commutare da RouterOS a SwOS passa da
/system routerboard settings set boot-os=swos, ma se il device-mode ha il lucchettorouterboardabbassato la commutazione viene rifiutata finché non lo sblocchi con una conferma fisica. È lo stesso meccanismo che protegge container e formattazione dei dischi.
Una nota onesta: tutto questo è reverse-engineering. MikroTik potrebbe cambiare il formato dei b-file tra una versione e l’altra senza preavviso, e confidiamo che prima o poi arrivi un’API ufficiale e documentata anche per SwOS. Nel frattempo, lo switch ha già tutto quello che serve per automatizzarlo: bastava sapere dove guardare.



