HydraIssues

Verify the GL.iNet Slate 7 Pro API on the LAN against pkg/glinet (follow-up to #516)
closed improvement Project: hydraneck Reporter: cederik 19 Aug 2026 20:48

Description

Goal

Verify the GL.iNet Slate 7 Pro (GL-BE10000) JSON-RPC API against the assumptions built into hydraneck pkg/glinet (shipped in v0.12.0, issue #516 Phase A). This task needs LAN access to the device. Run it from a machine on the router's network. The hydraneck server cannot reach the device.

Context

hydraneck v0.12.0 added a glinet router backend. It was built from the archived GL.iNet 4.x API description (dev.gl-inet.com is offline), not against real firmware. Two wire-format assumptions need confirmation on the real device. The full findings go back to issue #516.

You need:

  • The router's LAN IP. Default is 192.168.8.1. Set IP to it.
  • The device admin password. Ask Cederik if it is not set yet. Set PW to it.
  • curl, openssl, md5sum, python3 (only for pretty printing).

Do not change the router's WAN, Wi-Fi, or firewall settings. Steps 1 to 5 are read only. Step 6 writes one scratch WireGuard group and removes it again.

Step 1: reachability

curl -s -o /dev/null -w '%{http_code}\n' http://$IP/rpc -d '{}'

Expect an HTTP 200 (with a JSON-RPC error body). Record the code.

Step 2: challenge

curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":1,"method":"challenge","params":{"username":"root"}}'

Record the raw JSON. Confirm the result contains alg, salt, and nonce. Record whether alg is a number or a string, its value, and whether a hash-method field is present (expected on firmware 4.8+).

Step 3: login

hydraneck computes: cipher = unix crypt(3) of the password with alg and salt, then hash = md5 hex of root:<cipher>:<nonce> (or sha256/sha512 hex when hash-method says so).

# Use the alg from step 2: -1 for alg 1, -5 for alg 5, -6 for alg 6.
CIPHER=$(openssl passwd -6 -salt <salt-from-step-2> "$PW")
HASH=$(echo -n "root:$CIPHER:<nonce-from-step-2>" | md5sum | cut -d' ' -f1)
curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":2,"method":"login","params":{"username":"root","hash":"'$HASH'"}}'

Fetch a fresh challenge immediately before the login. Nonces expire. Expect a result that contains sid. Record the exact shape of the result. If login fails with error -32000, record the full error and try the sha256/sha512 digest per the hash-method field. Export SID for the next steps.

Step 4: system info

curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":3,"method":"call","params":["'$SID'","system","get_info",{}]}'

Record firmware_version, model, and board_info.model. hydraneck renders the version as <firmware_version> (<board_info.model>).

Step 5: clients and WireGuard read surface

curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":4,"method":"call","params":["'$SID'","clients","get_list",{}]}'
curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":5,"method":"call","params":["'$SID'","wg-client","get_group_list",{}]}'
curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":6,"method":"call","params":["'$SID'","wg-client","get_status",{}]}'

Record one full client entry (field names matter: mac, ip, name, online, tx, rx). Record the group list and status shapes. Confirm the module name wg-client (with hyphen) works.

Step 6: WireGuard write format test (scratch group, then clean up)

This settles the open assumption: add_config may want allowed_ips as a CSV string (what hydraneck sends) or as an array.

# Create a scratch group.
curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":7,"method":"call","params":["'$SID'","wg-client","add_group",{"group_name":"hydratest"}]}'
# Find its group_id.
curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":8,"method":"call","params":["'$SID'","wg-client","get_group_list",{}]}'
# Try add_config with allowed_ips as a CSV STRING (hydraneck's format). Use throwaway keys:
KEYS=$(curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":9,"method":"call","params":["'$SID'","wg-server","generate_key",{}]}')
curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":10,"method":"call","params":["'$SID'","wg-client","add_config",{"group_id":<GID>,"name":"hydratest-peer","address_v4":"10.99.99.2/32","private_key":"<PRIV>","public_key":"<PUB>","end_point":"203.0.113.1:51820","allowed_ips":"10.99.0.0/16","persistent_keepalive":25,"presharedkey_enable":false}]}'

Record whether the string form is accepted (result with peer_id) or rejected (record the exact error). If rejected, retry with "allowed_ips":["10.99.0.0/16"] and record the outcome. Do NOT start this tunnel. Clean up:

curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":11,"method":"call","params":["'$SID'","wg-client","remove_config",{"group_id":<GID>,"peer_id":<PEER_ID>}]}'
curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":12,"method":"call","params":["'$SID'","wg-client","remove_group",{"group_id":<GID>}]}'
curl -s http://$IP/rpc -d '{"jsonrpc":"2.0","id":13,"method":"logout","params":["'$SID'"]}'

Verify with get_group_list that the scratch group is gone.

Report

Collect for issue #516:

  • Raw challenge JSON (step 2): alg type and value, hash-method presence.
  • Login result shape (step 3) and which digest worked.
  • firmware_version, model, board_info.model (step 4).
  • One raw client entry and the wg-client group/status shapes (step 5).
  • add_config verdict: CSV string accepted yes/no, exact error if not (step 6).
  • Confirmation that the scratch group was removed.

Redact the password and the sid from the report. Hand the findings to Cederik, or PATCH them into issue #516 on issues.experiencenet.com if you have the API token. If any step contradicts the pkg/glinet implementation, say exactly which call and which field.

Comments (1)

api 19 Aug 2026 21:31

Runbook executed on the LAN 2026-08-19. All six steps completed; scratch group removed; findings posted to issue #516. Key results: challenge/login/system/clients assumptions confirmed; allowed_ips CSV string ACCEPTED by add_config; but wg-client get_status is Method not found (-32601) on firmware 4.8.4.