From 3de42ec13a5cbf83dbb6e6ace2d47d5d02f4bf04 Mon Sep 17 00:00:00 2001 From: ZhouYixun <291028775@qq.com> Date: Mon, 28 Nov 2022 00:00:58 +0800 Subject: [PATCH] fix: rm issue --- device.go | 242 +++++++++++++++++++++- device_test.go | 80 +++++++ idevice.go | 2 + pkg/libimobiledevice/client_dtxmessage.go | 1 - pkg/libimobiledevice/usbmux.go | 35 +++- pkg/libimobiledevice/webinspector.go | 17 ++ usbmux.go | 4 +- 7 files changed, 371 insertions(+), 10 deletions(-) diff --git a/device.go b/device.go index 201a5c1..f15103b 100644 --- a/device.go +++ b/device.go @@ -1,10 +1,31 @@ +/* + * sonic-gidevice Connect to your iOS Devices. + * Copyright (C) 2022 SonicCloudOrg + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package giDevice import ( "bytes" "context" + "encoding/binary" "errors" "fmt" + "io" + "log" + "net" "os" "path" "strings" @@ -28,7 +49,40 @@ func newDevice(client *libimobiledevice.UsbmuxClient, properties DevicePropertie } } +func NewRemoteConnect(ip string, port int) *device { + client, err := libimobiledevice.NewUsbmuxClient(fmt.Sprintf("%s:%d", ip, port)) + if err != nil { + log.Panic(err) + } + + clientConnectInit(client.InnerConn()) + + devicePropertiesPacket, err := client.ReceivePacket() + if err != nil { + log.Panic(err) + } + var properties = &DeviceProperties{} + err = devicePropertiesPacket.Unmarshal(properties) + if err != nil { + log.Panic(err) + } + buffer := new(bytes.Buffer) + data, err1 := client.InnerConn().Read(4) + if err1 != nil { + log.Panic(err1) + } + buffer.Write(data) + var remoteLockdownPort uint32 + if err = binary.Read(buffer, binary.LittleEndian, &remoteLockdownPort); err != nil { + log.Panic(err) + } + dev := newDevice(client, *properties) + dev.remoteAddr = fmt.Sprintf("%s:%d", ip, remoteLockdownPort) + return dev +} + type device struct { + remoteAddr string umClient *libimobiledevice.UsbmuxClient lockdownClient *libimobiledevice.LockdownClient @@ -56,11 +110,16 @@ func (d *device) Properties() DeviceProperties { } func (d *device) NewConnect(port int, timeout ...time.Duration) (InnerConn, error) { - newClient, err := libimobiledevice.NewUsbmuxClient(timeout...) + + newClient, err := libimobiledevice.NewUsbmuxClient(d.remoteAddr, timeout...) if err != nil { return nil, err } + if d.remoteAddr != "" { + clientConnectInit(newClient.InnerConn()) + } + var pkt libimobiledevice.Packet if pkt, err = newClient.NewPlistPacket( newClient.NewConnectRequest(d.properties.DeviceID, port), @@ -381,6 +440,105 @@ func (d *device) testmanagerdService() (testmanagerd Testmanagerd, err error) { return } +func (d *device) Share(port int) error { + + ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + if err != nil { + return err + } + address, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:0", "0.0.0.0")) + if err != nil { + return err + } + + lockdownLn, err := net.ListenTCP("tcp", address) + if err != nil { + return err + } + go func() { + err = d.shareBaseTcpServer(ln, lockdownLn.Addr().(*net.TCPAddr).Port) + if err != nil { + log.Panic(err) + } + }() + + return d.shareServer(lockdownLn) +} + +func (d *device) shareBaseTcpServer(ln net.Listener, serverPort int) error { + defer ln.Close() + for { + conn, err := ln.Accept() + if err != nil { + return err + } + remoteAddress := conn.RemoteAddr().String() + if debugFlag { + log.Printf("Incomming base request from: %v\n", remoteAddress) + } + + var remoteUsb = libimobiledevice.NewRemoteUsbmuxConn(conn) + localUsb, err := libimobiledevice.NewUsbmuxClient("", 0) + if err != nil { + log.Panic(err) + } + + if !serverCheckInit(remoteUsb.InnerConn()) { + continue + } + + propertiesPacket, err := remoteUsb.NewPlistPacket(d.properties) + if err != nil { + log.Panic(err) + } + err = remoteUsb.SendPacket(propertiesPacket) + if err != nil { + log.Panic(err) + } + + buf := new(bytes.Buffer) + b := make([]byte, 4) + binary.LittleEndian.PutUint32(b, uint32(serverPort)) + buf.Write(b) + _, err = conn.Write(buf.Bytes()) + if err != nil { + log.Panic(err) + } + forwardingData(conn, localUsb.RawConn()) + } +} + +func (d *device) shareServer(ln net.Listener) error { + defer ln.Close() + for { + conn, err := ln.Accept() + if err != nil { + return err + } + remoteAddress := conn.RemoteAddr().String() + + var remoteUsb = libimobiledevice.NewRemoteUsbmuxConn(conn) + + if !serverCheckInit(remoteUsb.InnerConn()) { + remoteUsb.Close() + continue + } + + if debugFlag { + log.Printf("Incomming server request from: %v\n", remoteAddress) + } + + newClient, err := libimobiledevice.NewUsbmuxClient("", 0) + if err != nil { + log.Panic(err) + } + + rConn := newClient.RawConn() + rConn.SetDeadline(time.Time{}) + forwardingData(conn, rConn) + } +} + func (d *device) AfcService() (afc Afc, err error) { if d.afc != nil { return d.afc, nil @@ -887,7 +1045,6 @@ func (d *device) XCTest(bundleID string, opts ...XCTestOption) (out <-chan strin return _out, cancelFunc, err } - // see https://github.com/SonicCloudOrg/sonic-gidevice/issues/31 // if err = d.instruments.startObserving(pid); err != nil { // return _out, cancelFunc, err // } @@ -972,3 +1129,84 @@ func (d *device) _uploadXCTestConfiguration(bundleID string, sessionId uuid.UUID return } + +func serverCheckInit(conn InnerConn) bool { + if !checkRecvMagic(conn, true) { + conn.Close() + return false + } + + buf := new(bytes.Buffer) + b := make([]byte, 4) + binary.LittleEndian.PutUint32(b, uint32(5)) + buf.Write(b) + buf.Write(checkMagic[6:]) + + err := conn.Write(buf.Bytes()) + if err != nil { + log.Panic(err) + } + return true +} + +func clientConnectInit(conn InnerConn) { + buf := new(bytes.Buffer) + b := make([]byte, 4) + + binary.LittleEndian.PutUint32(b, uint32(6)) + buf.Write(b) + buf.Write(checkMagic[:6]) + + err := conn.Write(buf.Bytes()) + if err != nil { + log.Panic(err) + } + if !checkRecvMagic(conn, false) { + conn.Close() + log.Panic("connection failed non remote sib connection") + } +} + +func forwardingData(lConn, rConn net.Conn) { + go func(lConn, rConn net.Conn) { + if _, err := io.Copy(lConn, rConn); err != nil { + lConn.Close() + rConn.Close() + if debugFlag { + log.Println(err) + } + return + } + }(lConn, rConn) + go func(lConn, rConn net.Conn) { + if _, err := io.Copy(rConn, lConn); err != nil { + lConn.Close() + rConn.Close() + if debugFlag { + log.Println(err) + } + return + } + }(lConn, rConn) +} + +// the connection is of the specified type +var checkMagic = [11]byte{0x61, 0x4F, 0x47, 0x32, 0x77, 0x6F, 0x53, 0x45, 0x45, 0x73, 0x2F} + +func checkRecvMagic(conn InnerConn, isPrefix bool) bool { + data, err := conn.Read(4) + if err != nil { + log.Panic(err) + } + data, err = conn.Read(int(binary.LittleEndian.Uint32(data))) + if err != nil { + log.Panic(err) + } + var subMagic []byte + if isPrefix { + subMagic = checkMagic[:6] + } else { + subMagic = checkMagic[6:] + } + return bytes.Equal(subMagic, data) +} diff --git a/device_test.go b/device_test.go index 00de1fc..c403550 100644 --- a/device_test.go +++ b/device_test.go @@ -2,6 +2,7 @@ package giDevice import ( "fmt" + "log" "os" "os/signal" "testing" @@ -172,3 +173,82 @@ func Test_device_InstallationProxyBrowse(t *testing.T) { t.Logf("%#v", l) } } + +func Test_device_share(t *testing.T) { + setupDevice(t) + SetDebug(true, true) + err := dev.Share(9123) + if err != nil { + log.Panic(err) + } +} + +func Test_device_connect(t *testing.T) { + SetDebug(true, true) + remoteDev := NewRemoteConnect("127.0.0.1", 9123) + data, err := remoteDev.GetValue("", "ProductVersion") + if err != nil { + log.Panic(err) + } + log.Println(data) +} + +func TestMockPerfdUser1(t *testing.T) { + //SetDebug(true, true) + remoteDev := NewRemoteConnect("127.0.0.1", 9123) + data, err := remoteDev.PerfStart( + WithPerfSystemCPU(true), + WithPerfSystemMem(true), + WithPerfSystemDisk(true), + WithPerfSystemNetwork(true), + WithPerfNetwork(true), + WithPerfFPS(true), + WithPerfGPU(true), + //WithPerfProcessAttributes("cpuUsage", "memAnon"), + //WithPerfBundleID("com.apple.mobilesafari"), + ) + if err != nil { + t.Fatal(err) + } + + timer := time.NewTimer(time.Duration(time.Second * 20)) + for { + select { + case <-timer.C: + dev.PerfStop() + return + case d := <-data: + fmt.Println(string(d)) + } + } +} + +func TestMockPerfdUser2(t *testing.T) { + //SetDebug(true, true) + remoteDev := NewRemoteConnect("127.0.0.1", 9123) + data, err := remoteDev.PerfStart( + WithPerfSystemCPU(true), + WithPerfSystemMem(true), + WithPerfSystemDisk(true), + WithPerfSystemNetwork(true), + WithPerfNetwork(true), + WithPerfFPS(true), + WithPerfGPU(true), + //WithPerfProcessAttributes("cpuUsage", "memAnon"), + //WithPerfBundleID("com.apple.mobilesafari"), + ) + if err != nil { + t.Fatal(err) + } + + timer := time.NewTimer(time.Duration(time.Second * 10)) + for { + select { + case <-timer.C: + dev.PerfStop() + return + case d := <-data: + fmt.Println(string(d)) + } + } +} diff --git a/idevice.go b/idevice.go index 7f83a09..3da5147 100644 --- a/idevice.go +++ b/idevice.go @@ -81,6 +81,8 @@ type Device interface { PerfStop() WebInspectorService() (webInspector WebInspector, err error) + + Share(port int) error } type DeviceProperties = libimobiledevice.DeviceProperties diff --git a/pkg/libimobiledevice/client_dtxmessage.go b/pkg/libimobiledevice/client_dtxmessage.go index 7fed570..7c03e35 100644 --- a/pkg/libimobiledevice/client_dtxmessage.go +++ b/pkg/libimobiledevice/client_dtxmessage.go @@ -179,7 +179,6 @@ func (c *dtxMessageClient) ReceiveDTXMessage() (result *DTXMessageResult, err er var aux, obj []byte - // see https://github.com/SonicCloudOrg/sonic-gidevice/issues/28 if r, l := payloadSize+payload.AuxiliaryLength, len(rawPayload); int(r) <= l { aux = rawPayload[payloadSize:r] } else { diff --git a/pkg/libimobiledevice/usbmux.go b/pkg/libimobiledevice/usbmux.go index 06b32a1..2d7743c 100644 --- a/pkg/libimobiledevice/usbmux.go +++ b/pkg/libimobiledevice/usbmux.go @@ -1,3 +1,20 @@ +/* + * sonic-gidevice Connect to your iOS Devices. + * Copyright (C) 2022 SonicCloudOrg + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package libimobiledevice import ( @@ -15,7 +32,7 @@ import ( var DefaultDeadlineTimeout = 30 * time.Second const ( - BundleID = "electricbubble.libimobiledevice" + BundleID = "org.cloud.sonic.gidevice" ProgramName = "libimobiledevice" ClientVersion = "libimobiledevice-beta" LibUSBMuxVersion = 3 @@ -112,13 +129,13 @@ type DeviceProperties struct { NetworkAddress []byte `plist:"NetworkAddress"` } -func NewUsbmuxClient(timeout ...time.Duration) (c *UsbmuxClient, err error) { +func NewUsbmuxClient(addr string, timeout ...time.Duration) (c *UsbmuxClient, err error) { if len(timeout) == 0 { timeout = []time.Duration{DefaultDeadlineTimeout} } c = &UsbmuxClient{version: ProtoVersionPlist} var conn net.Conn - if conn, err = rawDial(timeout[0]); err != nil { + if conn, err = rawDial(addr, timeout[0]); err != nil { return nil, fmt.Errorf("usbmux connect: %w", err) } @@ -126,6 +143,12 @@ func NewUsbmuxClient(timeout ...time.Duration) (c *UsbmuxClient, err error) { return } +func NewRemoteUsbmuxConn(conn net.Conn) (c *UsbmuxClient) { + c = &UsbmuxClient{version: ProtoVersionPlist} + c.innerConn = newInnerConn(conn, 0) + return +} + type UsbmuxClient struct { innerConn InnerConn version ProtoVersion @@ -259,11 +282,13 @@ func (c *UsbmuxClient) InnerConn() InnerConn { return c.innerConn } -func rawDial(timeout time.Duration) (net.Conn, error) { +func rawDial(addr string, timeout time.Duration) (net.Conn, error) { dialer := net.Dialer{ Timeout: timeout, } - + if addr != "" { + return dialer.Dial("tcp", addr) + } var network, address string switch runtime.GOOS { case "darwin", "android", "linux": diff --git a/pkg/libimobiledevice/webinspector.go b/pkg/libimobiledevice/webinspector.go index 1f7f521..6d6de5d 100644 --- a/pkg/libimobiledevice/webinspector.go +++ b/pkg/libimobiledevice/webinspector.go @@ -1,3 +1,20 @@ +/* + * sonic-gidevice Connect to your iOS Devices. + * Copyright (C) 2022 SonicCloudOrg + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package libimobiledevice import ( diff --git a/usbmux.go b/usbmux.go index c6a986f..6050536 100644 --- a/usbmux.go +++ b/usbmux.go @@ -9,7 +9,7 @@ import ( var _ Usbmux = (*usbmux)(nil) func NewUsbmux() (Usbmux, error) { - umClient, err := libimobiledevice.NewUsbmuxClient() + umClient, err := libimobiledevice.NewUsbmuxClient("") if err != nil { return nil, err } @@ -99,7 +99,7 @@ func (um *usbmux) Listen(devNotifier chan Device) (context.CancelFunc, error) { if baseDev.MessageType != libimobiledevice.MessageTypeDeviceAdd { baseDev.Properties.DeviceID = baseDev.DeviceID } - client, err := libimobiledevice.NewUsbmuxClient() + client, err := libimobiledevice.NewUsbmuxClient("") if err != nil { continue }