Hi — first, thanks for go-ios. Multi-device farm setup we run depends on it pretty heavily.
We've hit a recurring isolation problem and wanted to ask for a small CLI extension that would unblock it cleanly.
Setup
Linux host, kernel TUN tunnel started with sudo ios tunnel start
Multiple iOS devices (5–10) attached, each with its own forwards via ios forward
Long-lived WDA sessions per device; the host runs the tunnel as a single shared daemon process
ios tunnel ls cleanly shows the per-device state — each UDID gets its own IPv6 link-local + RSD port:
[
{ "address": "fdad:85c3:8dc6::1", "rsdPort": 50338, "udid": "00008101-...001E" },
{ "address": "fdc5:cb62:1683::1", "rsdPort": 64148, "udid": "00008101-...001E" },
{ "address": "fdef:64a2:81e::1", "rsdPort": 58811, "udid": "00008101-...003A" }
]
Problem
When a device reboots (post devmode enable --enable-post-restart, post-erase, or just any ios reboot), the tunnel daemon keeps stale state for that specific UDID:
routing table entry pointing at the pre-reboot IPv6 link-local that the device no longer holds
testmanagerd connection bound to the previous device descriptor
(likely) DDI / lockdown channel handle that iOS has since invalidated
Subsequent ios forward against the rebooted device fails with read: network is unreachable against an address that no longer matches what the device announces. Fresh lockdown info and usbmux list see the device fine — only the tunnel side is broken.
The only recovery path the CLI exposes today is ios tunnel stopagent + ios tunnel start, i.e. tearing down the whole shared daemon. That kills every other device's session on the host, mid-command, even though the other devices were never affected by the reboot. In a 10-device farm one factory reset cascades into 10 simultaneous WDA reconnects and the inevitable thundering herd.
What we'd love
A surgical, per-UDID equivalent of stopagent:
ios tunnel stop --udid= # tear down the tunnel for one device only
# (drop route, close testmanagerd, free RSD port)
# next ios tunnel ls no longer shows it
# next ios forward against that UDID re-handshakes
Optionally:
ios tunnel refresh --udid= # tear down + immediately re-create
The goal is: after a per-device reboot, we can refresh just that device's tunnel state without disturbing the other N–1 devices. Other tunnels in ios tunnel ls should keep their addresses, RSD ports, and active forwards untouched.
What we do today (workaround, suboptimal)
We track per-device reboot/erase completion ourselves, hold the tunnel restart until no other slot is in an active WDA session, and only then fuser -k 60105/tcp && ios tunnel start. Even with that gating, every reboot of any device costs a brief outage on every other device. With 10 devices and any factory-reset throughput this is painful.
Implementation hint
Internally ios tunnel ls already iterates per-UDID tunnel records — the data structure exists. A stop --udid would presumably:
find the tunnel record for that UDID,
cancel its goroutines (rsd listener + testmanagerd dispatch),
delete the kernel route to its IPv6 address,
remove the entry from the daemon's state map.
Other tunnels stay live; the daemon keeps running.
Happy to test a branch / PR on a real multi-device farm if you'd like — repro is just ios tunnel start with N devices, ios reboot --udid=A, then watch ios forward against A fail until you stop the daemon. The proposed ios tunnel stop --udid=A would skip the global restart entirely.
Thanks for considering. This single subcommand would be a huge isolation win for any multi-device orchestrator using go-ios.
Hi — first, thanks for go-ios. Multi-device farm setup we run depends on it pretty heavily.
We've hit a recurring isolation problem and wanted to ask for a small CLI extension that would unblock it cleanly.
Setup
Linux host, kernel TUN tunnel started with sudo ios tunnel start
Multiple iOS devices (5–10) attached, each with its own forwards via ios forward
Long-lived WDA sessions per device; the host runs the tunnel as a single shared daemon process
ios tunnel ls cleanly shows the per-device state — each UDID gets its own IPv6 link-local + RSD port:
[
{ "address": "fdad:85c3:8dc6::1", "rsdPort": 50338, "udid": "00008101-...001E" },
{ "address": "fdc5:cb62:1683::1", "rsdPort": 64148, "udid": "00008101-...001E" },
{ "address": "fdef:64a2:81e::1", "rsdPort": 58811, "udid": "00008101-...003A" }
]
Problem
When a device reboots (post devmode enable --enable-post-restart, post-erase, or just any ios reboot), the tunnel daemon keeps stale state for that specific UDID:
routing table entry pointing at the pre-reboot IPv6 link-local that the device no longer holds
testmanagerd connection bound to the previous device descriptor
(likely) DDI / lockdown channel handle that iOS has since invalidated
Subsequent ios forward against the rebooted device fails with read: network is unreachable against an address that no longer matches what the device announces. Fresh lockdown info and usbmux list see the device fine — only the tunnel side is broken.
The only recovery path the CLI exposes today is ios tunnel stopagent + ios tunnel start, i.e. tearing down the whole shared daemon. That kills every other device's session on the host, mid-command, even though the other devices were never affected by the reboot. In a 10-device farm one factory reset cascades into 10 simultaneous WDA reconnects and the inevitable thundering herd.
What we'd love
A surgical, per-UDID equivalent of stopagent:
ios tunnel stop --udid= # tear down the tunnel for one device only
# (drop route, close testmanagerd, free RSD port)
# next
ios tunnel lsno longer shows it# next
ios forwardagainst that UDID re-handshakesOptionally:
ios tunnel refresh --udid= # tear down + immediately re-create
The goal is: after a per-device reboot, we can refresh just that device's tunnel state without disturbing the other N–1 devices. Other tunnels in ios tunnel ls should keep their addresses, RSD ports, and active forwards untouched.
What we do today (workaround, suboptimal)
We track per-device reboot/erase completion ourselves, hold the tunnel restart until no other slot is in an active WDA session, and only then fuser -k 60105/tcp && ios tunnel start. Even with that gating, every reboot of any device costs a brief outage on every other device. With 10 devices and any factory-reset throughput this is painful.
Implementation hint
Internally ios tunnel ls already iterates per-UDID tunnel records — the data structure exists. A stop --udid would presumably:
find the tunnel record for that UDID,
cancel its goroutines (rsd listener + testmanagerd dispatch),
delete the kernel route to its IPv6 address,
remove the entry from the daemon's state map.
Other tunnels stay live; the daemon keeps running.
Happy to test a branch / PR on a real multi-device farm if you'd like — repro is just ios tunnel start with N devices, ios reboot --udid=A, then watch ios forward against A fail until you stop the daemon. The proposed ios tunnel stop --udid=A would skip the global restart entirely.
Thanks for considering. This single subcommand would be a huge isolation win for any multi-device orchestrator using go-ios.