doronz88/pymobiledevice3

FEATURE REQUEST: RSD tunnel on Linux (iOS >= 17.0, < 17.4)

corrrso opened this issue ยท 29 comments

Test environment
OS: Ubuntu 20.04.1 LTS
Target: tvOS 17.0

I have connected my device via usbmux:

[
    {
        "BuildVersion": "21J354",
        "ConnectionType": "USB",
        "DeviceClass": "AppleTV",
        "DeviceName": "ATV 9904167065",
        "Identifier": "blablabla",
        "ProductType": "AppleTV5,3",
        "ProductVersion": "17.0"
    }
]

And the device is reachable in my network (E.G. if I ping it, I see it).

If I try to run sudo python3 -m pymobiledevice3 remote start-quic-tunnel
I get __main__[2707] ERROR Device is not connected.

I'm a bit stuck over here. I tried to run python3 -m pymobiledevice3 bonjour browse to check what I'm getting returned, the output is

Exception in thread zeroconf-ServiceBrowser-_apple-mobdev2._tcp-2724:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "src/zeroconf/_services/browser.py", line 583, in zeroconf._services.browser.ServiceBrowser.run
  File "src/zeroconf/_services/browser.py", line 452, in zeroconf._services.browser._ServiceBrowserBase._fire_service_state_changed_event
  File "src/zeroconf/_services/browser.py", line 462, in zeroconf._services.browser._ServiceBrowserBase._fire_service_state_changed_event
  File "/usr/local/lib/python3.8/dist-packages/zeroconf/_services/__init__.py", line 56, in fire
    h(**kwargs)
  File "src/zeroconf/_services/browser.py", line 203, in zeroconf._services.browser._service_state_changed_from_listener.on_change
  File "/usr/local/lib/python3.8/dist-packages/pymobiledevice3/bonjour.py", line 51, in add_service
    ipv4 = [socket.inet_ntop(socket.AF_INET, address) for address in info.addresses_by_version(IPVersion.V4Only)]
AttributeError: 'zeroconf._services.info.ServiceInfo' object has no attribute 'addresses_by_version'
[]

I have the feeling I'm missing something very basic over here, but still I'm stuck. How I can then make start-quic-tunnel work, if I can, on Linux? Many thanks.

Currently, Linux is missing driver support for the changes Apple made to the USB ethernet implementation for iOS 17. We have been cooperating with other cool kids on the community's Discord server to be able to work with Linux also.

I hope these changes can be made public soon and part of an official release for the mainline kernel - Which I will definetly tweet about when this happens.

Till then, all I can offer is to wait patiently ๐Ÿ™

Gotcha, I'll join the community then!

Thanks for the info. Please feel free to either close the issue or keep it open until this is done :)

Currently, Linux is missing driver support for the changes Apple made to the USB ethernet implementation for iOS 17. We have been cooperating with other cool kids on the community's Discord server to be able to work with Linux also.

I hope these changes can be made public soon and part of an official release for the mainline kernel - Which I will definetly tweet about when this happens.

Till then, all I can offer is to wait patiently ๐Ÿ™

What's process of ios 17 linux support ? any update? Thanks a lot!

Is it supported on Linux @doronz88 ? Please drop me any updates!

Haven't seen any commit regarding it on linux kernel.

Since some were asking for a clear guide, I'll summarise the steps required to make the tunnel work on linux:

  • Build your own kernel with the following patch:
    idevice_debug_ncm.patch
  • Build and run usbmuxd from sources:
    https://github.com/libimobiledevice/usbmuxd
  • Edit usbmud service file to start with USBMUXD_DEFAULT_DEVICE_MODE=3
    • In file /usr/lib/systemd/system/usbmuxd.service
    ...
    [Service]
    Environment="USBMUXD_DEFAULT_DEVICE_MODE=3"
    ...
    

That's it! everything should work

How can this be used in an Ubuntu Docker container? such like https://hub.docker.com/_/ubuntu

Since some were asking for a clear guide, I'll summarise the steps required to make the tunnel work on linux:

  • Build your own kernel with the following patch:

idevice_debug_ncm.patch

That's it! everything should work

Would this be for libimobiledevice than pymobiledevice3?

I've tried applying the patch to my computer (kernel, as well as usbmuxd), and didn't have any issues doing that.
However, I've been trying to use pymobiledevice3 INSIDE a Docker container (haven't tried outside the container), which I assume should work just fine.
Ie. Docker should reuse my kernel, and therefore the kernel patch should be ok (AFAIK please do correct me!) and I'm forwarding the usbmuxd (patched) socket into the docker container.

I can see the device using usbmux list, but when I try to do remote start-tunnel, it just says device not connected.
However, I'm not sure what that error ACTUALLY means. Does it mean it couldn't find a device to begin starting the tunnel, or did it fail creating the tunnel?

Can somebody give me a sanity check, because I'm not exactly sure what I'm doing wrong here.

Starting docker container

docker run --rm -it -v /var/run/usbmuxd:/var/run/usbmuxd -p 5555:5555 --entrypoint=bash python

installing pymobiledevice3

cd /tmp
git clone https://github.com/doronz88/pymobiledevice3.git
cd pymobiledevice3
python3 -m pip install -U -e .

running commands

root@7cf58f3413c6:/# pymobiledevice3 usbmux list
[
    {
        "BuildVersion": "21B101",
        "ConnectionType": "USB",
        "DeviceClass": "iPhone",
        "DeviceName": "iPhone",
        "Identifier": "XXXXXXXXXXXXXXXXXXXXXXXXX",
        "ProductType": "iPhone14,6",
        "ProductVersion": "17.1.2"
    }
]

root@7cf58f3413c6:/# pymobiledevice3 remote start-tunnel
2024-01-18 11:43:36 7cf58f3413c6 pymobiledevice3.__main__[164] ERROR Device is not connected

I've tried applying the patch to my computer (kernel, as well as usbmuxd), and didn't have any issues doing that. However, I've been trying to use pymobiledevice3 INSIDE a Docker container (haven't tried outside the container), which I assume should work just fine. Ie. Docker should reuse my kernel, and therefore the kernel patch should be ok (AFAIK please do correct me!) and I'm forwarding the usbmuxd (patched) socket into the docker container.

I can see the device using usbmux list, but when I try to do remote start-tunnel, it just says device not connected. However, I'm not sure what that error ACTUALLY means. Does it mean it couldn't find a device to begin starting the tunnel, or did it fail creating the tunnel?

Can somebody give me a sanity check, because I'm not exactly sure what I'm doing wrong here.

Starting docker container

docker run --rm -it -v /var/run/usbmuxd:/var/run/usbmuxd -p 5555:5555 --entrypoint=bash python

installing pymobiledevice3

cd /tmp
git clone https://github.com/doronz88/pymobiledevice3.git
cd pymobiledevice3
python3 -m pip install -U -e .

running commands

root@7cf58f3413c6:/# pymobiledevice3 usbmux list
[
    {
        "BuildVersion": "21B101",
        "ConnectionType": "USB",
        "DeviceClass": "iPhone",
        "DeviceName": "iPhone",
        "Identifier": "XXXXXXXXXXXXXXXXXXXXXXXXX",
        "ProductType": "iPhone14,6",
        "ProductVersion": "17.1.2"
    }
]

root@7cf58f3413c6:/# pymobiledevice3 remote start-tunnel
2024-01-18 11:43:36 7cf58f3413c6 pymobiledevice3.__main__[164] ERROR Device is not connected

I tried outside container and met the same issue, have you resolved? @eyJhb

As someone who uses this wonderful repository (pymobiledevice3) for handling iOS 17 devices on Linux (Ubuntu) extensively I will share some of my knowledge.

  • I downloaded kernel sources directly from official Ubuntu repositories matching my exact version (22.04 LTS) - https://git.launchpad.net/\~ubuntu-kernel/ubuntu/+source/linux/+git/jammy. Then I applied the wonderful patch - https://github.com/doronz88/pymobiledevice3/files/13638682/idevice_debug_ncm.patch. I don't remember but I might've had to enable the idevice_debug_ncm driver in build config. I built the kernel and installed it, mainly following instructions from https://wiki.ubuntu.com/Kernel/BuildYourOwnKernel.
  • I built the latest usbmuxd from sources. I never had to modify any env variables, I believe that the latest version already has all the proper options set (like device mode 3 that @doronz88 suggested).
  • The idevice_debug_ncm driver is going to handle the iPhone's CDC NCM USB debug interface and make it available as a network device, but further action is needed to set up its network interface. You can do it manually using ip commands. You need to assign an IPv6 address to the device (you should see it listed with the command: ip l). The IPv6 address should follow the EUI-64 standard (derived from the CDC NCM device's MAC address). After that, you need to bring the interface up.
  • If you can't do the above step or you use NetworkManager on your system (standard on desktop Ubuntu) or you're willing to switch your networking to it, I have a convenient config that does all the interface setting up described in the previous point.
[connection]
id=ethusb-ios
type=ethernet

[ethernet]

[match]
driver=idevice_debug_ncm;

[ipv4]
method=disabled

[ipv6]
addr-gen-mode=eui64
ip6-privacy=0
method=link-local

[proxy]

This is a NetworkManager keyfile, it usually needs to be put in /etc/NetworkManager/system-connections with a name [something].nmconnection with root ownership and permissions 600. In any doubts, consult NetworkManager documentation.
You need to create as many such files as you want to connect iOS>17 devices. Just change the name and id.
After you reboot, the iPhone connection should be visible as active in NetworkManager connection list - nmcli command.

After you have all that set up, pymobiledevice3 should have no problem connecting to iOS>17 devices.
@haryshi @eyJhb

Wow @jordus100 thanks for the very detailed guide!
Could you submit a PR to add this steps to the README for linux?

@jordus100 thanks a lot for the information, I put the config file ethusb-ios.ncconnection with your quoted contents (just delete the ";" mark in [match] section) in /etc/NetworkManager/system-connections with permissions 600, and sudo reboot ubuntu, but after running command nmcli, the iphone device still displayed as is not connected:

enx9a0daf5f4670: disconnected
"Apple iPhone 5/5C/5S/6/SE/7/8/X"
1 connection available
ethernet (cdc_ncm), 9A:0D:AF:5F:46:70, hw, mtu 1500

my ubuntu version is 24.04, here is my steps:

  1. with kernel version 6.6.3 source file applying the idevice_debug_ncm patch( with command: sudo patch -p1 < idevice_debug_ncm.patch)
  2. build and install the kernel
  3. update GRUB file, sudo reboot and choose the new kernel
  4. build and install usbmuxd from sources
  5. put the usb-ios.ncconnection in /etc/NetworkManager/system-connections
  6. sudo reboot, launch usbmuxd with "sudo usbmuxd -s -f"
  7. run nmcli, the ios 17 device is listed as not connected and pymobiledevice3 cannot find the device.

you mentioned "to enable the idevice_debug_ncm driver in build config", and how to do that? I'm not sure how to confirm the driver is working well, expecting your reply, thanks a lot!

@haryshi if the driver is working properly, you should see two network devices named enx* after connecting the iPhone. One of them should be connected with the standard cdc_ncm driver (you already have that in your nmcli output) and the other via the custom idevice_debug_ncm. Also, maybe try the command nmcli dev as it gives more info about network devices.
Make sure that your iPhone has no passcode set, otherwise the debug interface won't activate (this is perhaps what you have experienced).

@haryshi I have kind of run into a perhaps similar issue to that of yours, please check the output of modinfo idevice_debug_ncm. If it returns an error, that means the kernel doesn't have the custom driver.

idevice_debug_ncm.patch

Couldn't this patch file be made into a kernel module?

idevice_debug_ncm.patch

Couldn't this patch file be made into a kernel module?

It could be but as far as I'm aware no one is working actively on it right now.

update: I've started tinkering with it

Wow @jordus100 thanks for the very detailed guide! Could you submit a PR to add this steps to the README for linux?

Sorry for the late reply, I'm really busy this week but I'll be happy to do that when I find time. Amongst other things, I'm resolving a couple of iOS 17 Linux related issues so maybe I'll post an update if I find out something important.

@jordus100 I succeed to connect to ios 17 device with your guide finally, thanks again, the key point is to enable the driver before build the kernel:

  • with "make menuconfig" command to make sure USB_IDEVICE_DEBUG_NCM is set to m in .config.
    1706688736501-1fdd0b7d-6726-401c-9a55-f3b8417f7656

after reboot of correct setting of /etc/NetworkManager/system-connections, the 'nmcli' command should display iPhone 17 device sth. like this:
enx42144ccaba4c: connected to ethusb-ios
"Apple iPhone 5/5C/5S/6/SE/7/8/X"
ethernet (idevice_debug_ncm), 42:14:4C:CA:BA:4B, hw, mtu 1500
inet6 fe80::4014:4cff:feca:bb4c/64
route6 fe80::/64 metric 1024

@jordus100 I have another question, have you tried pymobiledevice3 in a docker? how to make the device workable in a docker container? It seems to need additional settings.

@haryshi I'm glad you found success! Thanks for writing down the part about the kernel config, I also set it before building but was a bit confused and I didn't know what exactly it was that made it work and I also forgot what I edited.
Regarding pymobiledevice3 in a Docker container, no, I haven't tried that. I'm pretty sure that if you connect the iphone debug interface (enx42144ccaba4c in your case) to the Docker container's network interface with a virtual bridge, pymobiledevice3 would see it and connect.
That being said, I'm not sure if it would all work if the host OS didn't have the idevice_debug_ncm driver and only the Docker container did. An interesting thing to test for sure.

Hello,

I followed @jordus100 instruction and now I got the following entry in nmcli :

enx76b58788813a: connected to ethusb-ios
        "Apple iPhone 5/5C/5S/6/SE/7/8/X/XR"
        ethernet (idevice_debug_ncm), 76:B5:87:88:81:3A, hw, mtu 1500
        inet6 fe80::74b5:87ff:fe88:813a/64
        route6 fe80::/64 metric 1024

enxf64711ccb19a: disconnected
        "Apple iPhone 5/5C/5S/6/SE/7/8/X/XR"
        2 connections available
        ethernet (idevice_debug_ncm), F6:47:11:CC:B1:9A, hw, mtu 1500

but I see that both of them are using idevice_debug_ncm driver.

My issue is the fact that when connected to the first one the tunnel is still not working:

sudo -E python3 -m pymobiledevice3 remote tunneld
INFO:     Started server process [4232]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:5555 (Press CTRL+C to quit)
sudo -E python3 -m pymobiledevice3 remote rsd-info --tunnel ''
2024-02-23 10:41:43 debian __main__[4159] ERROR Device is not connected

If I'm connecting to second connection (enxf64711ccb19a) I get the following error:

sudo -E python3 -m pymobiledevice3 remote tunneld
INFO:     Started server process [4406]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:5555 (Press CTRL+C to quit)
*** stack smashing detected ***: terminated

Any idea what I did wrong?

@haryshi I'm glad you found success! Thanks for writing down the part about the kernel config, I also set it before building but was a bit confused and I didn't know what exactly it was that made it work and I also forgot what I edited. Regarding pymobiledevice3 in a Docker container, no, I haven't tried that. I'm pretty sure that if you connect the iphone debug interface (enx42144ccaba4c in your case) to the Docker container's network interface with a virtual bridge, pymobiledevice3 would see it and connect. That being said, I'm not sure if it would all work if the host OS didn't have the idevice_debug_ncm driver and only the Docker container did. An interesting thing to test for sure.

@jordus100 After I use --privileged and --network=host, I execute: pymobiledevice3 remote start-tunnel inside the container can connect suc.

but , our further goal is to mount multiple ios devices and map them to different docker containers through --device.
It cannot use the --network=host but --network=bridge mode. Is there any command to map it into?


<Thank you very much!>

 \
  \
  /  \~~~/  \
 (    ..     )----,
  \__     __/      \
    )|  /)         |\
     | /\  /___\   / ^
      "-|__|   |__|

@jordus100 After I use --privileged and --network=host, I execute: pymobiledevice3 remote start-tunnel inside the container can connect suc.

but , our further goal is to mount multiple ios devices and map them to different docker containers through --device. It cannot use the --network=host but --network=bridge mode. Is there any command to map it into?

That's great news about the Docker container working, thanks for sharing! As for mapping individual devices, I haven't looked into it at all.

Haven't seen any commit regarding it on linux kernel.

https://marc.info/?l=linux-usb&m=170138175510294&w=4

FYI authors of go-ios have written a Go program that will create interfaces directly from USB devices without a kernel module.

See https://github.com/danielpaulus/go-ios/tree/89f480768e8c3311da72c3ef50a2d19547bf2761/ncm
Also see the Makefile at the root of the project. It builds the tool. Just run the tool as root and it does it's thing.

@nanoscopic I tried go-ncm on linux docker but could not create the network interface. Not sure what I was missing

I'm not familiar enough with the project or a Linux user myself. If any of you manages to get this to work well, feel free to submit a PR ๐Ÿ˜ƒ
This can be either implemented proabably in pure Python (preferred way), or we'll bundle it as a resource for Linux installations. Prefereably this should be a shared library and wrap it using ctypes as we do with wintun

@nanoscopic I tried go-ncm on linux docker but could not create the network interface. Not sure what I was missing

Unless you are giving the container full system access, I'm pretty sure it won't work from a container.
It needs to be able to create a utun and have USB access to the device(s)

You don't need to run it as root. On Linux you can just give it permissions to make make/manage utuns and that should be sufficient.