summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--README150
-rw-r--r--stuff/README19
-rw-r--r--stuff/com.openssh.sftp.plist41
4 files changed, 211 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b25c15b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
*~
diff --git a/README b/README
new file mode 100644
index 0000000..60c2603
--- /dev/null
+++ b/README
@@ -0,0 +1,150 @@
1.This is an implementation of the iPhone/iPod Touch USB connection protocol.
2
3The server should be mostly compatible with the original Apple usbmuxd
4protocol. This means that a single client lib should be able to interoperate
5with both. Apple has now introduced a new plist-based version of the protocol
6which works in essentially the same way but uses XML-based plists as
7command/response payloads instead of binary blobs. The outer binary protocol is
8still the same used but now the only command/response format is 8 (plist).
9
10The server is under the usbmuxd directory. You'll need CMake and libusb 1.0 to
11build it. In addition, you need to apply the libusb patch in the patches/
12directory. If you want to debug using valgrind, apply the valgrind patch to
13improve the handling of the USB device filesystem ioctls.
14
15There is a Python client library in the python-client directory. It should be
16compatible with Windows, Linux, and OSX (using the Apple usbmuxd on Win and OSX)
17tcprelay.py implements a TCP connection forwarder that lets you pipe TCP
18connections to localhost to the phone. Run it with --help for usage. Note that
19under OSX you'll have to change the socket path from /tmp/usbmuxd to
20/var/run/usbmuxd (there is no socket path on Windows, only a TCP connection to
21localhost). The Python client lib is also compatible with the new plist-based
22protocol and should automatically select it if it sees such a server. However,
23you need Python 2.6 for Windows and Linux in this case, since the plistlib
24module doesn't come with older versions under these OSes (not that you'll have a
25server that supports this protocol under Linux. TODO: does Windows iTunes even
26use this yet?)
27
28ARCHITECTURE
29
30The iPhone / iPod Touch basically implements a rather strange USB networking
31system that operates at a higher level. It is of course completely proprietary.
32Generally speaking, this is what goes on in a typical usage scenario:
33
340. iTunes opens a connection to usbmuxd and asks it for device notifications
351. User inserts phone into computer
362. usbmuxd notices the phone and pings it with a version packet
373. phone replies
384. usbmuxd now considers the phone to be connected and tells iTunes
395. iTunes opens another separate connection to usbmuxd and asks it to connect
40to, say, the afc port on the device
416. usbmuxd sends a pseudo-TCP SYN packet to the phone
427. the phone's kernel driver receives the SYN packet and itself opens a
43 TCP connection to localhost on the afc port
448. the phone replies with a pseudo-TCP SYN/ACK indicating that the port is open
45 and the connection can proceed
467. usbmuxd sends a final ACK to the phone
478. usbmuxd replies to iTunes with a "connection successful" message
489. any data that iTunes writes to the usbmuxd socket from now on is forwarded,
49 through pseudo-TCP, through USB, back into a more regular TCP connection to
50 localhost, to the afc daemon on the phone, and vice versa
51
52The usbmuxd protocol is a relatively simple binary message protocol documented
53here:
54
55http://wikee.iphwn.org/usb:usbmux
56
57Note that once a connection is established the UNIX socket essentially becomes
58a dedicated pipe to the TCP connction and no more high-level control is
59possible (closing the socket closes the TCP connection). Ditto for the "listen
60for devices" mode - usbmuxd will reject any commands in such mode, and the
61socket essentially becomes a dedicated device notification pipe. This means
62that you need, at minimum, TWO connections to usbmuxd to do anything useful.
63
64On Windows, usbmuxd works the same way but a TCP connection to localhost port
6527015 replaces the UNIX socket. On OSX, the UNIX socket is /var/run/usbmuxd. The
66server and client implemented here default to /tmp/usbmuxd at the moment.
67
68The phone protocol operates over a pair of USB bulk endpoints. There is an outer
69layer used for packet size info and a "protocol" (version and TCP are the only
70two options), and that header is followed by TCP headers for actual data comms.
71However, the protocol isn't actual TCP, just a custom protocol which for some
72reason uses a standard TCP header and leaves most fields unused.
73
74There is no reordering or retransmission. There are no checksums, no URG, no
75PSH, no non-ACK, no FIN. What there *is* is the SEQ/ACK/window mechanism used
76for flow control, and RST is used as the only connection teardown mechanism (and
77also for "connection refused"), and the connection startup is SYN/SYNACK/ACK.
78
79Windows are constant-scaled by 8 bits. This is legal TCP as long as the
80corresponding option is negotiated. Of course, no such negotiation happens on
81this protocol.
82
83Note that, since there are no retransmissions, there is some overlap between ACK
84and window for flow control. For example, the server doesn't ever touch its
85window size, and just refuses to ACK stuff if its buffers are full and the
86client isn't reading data. The phone happily seems to stop sending stuff.
87
88Also, if the phone RSTs you out of nowhere, look at the packet payload for a
89textual error message. Note: if it claims to suffer from amnesia, that probably
90means you overflowed its input buffer by ignoring its flow control / window
91size. Go figure. Probably a logic bug in the kernel code.
92
93Note that all normal packets need to have flags set to ACK (and only ACK). There
94is no support for, erm, not-acking. Keep the ack number field valid at all
95times.
96
97
98GOTCHAS AND ANNOYANCES
99
100The usbmuxd CONNECT request port field is byte-swapped (network-endian). This is
101even more annoying for the plist based protocol, since it's even true there
102(where the field is plain text). So even for the plain text int, you need to
103swap the bytes (port 22 becomes <integer>5632</integer>).
104
105There are a bunch of gotchas due to the USB framing, and this is even worse
106because implementations tend to get it wrong (i.e. libusb, and this is the
107reason for the patch). Basically, USB Bulk offers, at the low level, the ability
108to transfer packets from 0 to wMaxPacketSize (512 here) bytes, period. There is
109no other support for higher level framing of transfers. The way you do those is
110by breaking them up into packets, and the final shorter packet parks the end of
111the transfer. The critical bit is that, if the transfer happens to be divisible
112by 512, you send a zero-length packet (ZLP) to indicate the end of the transfer.
113Libusb doesn't set this option by default and the iPhone gets packets stuck to
114each other, which it doesn't like. Actually, this framing is sort of redundant
115because the usbmux packet header includes a length field, but the phone still
116wants the ZLPs or else it breaks. To make matters worse, usbdevfs imposes a max
117transfer size of 16k, so libusb breaks transfers into that size. This is okay
118for sending as long as the ZLP is only added to the last transfer (the patch
119does that), but it can easily cause nasty race conditions on RX due to libusb
120doing multiple outstanding reads at the same time and then cancelling the rest
121when shorter data arrives (but what if some data got into the other requests
122already?), so we only do 16k reads and stick them together ourselves by looking
123at the packet size header. We still depend on ZLPs being sent to end transfers
124at non-16k boundaries that are multiples of 512, but that seems to work fine. I
125guess the ZLPs might cause spurious 0-byte transfers to show up on RX if things
126line up right, but we ignore those. By the way, the maximum packet/transfer size
127is 65535 bytes due to the 16-bit length header of the usbmux protocol.
128
129TODO
130
131The server currently assumes that the phone is well-behaved and does not do a
132bunch of checks like looking for the expected SEQ and ACK numbers from it. This
133is normally not an issue, but it's annoying for debugging because lost packets
134(which shouldn't happen, but can happen if the code is buggy) mean that stuff
135gets out of sync and then might crash and burn dozens of packets later.
136
137The server needs a proper front-end (i.e. daemonizing, commandline options,
138etc), a lot of testing, and some optimizing.
139
140Someone should probably do some edge-case testing on the TCP stuff.
141
142At some point we should probably write a C client lib.
143
144The outgoing ACK handling on the server probably needs some thought. Currently,
145when there's an outstanding ACK, we send it after a timeout (to avoid sending
146a no-payload ACK packet for everything the phone sends us). However, there's
147probably a better way of doing this.
148
149
150
diff --git a/stuff/README b/stuff/README
new file mode 100644
index 0000000..8c5c423
--- /dev/null
+++ b/stuff/README
@@ -0,0 +1,19 @@
1com.openssh.sft.plist is a launchd configuration to set up a bare SFTP server
2on TCP port 2299 localhost-only for USB use. It's nice for relatively fast music
3syncing and file transfer under Linux (and it avoids encryption). Con: it gives
4anyone with usb access root FS access on the phone, as well as anything running
5on the phone itself.
6
7Use it with a command like this:
8
9IPATH=/var/mobile/Media
10MOUNTPOINT=$HOME/media/iphone
11$ sshfs localhost:$IPATH $MOUNTPOINT -o workaround=rename -o directport=2299 \
12 -o kernel_cache -o entry_timeout=30 -o attr_timeout=30
13
14Make sure you run tcprelay.py:
15$ python tcprelay.py -t 2299
16
17Remember that to bypass the stupid new iTunesDB hash you need to edit
18/System/Library/Lockdown/Checkpoint.xml and change DBVersion to 2.
19
diff --git a/stuff/com.openssh.sftp.plist b/stuff/com.openssh.sftp.plist
new file mode 100644
index 0000000..569fabc
--- /dev/null
+++ b/stuff/com.openssh.sftp.plist
@@ -0,0 +1,41 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3<plist version="1.0">
4
5<dict>
6 <key>Label</key>
7 <string>com.openssh.sftpd</string>
8
9 <key>Program</key>
10 <string>/usr/libexec/sftp-server</string>
11
12 <key>ProgramArguments</key>
13 <array>
14 <string>/usr/libexec/sftp-server</string>
15 </array>
16
17 <key>SessionCreate</key>
18 <true/>
19
20 <key>Sockets</key>
21 <dict>
22 <key>Listeners</key>
23 <dict>
24 <key>SockServiceName</key>
25 <string>2299</string>
26 <key>SockNodeName</key>
27 <string>127.0.0.1</string>
28 </dict>
29 </dict>
30
31 <key>StandardErrorPath</key>
32 <string>/dev/null</string>
33
34 <key>inetdCompatibility</key>
35 <dict>
36 <key>Wait</key>
37 <false/>
38 </dict>
39</dict>
40
41</plist>