1
1
import asyncio
2
2
import dataclasses
3
3
import logging
4
+ import platform
4
5
import sys
5
6
import tempfile
6
7
from functools import partial
@@ -113,30 +114,38 @@ def rsd_info(service_provider: RemoteServiceDiscoveryService):
113
114
114
115
115
116
async def tunnel_task (
116
- service , secrets : Optional [TextIO ] = None , script_mode : bool = False ,
117
+ service , secrets : Optional [TextIO ] = None , script_mode : bool = False , userspace_tun_host : Optional [ str ] = None ,
117
118
max_idle_timeout : float = MAX_IDLE_TIMEOUT , protocol : TunnelProtocol = TunnelProtocol .DEFAULT ) -> None :
118
119
async with start_tunnel (
119
- service , secrets = secrets , max_idle_timeout = max_idle_timeout , protocol = protocol ) as tunnel_result :
120
+ service , secrets = secrets , max_idle_timeout = max_idle_timeout ,
121
+ protocol = protocol , userspace_tun_host = userspace_tun_host ) as tunnel_result :
120
122
logger .info ('tunnel created' )
123
+ use_userspace_tun = userspace_tun_host is not None
121
124
if script_mode :
122
- print (f'{ tunnel_result .address } { tunnel_result .port } ' )
125
+ if userspace_tun_host :
126
+ print (f'{ tunnel_result .address } { tunnel_result .port } { tunnel_result .interface } ' )
127
+ else :
128
+ print (f'{ tunnel_result .address } { tunnel_result .port } ' )
123
129
else :
130
+ interface_name = "Userspace TUN" if use_userspace_tun else tunnel_result .interface
131
+ userspace_param = f"--userspace-tun { tunnel_result .interface } " if use_userspace_tun else ""
124
132
if user_requested_colored_output ():
125
133
if secrets is not None :
126
134
print (click .style ('Secrets: ' , bold = True , fg = 'magenta' ) +
127
135
click .style (secrets .name , bold = True , fg = 'white' ))
128
136
print (click .style ('Identifier: ' , bold = True , fg = 'yellow' ) +
129
137
click .style (service .remote_identifier , bold = True , fg = 'white' ))
130
138
print (click .style ('Interface: ' , bold = True , fg = 'yellow' ) +
131
- click .style (tunnel_result . interface , bold = True , fg = 'white' ))
139
+ click .style (interface_name , bold = True , fg = 'white' ))
132
140
print (click .style ('Protocol: ' , bold = True , fg = 'yellow' ) +
133
141
click .style (tunnel_result .protocol , bold = True , fg = 'white' ))
134
142
print (click .style ('RSD Address: ' , bold = True , fg = 'yellow' ) +
135
143
click .style (tunnel_result .address , bold = True , fg = 'white' ))
136
144
print (click .style ('RSD Port: ' , bold = True , fg = 'yellow' ) +
137
145
click .style (tunnel_result .port , bold = True , fg = 'white' ))
138
146
print (click .style ('Use the follow connection option:\n ' , bold = True , fg = 'yellow' ) +
139
- click .style (f'--rsd { tunnel_result .address } { tunnel_result .port } ' , bold = True , fg = 'cyan' ))
147
+ click .style (userspace_param + f'--rsd { tunnel_result .address } { tunnel_result .port } ' ,
148
+ bold = True , fg = 'cyan' ))
140
149
else :
141
150
if secrets is not None :
142
151
print (f'Secrets: { secrets .name } ' )
@@ -145,16 +154,17 @@ async def tunnel_task(
145
154
print (f'Protocol: { tunnel_result .protocol } ' )
146
155
print (f'RSD Address: { tunnel_result .address } ' )
147
156
print (f'RSD Port: { tunnel_result .port } ' )
148
- print (f 'Use the follow connection option:\n '
149
- f'--rsd { tunnel_result .address } { tunnel_result .port } ' )
157
+ print ('Use the follow connection option:\n ' +
158
+ userspace_param + f'--rsd { tunnel_result .address } { tunnel_result .port } ' )
150
159
sys .stdout .flush ()
151
160
await tunnel_result .client .wait_closed ()
152
161
logger .info ('tunnel was closed' )
153
162
154
163
155
164
async def start_tunnel_task (
156
165
connection_type : ConnectionType , secrets : TextIO , udid : Optional [str ] = None , script_mode : bool = False ,
157
- max_idle_timeout : float = MAX_IDLE_TIMEOUT , protocol : TunnelProtocol = TunnelProtocol .DEFAULT ) -> None :
166
+ max_idle_timeout : float = MAX_IDLE_TIMEOUT , protocol : TunnelProtocol = TunnelProtocol .DEFAULT ,
167
+ userspace_tun_host : Optional [str ] = None ) -> None :
158
168
if start_tunnel is None :
159
169
raise NotImplementedError ('failed to start the tunnel on your platform' )
160
170
get_tunnel_services = {
@@ -173,13 +183,14 @@ async def start_tunnel_task(
173
183
service = prompt_device_list (tunnel_services )
174
184
175
185
await tunnel_task (service , secrets = secrets , script_mode = script_mode , max_idle_timeout = max_idle_timeout ,
176
- protocol = protocol )
186
+ protocol = protocol , userspace_tun_host = userspace_tun_host )
177
187
178
188
179
189
@remote_cli .command ('start-tunnel' , cls = BaseCommand )
180
190
@click .option ('-t' , '--connection-type' , type = click .Choice ([e .value for e in ConnectionType ], case_sensitive = False ),
181
191
default = ConnectionType .USB .value )
182
192
@click .option ('--udid' , help = 'UDID for a specific device to look for' )
193
+ @click .option ('--userspace-tun-host' , help = 'Specify a host to listen on to enable userspace TUN' )
183
194
@click .option ('--secrets' , type = click .File ('wt' ), help = 'TLS keyfile for decrypting with Wireshark' )
184
195
@click .option ('--script-mode' , is_flag = True ,
185
196
help = 'Show only HOST and port number to allow easy parsing from external shell scripts' )
@@ -188,17 +199,18 @@ async def start_tunnel_task(
188
199
@click .option ('-p' , '--protocol' ,
189
200
type = click .Choice ([e .value for e in TunnelProtocol ], case_sensitive = False ),
190
201
default = TunnelProtocol .DEFAULT .value )
191
- @sudo_required
192
202
def cli_start_tunnel (
193
- connection_type : ConnectionType , udid : Optional [str ], secrets : TextIO , script_mode : bool ,
194
- max_idle_timeout : float , protocol : str ) -> None :
203
+ connection_type : ConnectionType , udid : Optional [str ], userspace_tun_host : Optional [ str ] ,
204
+ secrets : TextIO , script_mode : bool , max_idle_timeout : float , protocol : str ) -> None :
195
205
""" start tunnel """
196
206
if not verify_tunnel_imports ():
197
207
return
208
+ if userspace_tun_host is None or platform .system () == 'Darwin' :
209
+ sudo_required (lambda : None )()
198
210
asyncio .run (
199
211
start_tunnel_task (
200
212
ConnectionType (connection_type ), secrets , udid , script_mode , max_idle_timeout = max_idle_timeout ,
201
- protocol = TunnelProtocol (protocol )), debug = True )
213
+ protocol = TunnelProtocol (protocol ), userspace_tun_host = userspace_tun_host ), debug = True )
202
214
203
215
204
216
@dataclasses .dataclass
0 commit comments