diff options
Diffstat (limited to 'README')
| -rw-r--r-- | README | 185 |
1 files changed, 155 insertions, 30 deletions
| @@ -1,31 +1,37 @@ | |||
| 1 | Background | 1 | Background |
| 2 | ========== | 2 | ========== |
| 3 | 3 | ||
| 4 | 'usbmuxd' stands for "USB multiplexing daemon". To the user/developer | 4 | 'usbmuxd' stands for "USB multiplexing daemon". To the user/developer what it |
| 5 | what it actually does is to proxy requests over a USB cable on directly | 5 | actually does is to proxy requests over a USB cable on directly to a listening |
| 6 | to a listening TCP port on the iPhone. | 6 | TCP port on the iPhone. |
| 7 | 7 | ||
| 8 | Multiple connections to different TCP ports can happen in parallel. | 8 | Multiple connections to different TCP ports can happen in parallel. An example |
| 9 | An example (and useful) tool called 'iproxy' is included that allows | 9 | (and useful) tool called 'iproxy' is included that allows you to forward |
| 10 | you to forward localhost ports to the device---allows SSH over USB on | 10 | localhost ports to the device---allows SSH over USB on jailbroken devices, or |
| 11 | jailbroken devices, or allowing access the lockdown daemon (and then | 11 | allowing access the lockdown daemon (and then to all of the file access, sync, |
| 12 | to all of the file access, sync, notification and backup services | 12 | notification and backup services running on the device). |
| 13 | running on the device). | 13 | |
| 14 | 14 | This higher-level layers are handled by libiphone. The version of libiphone | |
| 15 | This higher-level layers are handled by libiphone. The version of | 15 | compatible with the 'usbmuxd' infrastructure is called 'libiphone-usbmuxd'. |
| 16 | libiphone compatible with the 'usbmuxd' infrastructure is called | 16 | 'ifuse' is then able to sit on top of this. |
| 17 | 'libiphone-usbmuxd'. 'ifuse' is then able to sit on top of this. | 17 | |
| 18 | 18 | There is also a Python implementation of the client library in the python-client | |
| 19 | library, and an example tcprelay.py which performs a similar function to iproxy. | ||
| 20 | This implementation supports OSX and Windows and the new iTunes plist-based | ||
| 21 | usbmuxd protocol, so it is portable and will run on those operating systems with | ||
| 22 | no modification, using Apple's native usbmuxd. This is useful if you need to | ||
| 23 | tunnel to your phone from another OS in a pinch. Run python tcpclient.py --help | ||
| 24 | for usage information. | ||
| 19 | 25 | ||
| 20 | Building | 26 | Building |
| 21 | ======== | 27 | ======== |
| 22 | 28 | ||
| 23 | ./autogen.sh | 29 | mkdir build |
| 24 | ./configure --sysconfdir=/etc | 30 | cd build |
| 31 | cmake .. | ||
| 25 | make | 32 | make |
| 26 | sudo make install | 33 | sudo make install |
| 27 | 34 | ||
| 28 | |||
| 29 | Running (with magic) | 35 | Running (with magic) |
| 30 | ==================== | 36 | ==================== |
| 31 | 37 | ||
| @@ -33,21 +39,21 @@ Running (with magic) | |||
| 33 | ./iproxy 2222 22 & | 39 | ./iproxy 2222 22 & |
| 34 | ssh -p 2222 root@localhost | 40 | ssh -p 2222 root@localhost |
| 35 | 41 | ||
| 36 | Hopefully you get the normal SSH login prompt. You may still lots of | 42 | Hopefully you get the normal SSH login prompt. You may still lots of debugging |
| 37 | debugging output for the moment. If this is getting in the way of | 43 | output for the moment. If this is getting in the way of your ssh login, then |
| 38 | your ssh login, then run the 'ssh' command from a different xterminal | 44 | run the 'ssh' command from a different xterminal |
| 39 | or virtual console. | 45 | or virtual console. |
| 40 | 46 | ||
| 41 | 47 | ||
| 42 | Running (without magic) | 48 | Running (without magic) |
| 43 | ======================= | 49 | ======================= |
| 44 | 50 | ||
| 45 | If 'udev' is _not_ automatically running on your machine and picking | 51 | If 'udev' is _not_ automatically running on your machine and picking up the new |
| 46 | up the new .rules file, you will need to start usbmuxd by hand first. | 52 | .rules file, you will need to start usbmuxd by hand first. Check it's running |
| 47 | Check it's running and that there is only one copy with 'ps aux | grep | 53 | and that there is only one copy with 'ps aux | grep |
| 48 | usbmuxd'. | 54 | usbmuxd'. |
| 49 | 55 | ||
| 50 | sudo usbmuxd & | 56 | sudo usbmuxd -U -v -v & |
| 51 | ./iproxy 2222 22 & | 57 | ./iproxy 2222 22 & |
| 52 | ssh -p 2222 root@localhost | 58 | ssh -p 2222 root@localhost |
| 53 | 59 | ||
| @@ -55,13 +61,13 @@ usbmuxd'. | |||
| 55 | Tip: Starting SSH if disabled | 61 | Tip: Starting SSH if disabled |
| 56 | ============================= | 62 | ============================= |
| 57 | 63 | ||
| 58 | If your iphone is rooted, but SSH isn't started and you _cannot_ (for | 64 | If your iphone is rooted, but SSH isn't started and you _cannot_ (for instance, |
| 59 | instance, cracked/broken screen) get to the Services control panel on | 65 | cracked/broken screen) get to the Services control panel on the device, then you |
| 60 | the device, then you can start the SSH service over the USB by | 66 | can start the SSH service over the USB by |
| 61 | mounting the (jailbroken) filesystem. | 67 | mounting the (jailbroken) filesystem. |
| 62 | 68 | ||
| 63 | You will need to mount it usbing 'ifuse --afc2' (to access the root | 69 | You will need to mount it usbing 'ifuse --afc2' (to access the root directory of |
| 64 | directory of the device), and then edit: | 70 | the device), and then edit: |
| 65 | 71 | ||
| 66 | /Library/LaunchDaemons/com.openssh.sshd.plist | 72 | /Library/LaunchDaemons/com.openssh.sshd.plist |
| 67 | 73 | ||
| @@ -71,3 +77,122 @@ to _remove_ the lines: | |||
| 71 | <true/> | 77 | <true/> |
| 72 | 78 | ||
| 73 | Reboot the device and then sshd should be running. | 79 | Reboot the device and then sshd should be running. |
| 80 | |||
| 81 | TODO | ||
| 82 | ==== | ||
| 83 | |||
| 84 | The server currently assumes that the phone is well-behaved and does not do a | ||
| 85 | bunch of checks like looking for the expected SEQ and ACK numbers from it. This | ||
| 86 | is normally not an issue, but it's annoying for debugging because lost packets | ||
| 87 | (which shouldn't happen, but can happen if the code is buggy) mean that stuff | ||
| 88 | gets out of sync and then might crash and burn dozens of packets later. | ||
| 89 | |||
| 90 | The server needs more testing, and some optimizing. | ||
| 91 | |||
| 92 | Someone should probably do some edge-case testing on the TCP stuff. | ||
| 93 | |||
| 94 | The outgoing ACK handling on the server probably needs some thought. Currently, | ||
| 95 | when there's an outstanding ACK, we send it after a timeout (to avoid sending | ||
| 96 | a no-payload ACK packet for everything the phone sends us). However, there's | ||
| 97 | probably a better way of doing this. | ||
| 98 | |||
| 99 | Architecture information | ||
| 100 | ======================== | ||
| 101 | |||
| 102 | The iPhone / iPod Touch basically implements a rather strange USB networking | ||
| 103 | system that operates at a higher level. It is of course completely proprietary. | ||
| 104 | Generally speaking, this is what goes on in a typical usage scenario: | ||
| 105 | |||
| 106 | 0. iTunes opens a connection to usbmuxd and asks it for device notifications | ||
| 107 | 1. User inserts phone into computer | ||
| 108 | 2. usbmuxd notices the phone and pings it with a version packet | ||
| 109 | 3. phone replies | ||
| 110 | 4. usbmuxd now considers the phone to be connected and tells iTunes | ||
| 111 | 5. iTunes opens another separate connection to usbmuxd and asks it to connect | ||
| 112 | to, say, the afc port on the device | ||
| 113 | 6. usbmuxd sends a pseudo-TCP SYN packet to the phone | ||
| 114 | 7. the phone's kernel driver receives the SYN packet and itself opens a | ||
| 115 | TCP connection to localhost on the afc port | ||
| 116 | 8. the phone replies with a pseudo-TCP SYN/ACK indicating that the port is open | ||
| 117 | and the connection can proceed | ||
| 118 | 7. usbmuxd sends a final ACK to the phone | ||
| 119 | 8. usbmuxd replies to iTunes with a "connection successful" message | ||
| 120 | 9. any data that iTunes writes to the usbmuxd socket from now on is forwarded, | ||
| 121 | through pseudo-TCP, through USB, back into a more regular TCP connection to | ||
| 122 | localhost, to the afc daemon on the phone, and vice versa | ||
| 123 | |||
| 124 | The usbmuxd protocol is a relatively simple binary message protocol documented | ||
| 125 | here: | ||
| 126 | |||
| 127 | http://wikee.iphwn.org/usb:usbmux | ||
| 128 | |||
| 129 | Note that once a connection is established the UNIX socket essentially becomes | ||
| 130 | a dedicated pipe to the TCP connction and no more high-level control is | ||
| 131 | possible (closing the socket closes the TCP connection). Ditto for the "listen | ||
| 132 | for devices" mode - usbmuxd will reject any commands in such mode, and the | ||
| 133 | socket essentially becomes a dedicated device notification pipe. This means | ||
| 134 | that you need, at minimum, TWO connections to usbmuxd to do anything useful. | ||
| 135 | |||
| 136 | On Windows, usbmuxd works the same way but a TCP connection to localhost port | ||
| 137 | 27015 replaces the UNIX socket. On OSX, the UNIX socket is /var/run/usbmuxd. The | ||
| 138 | server and client implemented here default to /tmp/usbmuxd at the moment. | ||
| 139 | |||
| 140 | The phone protocol operates over a pair of USB bulk endpoints. There is an outer | ||
| 141 | layer used for packet size info and a "protocol" (version and TCP are the only | ||
| 142 | two options), and that header is followed by TCP headers for actual data comms. | ||
| 143 | However, the protocol isn't actual TCP, just a custom protocol which for some | ||
| 144 | reason uses a standard TCP header and leaves most fields unused. | ||
| 145 | |||
| 146 | There is no reordering or retransmission. There are no checksums, no URG, no | ||
| 147 | PSH, no non-ACK, no FIN. What there *is* is the SEQ/ACK/window mechanism used | ||
| 148 | for flow control, and RST is used as the only connection teardown mechanism (and | ||
| 149 | also for "connection refused"), and the connection startup is SYN/SYNACK/ACK. | ||
| 150 | |||
| 151 | Windows are constant-scaled by 8 bits. This is legal TCP as long as the | ||
| 152 | corresponding option is negotiated. Of course, no such negotiation happens on | ||
| 153 | this protocol. | ||
| 154 | |||
| 155 | Note that, since there are no retransmissions, there is some overlap between ACK | ||
| 156 | and window for flow control. For example, the server doesn't ever touch its | ||
| 157 | window size, and just refuses to ACK stuff if its buffers are full and the | ||
| 158 | client isn't reading data. The phone happily seems to stop sending stuff. | ||
| 159 | |||
| 160 | Also, if the phone RSTs you out of nowhere, look at the packet payload for a | ||
| 161 | textual error message. Note: if it claims to suffer from amnesia, that probably | ||
| 162 | means you overflowed its input buffer by ignoring its flow control / window | ||
| 163 | size. Go figure. Probably a logic bug in the kernel code. | ||
| 164 | |||
| 165 | Note that all normal packets need to have flags set to ACK (and only ACK). There | ||
| 166 | is no support for, erm, not-acking. Keep the ack number field valid at all | ||
| 167 | times. | ||
| 168 | |||
| 169 | The usbmuxd CONNECT request port field is byte-swapped (network-endian). This is | ||
| 170 | even more annoying for the plist based protocol, since it's even true there | ||
| 171 | (where the field is plain text). So even for the plain text int, you need to | ||
| 172 | swap the bytes (port 22 becomes <integer>5632</integer>). I have no clue if this | ||
| 173 | is the case on the new plist protocol on PPC macs (is the newer iTunes available | ||
| 174 | for those?) | ||
| 175 | |||
| 176 | There are a bunch of gotchas due to the USB framing, and this is even worse | ||
| 177 | because implementations tend to get it wrong (i.e. libusb, and this is the | ||
| 178 | reason for the patch). Basically, USB Bulk offers, at the low level, the ability | ||
| 179 | to transfer packets from 0 to wMaxPacketSize (512 here) bytes, period. There is | ||
| 180 | no other support for higher level framing of transfers. The way you do those is | ||
| 181 | by breaking them up into packets, and the final shorter packet marks the end of | ||
| 182 | the transfer. The critical bit is that, if the transfer happens to be divisible | ||
| 183 | by 512, you send a zero-length packet (ZLP) to indicate the end of the transfer. | ||
| 184 | Libusb doesn't set this option by default and the iPhone gets packets stuck to | ||
| 185 | each other, which it doesn't like. Actually, this framing is sort of redundant | ||
| 186 | because the usbmux packet header includes a length field, but the phone still | ||
| 187 | wants the ZLPs or else it breaks. To make matters worse, usbdevfs imposes a max | ||
| 188 | transfer size of 16k, so libusb breaks transfers into that size. This is okay | ||
| 189 | for sending as long as the ZLP is only added to the last transfer (the patch | ||
| 190 | does that), but it can easily cause nasty race conditions on RX due to libusb | ||
| 191 | doing multiple outstanding reads at the same time and then cancelling the rest | ||
| 192 | when shorter data arrives (but what if some data got into the other requests | ||
| 193 | already?), so we only do 16k reads and stick them together ourselves by looking | ||
| 194 | at the packet size header. We still depend on ZLPs being sent to end transfers | ||
| 195 | at non-16k boundaries that are multiples of 512, but that seems to work fine. I | ||
| 196 | guess the ZLPs might cause spurious 0-byte transfers to show up on RX if things | ||
| 197 | line up right, but we ignore those. By the way, the maximum packet/transfer size | ||
| 198 | is 65535 bytes due to the 16-bit length header of the usbmux protocol. | ||
