pymobiledevice3 4.27.6__tar.gz → 5.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pymobiledevice3 might be problematic. Click here for more details.

Files changed (228) hide show
  1. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/PKG-INFO +1 -2
  2. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/__main__.py +0 -1
  3. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/_version.py +3 -3
  4. pymobiledevice3-5.0.0/pymobiledevice3/bonjour.py +402 -0
  5. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/bonjour.py +4 -4
  6. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/lockdown.py +7 -2
  7. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/remote.py +4 -3
  8. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/lockdown.py +7 -12
  9. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/tunnel_service.py +16 -8
  10. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/utils.py +2 -2
  11. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/mobile_image_mounter.py +1 -1
  12. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/tunneld/server.py +118 -79
  13. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/usbmux.py +16 -12
  14. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/utils.py +1 -1
  15. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3.egg-info/PKG-INFO +1 -2
  16. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3.egg-info/requires.txt +0 -1
  17. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/requirements.txt +0 -1
  18. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/conftest.py +0 -1
  19. pymobiledevice3-4.27.6/pymobiledevice3/bonjour.py +0 -145
  20. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.gitattributes +0 -0
  21. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/FUNDING.yml +0 -0
  22. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  23. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  24. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  25. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/pull_request_template.md +0 -0
  26. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/workflows/codeql.yml +0 -0
  27. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/workflows/generate-executable.py +0 -0
  28. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/workflows/markdown-lint.yml +0 -0
  29. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/workflows/python-app.yml +0 -0
  30. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.github/workflows/python-publish.yml +0 -0
  31. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.gitignore +0 -0
  32. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/.pre-commit-config.yaml +0 -0
  33. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/CODE_OF_CONDUCT.md +0 -0
  34. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/CONTRIBUTING.md +0 -0
  35. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/LICENSE +0 -0
  36. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/README.md +0 -0
  37. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/example.gif +0 -0
  38. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/markdownlint-config.json +0 -0
  39. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/misc/DTServices-14.2.txt +0 -0
  40. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/misc/DTServices-14.5.txt +0 -0
  41. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/misc/RemoteXPC.md +0 -0
  42. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/misc/plist_sniffer.py +0 -0
  43. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/misc/pyinstaller.md +0 -0
  44. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/misc/remotexpc_sniffer.py +0 -0
  45. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/misc/understanding_idevice_protocol_layers.md +0 -0
  46. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/misc/usbmux_sniff.sh +0 -0
  47. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/__init__.py +0 -0
  48. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/ca.py +0 -0
  49. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/__init__.py +0 -0
  50. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/activation.py +0 -0
  51. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/afc.py +0 -0
  52. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/amfi.py +0 -0
  53. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/apps.py +0 -0
  54. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/backup.py +0 -0
  55. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/cli_common.py +0 -0
  56. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/companion_proxy.py +0 -0
  57. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/completions.py +0 -0
  58. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/crash.py +0 -0
  59. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/developer.py +0 -0
  60. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/diagnostics.py +0 -0
  61. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/mounter.py +0 -0
  62. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/notification.py +0 -0
  63. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/pcap.py +0 -0
  64. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/power_assertion.py +0 -0
  65. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/processes.py +0 -0
  66. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/profile.py +0 -0
  67. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/provision.py +0 -0
  68. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/restore.py +0 -0
  69. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/springboard.py +0 -0
  70. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/syslog.py +0 -0
  71. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/usbmux.py +0 -0
  72. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/version.py +0 -0
  73. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/cli/webinspector.py +0 -0
  74. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/common.py +0 -0
  75. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/exceptions.py +0 -0
  76. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/irecv.py +0 -0
  77. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/irecv_devices.py +0 -0
  78. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/lockdown_service_provider.py +0 -0
  79. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/osu/__init__.py +0 -0
  80. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/osu/os_utils.py +0 -0
  81. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/osu/posix_util.py +0 -0
  82. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/osu/win_util.py +0 -0
  83. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/pair_records.py +0 -0
  84. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/__init__.py +0 -0
  85. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/common.py +0 -0
  86. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/core_device/__init__.py +0 -0
  87. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/core_device/app_service.py +0 -0
  88. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/core_device/core_device_service.py +0 -0
  89. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/core_device/device_info.py +0 -0
  90. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/core_device/diagnostics_service.py +0 -0
  91. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/core_device/file_service.py +0 -0
  92. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/module_imports.py +0 -0
  93. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/remote_service.py +0 -0
  94. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/remote_service_discovery.py +0 -0
  95. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/remotexpc.py +0 -0
  96. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/remote/xpc_message.py +0 -0
  97. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/__init__.py +0 -0
  98. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/dsc_uuid_map.json +0 -0
  99. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/dsc_uuid_map.py +0 -0
  100. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/firmware_notifications.py +0 -0
  101. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/notifications.txt +0 -0
  102. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/webinspector/element_attribute.js +0 -0
  103. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/webinspector/element_clear.js +0 -0
  104. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/webinspector/enter_fullscreen.js +0 -0
  105. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/webinspector/find_nodes.js +0 -0
  106. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/webinspector/focus.js +0 -0
  107. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/webinspector/get_attribute.js +0 -0
  108. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/webinspector/is_displayed.js +0 -0
  109. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/webinspector/is_editable.js +0 -0
  110. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/resources/webinspector/is_enabled.js +0 -0
  111. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/__init__.py +0 -0
  112. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/asr.py +0 -0
  113. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/base_restore.py +0 -0
  114. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/consts.py +0 -0
  115. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/device.py +0 -0
  116. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/fdr.py +0 -0
  117. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/ftab.py +0 -0
  118. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/img4.py +0 -0
  119. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/mbn.py +0 -0
  120. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/recovery.py +0 -0
  121. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/restore.py +0 -0
  122. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/restore_options.py +0 -0
  123. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/restored_client.py +0 -0
  124. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/restore/tss.py +0 -0
  125. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/service_connection.py +0 -0
  126. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/__init__.py +0 -0
  127. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/accessibilityaudit.py +0 -0
  128. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/afc.py +0 -0
  129. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/amfi.py +0 -0
  130. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/companion.py +0 -0
  131. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/crash_reports.py +0 -0
  132. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/debugserver_applist.py +0 -0
  133. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/device_arbitration.py +0 -0
  134. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/device_link.py +0 -0
  135. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/diagnostics.py +0 -0
  136. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dtfetchsymbols.py +0 -0
  137. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/__init__.py +0 -0
  138. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +0 -0
  139. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +0 -0
  140. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/__init__.py +0 -0
  141. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +0 -0
  142. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/application_listing.py +0 -0
  143. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/condition_inducer.py +0 -0
  144. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +0 -0
  145. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/device_info.py +0 -0
  146. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/energy_monitor.py +0 -0
  147. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/graphics.py +0 -0
  148. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/location_simulation.py +0 -0
  149. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/location_simulation_base.py +0 -0
  150. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/network_monitor.py +0 -0
  151. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/notifications.py +0 -0
  152. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/process_control.py +0 -0
  153. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/screenshot.py +0 -0
  154. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/instruments/sysmontap.py +0 -0
  155. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/dvt/testmanaged/xcuitest.py +0 -0
  156. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/file_relay.py +0 -0
  157. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/heartbeat.py +0 -0
  158. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/house_arrest.py +0 -0
  159. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/installation_proxy.py +0 -0
  160. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/lockdown_service.py +0 -0
  161. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/misagent.py +0 -0
  162. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/mobile_activation.py +0 -0
  163. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/mobile_config.py +0 -0
  164. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/mobilebackup2.py +0 -0
  165. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/notification_proxy.py +0 -0
  166. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/os_trace.py +0 -0
  167. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/pcapd.py +0 -0
  168. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/power_assertion.py +0 -0
  169. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/preboard.py +0 -0
  170. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/remote_fetch_symbols.py +0 -0
  171. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/remote_server.py +0 -0
  172. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/restore_service.py +0 -0
  173. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/screenshot.py +0 -0
  174. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/simulate_location.py +0 -0
  175. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/springboard.py +0 -0
  176. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/syslog.py +0 -0
  177. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/__init__.py +0 -0
  178. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/alert.py +0 -0
  179. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/automation_session.py +0 -0
  180. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/cdp_screencast.py +0 -0
  181. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/cdp_server.py +0 -0
  182. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/cdp_target.py +0 -0
  183. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/driver.py +0 -0
  184. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/element.py +0 -0
  185. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/inspector_session.py +0 -0
  186. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/selenium_api.py +0 -0
  187. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/session_protocol.py +0 -0
  188. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/web_protocol/switch_to.py +0 -0
  189. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/services/webinspector.py +0 -0
  190. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/tcp_forwarder.py +0 -0
  191. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/tunneld/__init__.py +0 -0
  192. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3/tunneld/api.py +0 -0
  193. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3.egg-info/SOURCES.txt +0 -0
  194. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3.egg-info/dependency_links.txt +0 -0
  195. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3.egg-info/entry_points.txt +0 -0
  196. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pymobiledevice3.egg-info/top_level.txt +0 -0
  197. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pyproject.toml +0 -0
  198. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/pytest.ini +0 -0
  199. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/setup.cfg +0 -0
  200. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/__init__.py +0 -0
  201. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/cli/__init__.py +0 -0
  202. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/cli/test_cli.py +0 -0
  203. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/__init__.py +0 -0
  204. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/instruments/__init__.py +0 -0
  205. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/instruments/test_core_profile_session.py +0 -0
  206. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/instruments/test_dvt_secure_socket_proxy.py +0 -0
  207. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/instruments/test_fetch_symbols.py +0 -0
  208. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/instruments/test_location.py +0 -0
  209. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/instruments/test_screenshot.py +0 -0
  210. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_accessibility.py +0 -0
  211. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_afc.py +0 -0
  212. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_apps.py +0 -0
  213. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_backup2.py +0 -0
  214. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_bonjour.py +0 -0
  215. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_crash_reports.py +0 -0
  216. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_list_devices.py +0 -0
  217. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_lockdown.py +0 -0
  218. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_pcapd.py +0 -0
  219. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_springboard_services_relay.py +0 -0
  220. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_start_tunnel.py +0 -0
  221. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_syslog_relay.py +0 -0
  222. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_tcp_forwarder.py +0 -0
  223. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_web_protocol/__init__.py +0 -0
  224. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_web_protocol/common.py +0 -0
  225. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_web_protocol/conftest.py +0 -0
  226. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_web_protocol/test_driver.py +0 -0
  227. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_web_protocol/test_element.py +0 -0
  228. {pymobiledevice3-4.27.6 → pymobiledevice3-5.0.0}/tests/services/test_webinspector.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymobiledevice3
3
- Version: 4.27.6
3
+ Version: 5.0.0
4
4
  Summary: Pure python3 implementation for working with iDevices (iPhone, etc...)
5
5
  Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
6
6
  Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
@@ -47,7 +47,6 @@ Requires-Dist: nest_asyncio>=1.5.5
47
47
  Requires-Dist: Pillow
48
48
  Requires-Dist: inquirer3>=0.6.0
49
49
  Requires-Dist: ipsw_parser>=1.3.4
50
- Requires-Dist: zeroconf>=0.132.2
51
50
  Requires-Dist: ifaddr
52
51
  Requires-Dist: hyperframe
53
52
  Requires-Dist: srptools
@@ -27,7 +27,6 @@ coloredlogs.install(level=logging.INFO)
27
27
 
28
28
  logging.getLogger('quic').disabled = True
29
29
  logging.getLogger('asyncio').disabled = True
30
- logging.getLogger('zeroconf').disabled = True
31
30
  logging.getLogger('parso.cache').disabled = True
32
31
  logging.getLogger('parso.cache.pickle').disabled = True
33
32
  logging.getLogger('parso.python.diff').disabled = True
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '4.27.6'
32
- __version_tuple__ = version_tuple = (4, 27, 6)
31
+ __version__ = version = '5.0.0'
32
+ __version_tuple__ = version_tuple = (5, 0, 0)
33
33
 
34
- __commit_id__ = commit_id = 'gb568fdc20'
34
+ __commit_id__ = commit_id = 'ga2babc5a5'
@@ -0,0 +1,402 @@
1
+ # Async, dependency-light mDNS browser returning dataclasses with per-address interface names.
2
+ # Works for any DNS-SD type, e.g. "_remoted._tcp.local."
3
+ # - Uses ifaddr (optional) to map IPs -> local interfaces; otherwise iface will be None.
4
+
5
+ import asyncio
6
+ import ipaddress
7
+ import socket
8
+ import struct
9
+ import sys
10
+ from collections import defaultdict
11
+ from dataclasses import dataclass, field
12
+ from typing import Dict, List, Optional, Set, Tuple
13
+
14
+ import ifaddr # pip install ifaddr
15
+
16
+ from pymobiledevice3.osu.os_utils import get_os_utils
17
+
18
+ REMOTEPAIRING_SERVICE_NAME = '_remotepairing._tcp.local.'
19
+ REMOTEPAIRING_MANUAL_PAIRING_SERVICE_NAME = '_remotepairing-manual-pairing._tcp.local.'
20
+ MOBDEV2_SERVICE_NAME = '_apple-mobdev2._tcp.local.'
21
+ REMOTED_SERVICE_NAME = '_remoted._tcp.local.'
22
+ OSUTILS = get_os_utils()
23
+ DEFAULT_BONJOUR_TIMEOUT = OSUTILS.bonjour_timeout
24
+
25
+ MDNS_PORT = 5353
26
+ MDNS_MCAST_V4 = "224.0.0.251"
27
+ MDNS_MCAST_V6 = "ff02::fb"
28
+
29
+ QTYPE_A = 1
30
+ QTYPE_PTR = 12
31
+ QTYPE_TXT = 16
32
+ QTYPE_AAAA = 28
33
+ QTYPE_SRV = 33
34
+
35
+ CLASS_IN = 0x0001
36
+ CLASS_QU = 0x8000 # unicast-response bit (we use multicast queries)
37
+
38
+
39
+ # ---------------- Dataclasses ----------------
40
+
41
+ # --- Dataclass decorator shim (adds slots only on 3.10+)
42
+ def dataclass_compat(*d_args, **d_kwargs):
43
+ if sys.version_info < (3, 10):
44
+ d_kwargs.pop("slots", None) # ignore on 3.9
45
+ return dataclass(*d_args, **d_kwargs)
46
+
47
+
48
+ @dataclass_compat(slots=True)
49
+ class Address:
50
+ ip: str
51
+ iface: Optional[str] # local interface name (e.g., "en0"), or None if unknown
52
+
53
+ @property
54
+ def full_ip(self) -> str:
55
+ if self.iface and self.ip.lower().startswith("fe80:"):
56
+ return f"{self.ip}%{self.iface}"
57
+ return self.ip
58
+
59
+
60
+ @dataclass_compat(slots=True)
61
+ class ServiceInstance:
62
+ instance: str # "<Instance Name>._type._proto.local."
63
+ host: Optional[str] # "host.local" (without trailing dot), or None if unresolved
64
+ port: Optional[int] # SRV port
65
+ addresses: List[Address] = field(default_factory=list) # IPs with interface names
66
+ properties: Dict[str, str] = field(default_factory=dict) # TXT key/values
67
+
68
+
69
+ # ---------------- DNS helpers ----------------
70
+
71
+
72
+ def encode_name(name: str) -> bytes:
73
+ name = name.rstrip(".")
74
+ out = bytearray()
75
+ for label in name.split(".") if name else []:
76
+ b = label.encode("utf-8")
77
+ if len(b) > 63:
78
+ raise ValueError("label too long")
79
+ out.append(len(b))
80
+ out += b
81
+ out.append(0)
82
+ return bytes(out)
83
+
84
+
85
+ def decode_name(data: bytes, off: int) -> Tuple[str, int]:
86
+ labels = []
87
+ jumped = False
88
+ orig_end = off
89
+ for _ in range(128): # loop guard
90
+ if off >= len(data):
91
+ break
92
+ length = data[off]
93
+ if length == 0:
94
+ off += 1
95
+ break
96
+ if (length & 0xC0) == 0xC0:
97
+ if off + 1 >= len(data):
98
+ raise ValueError("truncated name pointer")
99
+ ptr = ((length & 0x3F) << 8) | data[off + 1]
100
+ if ptr >= len(data):
101
+ raise ValueError("bad name pointer")
102
+ if not jumped:
103
+ orig_end = off + 2
104
+ off = ptr
105
+ jumped = True
106
+ continue
107
+ off += 1
108
+ end = off + length
109
+ if end > len(data):
110
+ raise ValueError("truncated label")
111
+ labels.append(data[off:end].decode("utf-8", errors="replace"))
112
+ off = end
113
+ return ".".join(labels) + ".", (orig_end if jumped else off)
114
+
115
+
116
+ def build_query(name: str, qtype: int, unicast: bool = False) -> bytes:
117
+ hdr = struct.pack("!HHHHHH", 0, 0, 1, 0, 0, 0) # TXID=0, flags=0, 1 question
118
+ qclass = CLASS_IN | (CLASS_QU if unicast else 0)
119
+ return hdr + encode_name(name) + struct.pack("!HH", qtype, qclass)
120
+
121
+
122
+ def parse_rr(data: bytes, off: int):
123
+ name, off = decode_name(data, off)
124
+ if off + 10 > len(data):
125
+ raise ValueError("truncated RR header")
126
+ rtype, rclass, ttl, rdlen = struct.unpack("!HHIH", data[off: off + 10])
127
+ off += 10
128
+ rdata = data[off: off + rdlen]
129
+ off += rdlen
130
+
131
+ rr = {"name": name, "type": rtype, "class": rclass & 0x7FFF, "ttl": ttl}
132
+ if rtype == QTYPE_PTR:
133
+ target, _ = decode_name(data, off - rdlen)
134
+ rr["ptrdname"] = target
135
+ elif rtype == QTYPE_SRV and rdlen >= 6:
136
+ priority, weight, port = struct.unpack("!HHH", rdata[:6])
137
+ target, _ = decode_name(data, off - rdlen + 6)
138
+ rr.update(
139
+ {"priority": priority, "weight": weight, "port": port, "target": target}
140
+ )
141
+ elif rtype == QTYPE_TXT:
142
+ kv = {}
143
+ i = 0
144
+ while i < rdlen:
145
+ b = rdata[i]
146
+ i += 1
147
+ seg = rdata[i: i + b]
148
+ i += b
149
+ if not seg:
150
+ continue
151
+ if b"=" in seg:
152
+ k, v = seg.split(b"=", 1)
153
+ kv[k.decode()] = v.decode(errors="replace")
154
+ else:
155
+ kv[seg.decode()] = ""
156
+ rr["txt"] = kv
157
+ elif rtype == QTYPE_A and rdlen == 4:
158
+ rr["address"] = socket.inet_ntop(socket.AF_INET, rdata)
159
+ elif rtype == QTYPE_AAAA and rdlen == 16:
160
+ rr["address"] = socket.inet_ntop(socket.AF_INET6, rdata)
161
+ else:
162
+ rr["raw"] = rdata
163
+ return rr, off
164
+
165
+
166
+ def parse_mdns_message(data: bytes):
167
+ if len(data) < 12:
168
+ return []
169
+ _, _, qd, an, ns, ar = struct.unpack("!HHHHHH", data[:12])
170
+ off = 12
171
+ for _ in range(qd):
172
+ _, off = decode_name(data, off)
173
+ off += 4
174
+ rrs = []
175
+ for _ in range(an + ns + ar):
176
+ rr, off = parse_rr(data, off)
177
+ rrs.append(rr)
178
+ return rrs
179
+
180
+
181
+ # ---------------- Interface mapping helpers ----------------
182
+
183
+
184
+ class _Adapters:
185
+ def __init__(self):
186
+ self.adapters = ifaddr.get_adapters() if ifaddr is not None else []
187
+
188
+ def pick_iface_for_ip(
189
+ self, ip_str: str, family: int, v6_scopeid: Optional[int]
190
+ ) -> Optional[str]:
191
+ # Prefer scope id for IPv6 link-local
192
+ if family == socket.AF_INET6 and ip_str.lower().startswith("fe80:"):
193
+ if v6_scopeid:
194
+ try:
195
+ return socket.if_indextoname(v6_scopeid)
196
+ except OSError:
197
+ pass
198
+
199
+ # Otherwise, try to match destination ip to local subnet via ifaddr
200
+ if not self.adapters:
201
+ return None
202
+ ip = ipaddress.ip_address(ip_str)
203
+ best = (None, -1) # (name, prefix_len)
204
+ for ad in self.adapters:
205
+ for ipn in ad.ips:
206
+ if isinstance(ipn.ip, str):
207
+ # IPv4
208
+ fam = socket.AF_INET
209
+ ipn_ip = ipn.ip
210
+ else:
211
+ # IPv6
212
+ fam = socket.AF_INET6
213
+ ipn_ip = ipn.ip[0]
214
+ if fam != family:
215
+ continue
216
+ net = ipaddress.ip_network(
217
+ f"{ipn_ip}/{ipn.network_prefix}", strict=False
218
+ )
219
+ if ip in net and ipn.network_prefix > best[1]:
220
+ best = (ad.nice_name or ad.name, ipn.network_prefix)
221
+ return best[0]
222
+
223
+
224
+ # ---------------- async sockets ----------------
225
+
226
+
227
+ class _DatagramProtocol(asyncio.DatagramProtocol):
228
+ def __init__(self, queue: asyncio.Queue):
229
+ self.queue = queue
230
+
231
+ def datagram_received(self, data, addr):
232
+ # addr: IPv4 -> (host, port); IPv6 -> (host, port, flowinfo, scopeid)
233
+ self.queue.put_nowait((data, addr))
234
+
235
+
236
+ async def _bind_ipv4(queue: asyncio.Queue):
237
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
238
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
239
+ if hasattr(socket, "SO_REUSEPORT"):
240
+ try:
241
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
242
+ except OSError:
243
+ pass
244
+ s.bind(("0.0.0.0", MDNS_PORT))
245
+ try:
246
+ mreq = struct.pack(
247
+ "=4s4s", socket.inet_aton(MDNS_MCAST_V4), socket.inet_aton("0.0.0.0")
248
+ )
249
+ s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
250
+ except OSError:
251
+ pass
252
+ transport, _ = await asyncio.get_running_loop().create_datagram_endpoint(
253
+ lambda: _DatagramProtocol(queue), sock=s
254
+ )
255
+ return transport, s
256
+
257
+
258
+ async def _bind_ipv6_all_ifaces(queue: asyncio.Queue):
259
+ s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
260
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
261
+ if hasattr(socket, "SO_REUSEPORT"):
262
+ try:
263
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
264
+ except OSError:
265
+ pass
266
+ s.bind(("::", MDNS_PORT))
267
+ grp = socket.inet_pton(socket.AF_INET6, MDNS_MCAST_V6)
268
+ for ifindex, _ in socket.if_nameindex():
269
+ mreq6 = grp + struct.pack("@I", ifindex)
270
+ try:
271
+ s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq6)
272
+ except OSError:
273
+ continue
274
+ transport, _ = await asyncio.get_running_loop().create_datagram_endpoint(
275
+ lambda: _DatagramProtocol(queue), sock=s
276
+ )
277
+ return transport, s
278
+
279
+
280
+ async def _open_mdns_sockets():
281
+ queue = asyncio.Queue()
282
+ transports: List[Tuple[asyncio.BaseTransport, socket.socket]] = []
283
+ t4, s4 = await _bind_ipv4(queue)
284
+ transports.append((t4, s4))
285
+ t6, s6 = await _bind_ipv6_all_ifaces(queue)
286
+ transports.append((t6, s6))
287
+ if not transports:
288
+ raise RuntimeError("Failed to open mDNS sockets (UDP/5353)")
289
+ return transports, queue
290
+
291
+
292
+ async def _send_query_all(transports, pkt: bytes):
293
+ for transport, sock in transports:
294
+ if sock.family == socket.AF_INET:
295
+ transport.sendto(pkt, (MDNS_MCAST_V4, MDNS_PORT))
296
+ else:
297
+ # Send once per iface index for better reachability
298
+ for ifindex, _ in socket.if_nameindex():
299
+ transport.sendto(pkt, (MDNS_MCAST_V6, MDNS_PORT, 0, ifindex))
300
+
301
+
302
+ # ---------------- Public API ----------------
303
+
304
+
305
+ async def browse_service(
306
+ service_type: str, timeout: float = 4.0
307
+ ) -> List[ServiceInstance]:
308
+ """
309
+ Discover a DNS-SD/mDNS service type (e.g. "_remoted._tcp.local.") on the local network.
310
+
311
+ Returns: List[ServiceInstance] with Address(ip, iface) entries.
312
+ """
313
+ if not service_type.endswith("."):
314
+ service_type += "."
315
+
316
+ transports, queue = await _open_mdns_sockets()
317
+ adapters = _Adapters()
318
+
319
+ ptr_targets: Set[str] = set()
320
+ srv_map: Dict[str, Dict] = {}
321
+ txt_map: Dict[str, Dict] = {}
322
+ # host -> list[(ip, iface)]
323
+ host_addrs: Dict[str, List[Address]] = defaultdict(list)
324
+
325
+ def _record_addr(rr_name: str, ip_str: str, pkt_addr):
326
+ # Determine family and possible scopeid from the packet that delivered this RR
327
+ family = socket.AF_INET6 if ":" in ip_str else socket.AF_INET
328
+ scopeid = None
329
+ if isinstance(pkt_addr, tuple) and len(pkt_addr) == 4: # IPv6 remote tuple
330
+ scopeid = pkt_addr[3]
331
+ iface = adapters.pick_iface_for_ip(ip_str, family, scopeid)
332
+ # avoid duplicates for the same host/ip
333
+ existing = host_addrs[rr_name]
334
+ if not any(a.ip == ip_str for a in existing):
335
+ existing.append(Address(ip=ip_str, iface=iface))
336
+
337
+ try:
338
+ await _send_query_all(
339
+ transports, build_query(service_type, QTYPE_PTR, unicast=False)
340
+ )
341
+ loop = asyncio.get_running_loop()
342
+ end = loop.time() + timeout
343
+ while loop.time() < end:
344
+ try:
345
+ data, pkt_addr = await asyncio.wait_for(
346
+ queue.get(), timeout=end - loop.time()
347
+ )
348
+ except asyncio.TimeoutError:
349
+ break
350
+ for rr in parse_mdns_message(data):
351
+ t = rr.get("type")
352
+ if t == QTYPE_PTR and rr.get("name") == service_type:
353
+ ptr_targets.add(rr.get("ptrdname"))
354
+ elif t == QTYPE_SRV:
355
+ srv_map[rr["name"]] = {
356
+ "target": rr.get("target"),
357
+ "port": rr.get("port"),
358
+ }
359
+ elif t == QTYPE_TXT:
360
+ txt_map[rr["name"]] = rr.get("txt", {})
361
+ elif t == QTYPE_A and rr.get("address"):
362
+ _record_addr(rr["name"], rr["address"], pkt_addr)
363
+ elif t == QTYPE_AAAA and rr.get("address"):
364
+ _record_addr(rr["name"], rr["address"], pkt_addr)
365
+ finally:
366
+ for transport, _ in transports:
367
+ transport.close()
368
+
369
+ # Assemble dataclasses
370
+ results: List[ServiceInstance] = []
371
+ for inst in sorted(ptr_targets):
372
+ srv = srv_map.get(inst, {})
373
+ target = srv.get("target")
374
+ host = (target[:-1] if target and target.endswith(".") else target) or None
375
+ addrs = host_addrs.get(target, []) if target else []
376
+ props = txt_map.get(inst, {})
377
+ results.append(
378
+ ServiceInstance(
379
+ instance=inst,
380
+ host=host,
381
+ port=srv.get("port"),
382
+ addresses=addrs,
383
+ properties=props,
384
+ )
385
+ )
386
+ return results
387
+
388
+
389
+ async def browse_remoted(timeout: float = DEFAULT_BONJOUR_TIMEOUT) -> list[ServiceInstance]:
390
+ return await browse_service(REMOTED_SERVICE_NAME, timeout=timeout)
391
+
392
+
393
+ async def browse_mobdev2(timeout: float = DEFAULT_BONJOUR_TIMEOUT) -> list[ServiceInstance]:
394
+ return await browse_service(MOBDEV2_SERVICE_NAME, timeout=timeout)
395
+
396
+
397
+ async def browse_remotepairing(timeout: float = DEFAULT_BONJOUR_TIMEOUT) -> list[ServiceInstance]:
398
+ return await browse_service(REMOTEPAIRING_SERVICE_NAME, timeout=timeout)
399
+
400
+
401
+ async def browse_remotepairing_manual_pairing(timeout: float = DEFAULT_BONJOUR_TIMEOUT) -> list[ServiceInstance]:
402
+ return await browse_service(REMOTEPAIRING_MANUAL_PAIRING_SERVICE_NAME, timeout=timeout)
@@ -41,8 +41,8 @@ def cli_mobdev2(timeout: float, pair_records: Optional[str]) -> None:
41
41
  async def cli_remotepairing_task(timeout: float) -> None:
42
42
  output = []
43
43
  for answer in await browse_remotepairing(timeout=timeout):
44
- for ip in answer.ips:
45
- output.append({'hostname': ip, 'port': answer.port})
44
+ for address in answer.addresses:
45
+ output.append({'hostname': address.full_ip, 'port': answer.port})
46
46
  print_json(output)
47
47
 
48
48
 
@@ -56,8 +56,8 @@ def cli_remotepairing(timeout: float) -> None:
56
56
  async def cli_remotepairing_manual_pairing_task(timeout: float) -> None:
57
57
  output = []
58
58
  for answer in await browse_remotepairing_manual_pairing(timeout=timeout):
59
- for ip in answer.ips:
60
- output.append({'hostname': ip, 'port': answer.port, 'name': answer.properties[b'name'].decode()})
59
+ for address in answer.addresses:
60
+ output.append({'hostname': address.full_ip, 'port': answer.port, 'name': answer.properties[b'name'].decode()})
61
61
  print_json(output)
62
62
 
63
63
 
@@ -161,6 +161,12 @@ def lockdown_wifi_connections(service_provider: LockdownClient, state):
161
161
  service_provider.enable_wifi_connections = state == 'on'
162
162
 
163
163
 
164
+ async def async_cli_start_tunnel(
165
+ service_provider: LockdownServiceProvider, script_mode: bool) -> None:
166
+ await tunnel_task(await CoreDeviceTunnelProxy.create(service_provider),
167
+ script_mode=script_mode, secrets=None, protocol=TunnelProtocol.TCP)
168
+
169
+
164
170
  @lockdown_group.command('start-tunnel', cls=Command)
165
171
  @click.option('--script-mode', is_flag=True,
166
172
  help='Show only HOST and port number to allow easy parsing from external shell scripts')
@@ -168,8 +174,7 @@ def lockdown_wifi_connections(service_provider: LockdownClient, state):
168
174
  def cli_start_tunnel(
169
175
  service_provider: LockdownServiceProvider, script_mode: bool) -> None:
170
176
  """ start tunnel """
171
- service = CoreDeviceTunnelProxy(service_provider)
172
- asyncio.run(tunnel_task(service, script_mode=script_mode, secrets=None, protocol=TunnelProtocol.TCP), debug=True)
177
+ asyncio.run(async_cli_start_tunnel(service_provider, script_mode), debug=True)
173
178
 
174
179
 
175
180
  @lockdown_group.command('assistive-touch', cls=Command)
@@ -220,9 +220,10 @@ async def start_remote_pair_task(device_name: str) -> None:
220
220
  if device_name is not None and current_device_name != device_name:
221
221
  continue
222
222
 
223
- for ip in answer.ips:
224
- devices.append(RemotePairingManualPairingDevice(ip=ip, port=answer.port, device_name=current_device_name,
225
- identifier=answer.properties[b'identifier'].decode()))
223
+ for address in answer.addresses:
224
+ devices.append(
225
+ RemotePairingManualPairingDevice(ip=address.full_ip, port=answer.port, device_name=current_device_name,
226
+ identifier=answer.properties[b'identifier'].decode()))
226
227
 
227
228
  if len(devices) > 0:
228
229
  device = prompt_device_list(devices)
@@ -848,7 +848,7 @@ def create_using_remote(service: ServiceConnection, identifier: str = None, labe
848
848
 
849
849
  async def get_mobdev2_lockdowns(
850
850
  udid: Optional[str] = None, pair_records: Optional[Path] = None, only_paired: bool = False,
851
- timeout: float = DEFAULT_BONJOUR_TIMEOUT, ips: Optional[list[str]] = None) \
851
+ timeout: float = DEFAULT_BONJOUR_TIMEOUT) \
852
852
  -> AsyncIterable[tuple[str, TcpLockdownClient]]:
853
853
  records = {}
854
854
  if pair_records is None:
@@ -863,26 +863,21 @@ async def get_mobdev2_lockdowns(
863
863
  record = plistlib.loads(file.read_bytes())
864
864
  records[record['WiFiMACAddress']] = record
865
865
 
866
- iterated_ips = set()
867
- for answer in await browse_mobdev2(timeout=timeout, ips=ips):
868
- if '@' not in answer.name:
866
+ for answer in await browse_mobdev2(timeout=timeout):
867
+ if '@' not in answer.instance:
869
868
  continue
870
- wifi_mac_address = answer.name.split('@', 1)[0]
869
+ wifi_mac_address = answer.instance.split('@', 1)[0]
871
870
  record = records.get(wifi_mac_address)
872
871
 
873
872
  if only_paired and record is None:
874
873
  continue
875
874
 
876
- for ip in answer.ips:
877
- if ip in iterated_ips:
878
- # skip ips we already iterated over, possibly from previous queries
879
- continue
880
- iterated_ips.add(ip)
875
+ for address in answer.addresses:
881
876
  try:
882
- lockdown = create_using_tcp(hostname=ip, autopair=False, pair_record=record)
877
+ lockdown = create_using_tcp(hostname=address.full_ip, autopair=False, pair_record=record)
883
878
  except Exception:
884
879
  continue
885
880
  if only_paired and not lockdown.paired:
886
881
  lockdown.close()
887
882
  continue
888
- yield ip, lockdown
883
+ yield address.full_ip, lockdown
@@ -190,7 +190,7 @@ class RemotePairingTunnel(ABC):
190
190
  self._tun_read_task = asyncio.create_task(self.tun_read_task(), name=f'tun-read-{address}')
191
191
 
192
192
  async def stop_tunnel(self) -> None:
193
- self._logger.debug('stopping tunnel')
193
+ self._logger.debug(f'[{asyncio.current_task().get_name()}] stopping tunnel')
194
194
  self._tun_read_task.cancel()
195
195
  with suppress(CancelledError):
196
196
  await self._tun_read_task
@@ -223,6 +223,9 @@ class RemotePairingQuicTunnel(RemotePairingTunnel, QuicConnectionProtocol):
223
223
  self._quic.send_datagram_frame(packet)
224
224
  self.transmit()
225
225
 
226
+ # Allow other tasks to run
227
+ await asyncio.sleep(0)
228
+
226
229
  async def request_tunnel_establish(self) -> dict:
227
230
  stream_id = self._quic.get_next_available_stream_id()
228
231
  # pad the data with random data to force the MTU size correctly
@@ -939,17 +942,21 @@ class RemotePairingManualPairingService(RemotePairingTunnelService):
939
942
  class CoreDeviceTunnelProxy(StartTcpTunnel):
940
943
  SERVICE_NAME = 'com.apple.internal.devicecompute.CoreDeviceProxy'
941
944
 
942
- def __init__(self, lockdown: LockdownServiceProvider) -> None:
943
- self._lockdown = lockdown
944
- self._service: Optional[ServiceConnection] = None
945
+ @classmethod
946
+ async def create(cls, lockdown: LockdownServiceProvider) -> 'CoreDeviceTunnelProxy':
947
+ return cls(await lockdown.aio_start_lockdown_service(cls.SERVICE_NAME), lockdown.udid)
948
+
949
+ def __init__(self, service: ServiceConnection, remote_identifier: str) -> None:
950
+ self._service: ServiceConnection = service
951
+ self._remote_identifier: str = remote_identifier
945
952
 
946
953
  @property
947
954
  def remote_identifier(self) -> str:
948
- return self._lockdown.udid
955
+ return self._remote_identifier
949
956
 
950
957
  @asynccontextmanager
951
958
  async def start_tcp_tunnel(self) -> AsyncGenerator['TunnelResult', None]:
952
- self._service = await self._lockdown.aio_start_lockdown_service(self.SERVICE_NAME)
959
+ assert self._service is not None, 'service must be connected first'
953
960
  tunnel = RemotePairingTcpTunnel(self._service.reader, self._service.writer)
954
961
  handshake_response = await tunnel.request_tunnel_establish()
955
962
  tunnel.start_tunnel(handshake_response['clientParameters']['address'],
@@ -1078,13 +1085,14 @@ async def get_remote_pairing_tunnel_services(
1078
1085
  udid: Optional[str] = None) -> list[RemotePairingTunnelService]:
1079
1086
  result = []
1080
1087
  for answer in await browse_remotepairing(timeout=bonjour_timeout):
1081
- for ip in answer.ips:
1088
+ for address in answer.addresses:
1082
1089
  for identifier in iter_remote_paired_identifiers():
1083
1090
  if udid is not None and identifier != udid:
1084
1091
  continue
1085
1092
  conn = None
1086
1093
  try:
1087
- conn = await create_core_device_tunnel_service_using_remotepairing(identifier, ip, answer.port)
1094
+ conn = await create_core_device_tunnel_service_using_remotepairing(
1095
+ identifier, address.full_ip, answer.port)
1088
1096
  result.append(conn)
1089
1097
  break
1090
1098
  except ConnectionAbortedError:
@@ -17,8 +17,8 @@ async def get_rsds(bonjour_timeout: float = DEFAULT_BONJOUR_TIMEOUT, udid: Optio
17
17
  result = []
18
18
  with stop_remoted():
19
19
  for answer in await browse_remoted(timeout=bonjour_timeout):
20
- for ip in answer.ips:
21
- rsd = RemoteServiceDiscoveryService((ip, RSD_PORT))
20
+ for address in answer.addresses:
21
+ rsd = RemoteServiceDiscoveryService((address.full_ip, RSD_PORT))
22
22
  try:
23
23
  await rsd.connect()
24
24
  except ConnectionRefusedError:
@@ -18,7 +18,7 @@ from pymobiledevice3.services.lockdown_service import LockdownService
18
18
 
19
19
  logger = logging.getLogger(__name__)
20
20
 
21
- LATEST_DDI_BUILD_ID = '17A324'
21
+ LATEST_DDI_BUILD_ID = '17B5045g'
22
22
 
23
23
 
24
24
  class MobileImageMounterService(LockdownService):