Skip to content

Instantly share code, notes, and snippets.

@Strykar
Created March 2, 2026 18:36
Show Gist options
  • Select an option

  • Save Strykar/8544127dde6bcc4fa77536b3e72609e5 to your computer and use it in GitHub Desktop.

Select an option

Save Strykar/8544127dde6bcc4fa77536b3e72609e5 to your computer and use it in GitHub Desktop.
RouterOS - MKTXP WAN detection helpers
#!/usr/bin/env python3
"""
Standalone RouterOS WAN topology inspector
- Deterministic WAN derivation
"""
from routeros_api import RouterOsApiPool
import ipaddress
# ---- USER CONFIG ----
HOST = "192.168.88.1"
USER = "mktxp_user"
PASSWORD = "mktxp_pass"
PORT = 8729
# --------------------
def main():
pool = RouterOsApiPool(
HOST,
username=USER,
password=PASSWORD,
port=PORT,
use_ssl=True,
plaintext_login=True,
ssl_verify=False,
ssl_verify_hostname=False,
)
api = pool.get_api()
# ROUTES
v4_routes = api.get_resource("/ip/route").get(dst_address="0.0.0.0/0")
v6_routes = api.get_resource("/ipv6/route").get(dst_address="::/0")
print("\n=== MikroTik WAN routing (raw) ===\n")
print("[IPv4]")
for r in v4_routes:
gw = r.get("gateway")
igw = r.get("immediate-gw")
if gw and igw and "%" in igw:
print(f"{gw} -> {igw}")
print("\n[IPv6]")
for r in v6_routes:
gw = r.get("gateway")
igw = r.get("immediate-gw")
if gw and "%" in gw:
print(f"{gw} -> {igw}")
# WAN INTERFACES (from default routes)
def wan_iface_from_route(r):
if "vrf-interface" in r:
return r["vrf-interface"]
igw = r.get("immediate-gw", "")
if "%" in igw:
return igw.split("%", 1)[1]
return None
wan_ifaces_v4 = {wan_iface_from_route(r) for r in v4_routes if wan_iface_from_route(r)}
wan_ifaces_v6 = {wan_iface_from_route(r) for r in v6_routes if wan_iface_from_route(r)}
wan_ifaces = wan_ifaces_v4 | wan_ifaces_v6
# IPv4 ADDRESSES
ipv4_addrs = api.get_resource("/ip/address").get()
ipv4_by_iface = {}
for a in ipv4_addrs:
iface = a.get("interface")
ip = a.get("address", "").split("/")[0]
if iface in wan_ifaces:
ipv4_by_iface.setdefault(iface, []).append(ip)
# IPv6: DYNAMIC POOLS ONLY
pools = api.get_resource("/ipv6/pool").get()
dynamic_prefixes = []
for p in pools:
if p.get("dynamic") == "true":
dynamic_prefixes.append(ipaddress.ip_network(p["prefix"], strict=False))
ipv6_addrs = api.get_resource("/ipv6/address").get()
derived_ipv6 = {} # iface -> single IPv6 address
for a in ipv6_addrs:
addr = a.get("address")
if not addr:
continue
ip = ipaddress.ip_address(addr.split("/")[0])
# Skip link-local
if ip.is_link_local:
continue
# Must belong to a dynamic delegated prefix
if not any(ip in pfx for pfx in dynamic_prefixes):
continue
# Map back to WAN via IPv6 default route interface
for r in v6_routes:
iface = wan_iface_from_route(r)
if iface:
derived_ipv6[iface] = str(ip)
# OUTPUT
print("\n=== Derived WAN interfaces & global addresses ===\n")
for iface in sorted(wan_ifaces):
for ip in ipv4_by_iface.get(iface, []):
print(f"* {iface:<10} {ip}")
if iface in derived_ipv6:
print(f"* {iface:<10} {derived_ipv6[iface]}")
pool.disconnect()
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
RouterOS WAN structure inspection script.
"""
from routeros_api import RouterOsApiPool
# ---- USER CONFIG ----
HOST = "192.168.88.1"
USER = "mktxp_user"
PASSWORD = "mktxp_pass"
PORT = 8729
# --------------------
def print_section(title):
print("\n" + "=" * len(title))
print(title)
print("=" * len(title))
def main():
pool = RouterOsApiPool(
HOST,
username=USER,
password=PASSWORD,
port=PORT,
use_ssl=True,
plaintext_login=True,
ssl_verify=False,
ssl_verify_hostname=False,
)
api = pool.get_api()
print_section("INTERFACES (/interface)")
for i in api.get_resource("/interface").get():
print(f"{i.get('name'):15} type={i.get('type')}")
print_section("IPv4 DEFAULT ROUTES (/ip/route dst=0.0.0.0/0)")
for r in api.get_resource("/ip/route").get(**{"dst-address": "0.0.0.0/0"}):
print(r)
print_section("IPv6 DEFAULT ROUTES (/ipv6/route dst=::/0)")
for r in api.get_resource("/ipv6/route").get(**{"dst-address": "::/0"}):
print(r)
print_section("IPv4 ADDRESSES (/ip/address)")
for a in api.get_resource("/ip/address").get():
print(f"{a.get('interface'):15} {a.get('address')}")
print_section("IPv6 ADDRESSES (/ipv6/address)")
for a in api.get_resource("/ipv6/address").get():
print(
f"{a.get('interface'):15} "
f"{a.get('address'):35} "
f"link-local={a.get('link-local')}"
)
print_section("IPv6 POOLS (/ipv6/pool)")
for p in api.get_resource("/ipv6/pool").get():
print(p)
pool.disconnect()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment