iKuai Router Management
Control an iKuai router via its private /Action/login + /Action/call API.
Authenticated session is auto-managed, including re-login on Result: 10014.
This skill ships a fully-typed Python helper at helpers/ikuai.py covering 105
verified func_names discovered via Chrome DevTools Protocol on a real iKuai
3.7.8 (IK-M50) device. Always import the helper rather than crafting HTTP by
hand — it handles auth, pagination, error mapping, and parameter quirks.
Setup (one-time)
Provide credentials via env vars (.env file, shell, or skill-runtime config):
IKUAI_BASE_URL=http://192.168.1.1
IKUAI_USER=admin
IKUAI_PASS=<plaintext password>
Verify:
from helpers.ikuai import IKuai
ik = IKuai() # reads env, lazy-logs-in
print(ik.status.sysstat()) # → {verinfo, stream, cputemp}
Quick reference — what's where
| Domain | Module | Common methods |
|---|---|---|
| Health / monitor | ik.status | sysstat(), homepage(), monitor_iface(), monitor_lanip(), monitor_app_flow(), monitor_system(), arp(), iksyscheck() |
| Network basics | ik.network | lan(), wan(), vlan(), dns(), dns_replace(), ipgroup(), macgroup(), domain_group(), ddns(), nat_ddns(), igmp_proxy(), ipv6group() |
| DHCP | ik.dhcp | server(), static(), lease(), acl_mac() |
| NAT / port-forward ⭐ | ik.nat | dnat_list(), dnat_add(...), dnat_del(id), dnat_toggle(id, enabled), netmap(), nat_rule(), upnpd(), upnpd_leases() |
| Routing | ik.routing | static_rt(), static_rt_table(), lb_pcc() |
| QoS / 流控 | ik.qos | mac_qos(), simple_qos(), stream_control(), stream_domain(), stream_ipport(), stream_updown() |
| Firewall / ACL | ik.firewall | acl(), acl_mac(), acl_qq(), conn_limit(), dprotos(), alg() |
| URL / domain filter | ik.filter | url_black(), url_keywords(), url_redirect(), url_replace(), domain_blacklist() |
| VPN | ik.vpn | pptp_server(), pptp_client(), l2tp_client(), openvpn_client(), ipsec(), wireguard(), ike_server(), ike_client() |
| Auth / PPPoE | ik.auth | webuser(), webauth(), pppuser(), pppoe_server(), pppoe_proxy(), ppp_online(), ppp_passwd(), ppp_package(), ppp_paylog(), coupon() |
| Wireless / AC | ik.ac | server(), group(), online_clt(), status(), upgrade(), net_optimize(), wls_black(), wls_mvlan(), camera() |
| Logs (syslog) | ik.logs | arp(), dhcpd(), webadmin(), pppauth(), sysevent(), wanpppoe(), apaction(), ddns(), notice() |
| System | ik.system | basic(), register(), advanced(), remote_control(), watchdog(), upgrade(), ik_sysctl(), dingtalk(), notice_temp(), notice_cycle(), notice_remind(), notice_expires() |
| Tools | ik.tools | speedtest(), iperf(), tcpdump(), wakeup(), cflow(), tcp_proxy(), dev_control(), mac_comment_list() |
| Catch-all | ik.call(func, action, param) | For any uncovered combination |
Read patterns
# table-style — paginated list
rules = ik.nat.dnat_list() # default first 100
rules = ik.nat.dnat_list(limit="0,500") # explicit page
print(rules) # list of dicts with id/lan_addr/lan_port/wan_port/protocol/enabled/comment
# single-config (no pagination)
print(ik.network.wan()) # → {data: {...}}
print(ik.status.sysstat()) # → {verinfo, stream, cputemp}
Write patterns (port-forward example)
For destructive ops, briefly state the intended write in chat before executing — this gives the user visibility even when running unattended.
ik.nat.dnat_add(
comment="Web API",
interface="wan1",
lan_addr="192.168.1.10",
lan_port="19119",
wan_port="19119",
protocol="tcp",
src_addr="", # empty = any source
enabled="yes",
)
ik.nat.dnat_del(id=7)
ik.nat.dnat_toggle(id=7, enabled="no")
For other write ops not wrapped, use ik.call(...):
ik.call("dhcp_static", "add", {
"interface": "lan1",
"ip_addr": "192.168.1.51",
"mac": "aa:bb:cc:dd:ee:ff",
"comment": "Static binding",
"enabled": "yes",
})
Behaviour rules for the agent
- Never expose
IKUAI_PASSin chat replies or logs. - For destructive ops (
del, sys reboot, firewall rule changes that may block traffic), reply with a one-line preview ("Going to delete dnat rule id=7 (5000→9443 on .6). Doing it now.") before executing, so the user has visibility even in YOLO mode. - Read methods are free — call them liberally to ground answers in current state instead of guessing.
- If a method raises
RouterAPIError, the message is human-readable; surface it in the reply rather than retrying blindly. - Schema reference:
helpers/funcs.jsonhas all 105 verified(func_name, action, param_keys)triples in case you need to hand-craft a call viaik.call().
Common port-forward fields (dnat schema)
Captured live from this device, so it's accurate for iKuai 3.7.8 / IK-M50:
| Field | Type | Notes |
|---|---|---|
id | int | server-assigned, omit on add |
enabled | "yes" / "no" | |
comment | string | free text |
interface | string | e.g. wan1 |
src_addr | string | source filter, empty = any |
lan_addr | string | dest LAN IP |
lan_addr_int | int | server computes from lan_addr; do not set |
protocol | "tcp" / "udp" / "tcp+udp" | |
wan_port | string | external port (yes, string not int) |
lan_port | string | internal port |
Troubleshooting
RouterAPIError: 'no login authentication'→ token expired. Helper re-logs-in automatically; if persistent, password is wrong.- HTTP 404 on
/Action/call→ wrong base URL. Result != 30000→ operation rejected at iKuai layer; inspectErrMsgfor detail (param name typo, value out of range, etc.).