Documentation ¶
Overview ¶
Package tunnel implements creating a TUN interface for iOS 17 devices. These tunnels are used to connect to services running on the device. On older iOS versions this was done over the 'usbmuxd'-socket. Services that are available via usbmuxd can also be used over the tunnel (they are listed in remote service discovery).
Starting a tunnel is a two-step process:
- Pair Device/Verify Device Pairing
- Setting up a TUN interface
Device Pairing ¶
The step of device pairing means either that a new pairing is set up, or credentials from an already existing pairing are verified. For device pairing we connect to the RemoteXPC service 'com.apple.internal.dt.coredevice.untrusted.tunnelservice' directly on the ethernet interface exposed by the device. Process: - host -> device : 'setupManualPairing' request
- device -> host : device public key and salt to initialize SRP
- host -> device : host public key and SRP client proof
- device -> host : SRP host proof
- host -> device : host info (signed with the key from the host pair record) encrypted with the session key obtained through SRP
- device -> host : device info encrypted with the same key as above
Verifying a device pairing works by signing the host identifier (which is part of the pair record on the host) with a key derived through ECDH. The public keys used there are the key of the pair record on the host and the device provides a public key when the host asks to verify the pairing.
Tunnel Interface ¶
For the TUN interface we continue to use the same connection that we opened for the device pairing. The host asks the device to create a listener, and provides a public key, as well as the requested tunnel type. There are two types of tunnels that can be created, QUIC and TCP. In this package only QUIC is supported. The device will respond with a public key and a port number on which the tunnel endpoint listens on the device. The host opens a QUIC connection using a self-signed certificate with the public key that was sent to the device earlier. The first messages on this QUIC connection exchange the parameters for this tunnel. The host sends a 'clientHandshakeRequest' containing the MTU used for the TUN interface, and the device responds with the information about what IP addresses the host and the device have to use for this tunnel, as well as the port on which remote service discovery (RSD) is reachable on the device
After that all services listed in RSD are available via this TUN interface
Index ¶
- func CloseAgent() error
- func IsAgentRunning() bool
- func RunAgent(args ...string) error
- func ServeTunnelInfo(tm *TunnelManager, port int) error
- func WaitUntilAgentReady() bool
- type Endpoint
- type PairRecordManager
- type Tunnel
- func ConnectTunnelLockdown(device ios.DeviceEntry) (Tunnel, error)
- func ConnectUserSpaceTunnelLockdown(device ios.DeviceEntry, ifacePort int) (Tunnel, error)
- func ListRunningTunnels(tunnelInfoHost string, tunnelInfoPort int) ([]Tunnel, error)
- func ManualPairAndConnectToTunnel(ctx context.Context, device ios.DeviceEntry, p PairRecordManager) (Tunnel, error)
- func TunnelInfoForDevice(udid string, tunnelInfoHost string, tunnelInfoPort int) (Tunnel, error)
- type TunnelManager
- func (m *TunnelManager) Close() error
- func (m *TunnelManager) FindTunnel(udid string) (Tunnel, error)
- func (m *TunnelManager) FirstUpdateCompleted() bool
- func (m *TunnelManager) ListTunnels() ([]Tunnel, error)
- func (m *TunnelManager) RemoveTunnel(ctx context.Context, serialNumber string) error
- func (m *TunnelManager) UpdateTunnels(ctx context.Context) error
- type UserSpaceTUNInterface
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CloseAgent ¶ added in v1.0.129
func CloseAgent() error
func IsAgentRunning ¶ added in v1.0.129
func IsAgentRunning() bool
func ServeTunnelInfo ¶
func ServeTunnelInfo(tm *TunnelManager, port int) error
ServeTunnelInfo starts a simple http serve that exposes the tunnel information about the running tunnel. The API has two endpoints: 1. GET localhost:{PORT}/tunnel/{UDID} to get the tunnel info for a specific device 2. DELETE localhost:{PORT}/tunnel/{UDID} to stop a device tunnel 3. GET localhost:{PORT}/tunnels to get a list of all tunnels
func WaitUntilAgentReady ¶ added in v1.0.129
func WaitUntilAgentReady() bool
Types ¶
type Endpoint ¶ added in v1.0.129
Endpoint implements the interface of stack.LinkEndpoint from io.ReadWriter.
func RWCEndpointNew ¶ added in v1.0.129
RWCEndpointNew creates a new io.ReadWriter based endpoint. It is used to connect the virtual TUN device with the lockdown connection to the device. The lockdown connection expects IP packets as it is a proxy to some virtual network interface on the device. So in essence, the virtual gVisor TUN device will receive normal tcp ip connections and then encode them into IP packets sent to lockdown using a RWCEndpoint.
func (*Endpoint) Attach ¶ added in v1.0.129
func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher)
Attach launches the goroutine that reads packets from io.Reader and dispatches them via the provided dispatcher.
type PairRecordManager ¶
type PairRecordManager struct {
// contains filtered or unexported fields
}
PairRecordManager implements the same logic as macOS related to remote pair records. Those pair records are used whenever a tunnel gets created.
func NewPairRecordManager ¶
func NewPairRecordManager(p string) (PairRecordManager, error)
NewPairRecordManager creates a PairRecordManager that reads/stores the pair records information at the given path To use the same pair records as macOS does, this path should be /var/db/lockdown/RemotePairing/user_501 (user_501 is the default for the root user)
func (PairRecordManager) StoreDeviceInfo ¶
func (p PairRecordManager) StoreDeviceInfo(d device) error
StoreDeviceInfo stores the provided Device info as a plist encoded file in the `peers/` directory
type Tunnel ¶
type Tunnel struct { // Address is the IPv6 address of the device over the tunnel Address string `json:"address"` // RsdPort is the port on which remote service discover is reachable RsdPort int `json:"rsdPort"` // Udid is the id of the device for this tunnel Udid string `json:"udid"` // Userspace TUN device is used, connect to the local tcp port at Default UserspaceTUN bool `json:"userspaceTun"` UserspaceTUNPort int `json:"userspaceTunPort"` // contains filtered or unexported fields }
Tunnel describes the parameters of an established tunnel to the device
func ConnectTunnelLockdown ¶
func ConnectTunnelLockdown(device ios.DeviceEntry) (Tunnel, error)
func ConnectUserSpaceTunnelLockdown ¶ added in v1.0.129
func ConnectUserSpaceTunnelLockdown(device ios.DeviceEntry, ifacePort int) (Tunnel, error)
func ListRunningTunnels ¶
func ManualPairAndConnectToTunnel ¶
func ManualPairAndConnectToTunnel(ctx context.Context, device ios.DeviceEntry, p PairRecordManager) (Tunnel, error)
ManualPairAndConnectToTunnel tries to verify an existing pairing, and if this fails it triggers a new manual pairing process. After a successful pairing a tunnel for this device gets started and the tunnel information is returned
func TunnelInfoForDevice ¶
type TunnelManager ¶
type TunnelManager struct {
// contains filtered or unexported fields
}
TunnelManager starts tunnels for devices when needed (if no tunnel is running yet) and stores the information how those tunnels are reachable (address and remote service discovery port)
func NewTunnelManager ¶
func NewTunnelManager(pm PairRecordManager, userspaceTUN bool) *TunnelManager
NewTunnelManager creates a new TunnelManager instance for setting up device tunnels for all connected devices If userspaceTUN is set to true, the network stack will run in user space.
func (*TunnelManager) Close ¶ added in v1.0.129
func (m *TunnelManager) Close() error
func (*TunnelManager) FindTunnel ¶
func (m *TunnelManager) FindTunnel(udid string) (Tunnel, error)
func (*TunnelManager) FirstUpdateCompleted ¶ added in v1.0.129
func (m *TunnelManager) FirstUpdateCompleted() bool
FirstUpdateCompleted returns true if the first update completed, use it to prevent race conditions when trying to use go-ios agent for the first time
func (*TunnelManager) ListTunnels ¶
func (m *TunnelManager) ListTunnels() ([]Tunnel, error)
ListTunnels provides all currently running device tunnels
func (*TunnelManager) RemoveTunnel ¶ added in v1.0.138
func (m *TunnelManager) RemoveTunnel(ctx context.Context, serialNumber string) error
func (*TunnelManager) UpdateTunnels ¶
func (m *TunnelManager) UpdateTunnels(ctx context.Context) error
UpdateTunnels checks for connected devices and starts a new tunnel if needed On device disconnects the tunnel resources get cleaned up
type UserSpaceTUNInterface ¶ added in v1.0.129
type UserSpaceTUNInterface struct { //If EnableSniffer, raw TCP packets will be dumped to the console. EnableSniffer bool // contains filtered or unexported fields }
UserSpaceTUNInterface uses gVisor's netstack to create a userspace virtual network interface. You can use it to connect local tcp connections to remote adresses on the network. Set it up with the Init method and provide a io.ReadWriter to a IP/TUN compatible device. If EnableSniffer, raw TCP packets will be dumped to the console.
func (*UserSpaceTUNInterface) Init ¶ added in v1.0.129
func (iface *UserSpaceTUNInterface) Init(mtu uint32, connToTUNIface io.ReadWriteCloser, ipAddrString string, prefixLength int) error
Init initializes the virtual network interface. The connToTUNIface needs to be connection that understands IP packets to a remote TUN device or sth. provide mtu, ip address as a string and the prefix length of the interface.
func (*UserSpaceTUNInterface) TunnelRWCThroughInterface ¶ added in v1.0.129
func (iface *UserSpaceTUNInterface) TunnelRWCThroughInterface(localPort uint16, remoteAddr net.IP, remotePort uint16, rw io.ReadWriteCloser) error