@@ -1644,7 +1644,7 @@ def fatal(msg):
16441644class VNCWebProxy :
16451645 GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
16461646
1647- def __init__ (self , vnc_host , vnc_port , web_port , vm_info = "" , qemu_pid = None , audio_enabled = False , qmon_port = None , error_log_path = None , is_console_vnc = False ):
1647+ def __init__ (self , vnc_host , vnc_port , web_port , vm_info = "" , qemu_pid = None , audio_enabled = False , qmon_port = None , error_log_path = None , is_console_vnc = False , listen_addr = '127.0.0.1' ):
16481648 self .vnc_host = vnc_host
16491649 self .vnc_port = vnc_port
16501650 self .web_port = web_port
@@ -1654,6 +1654,7 @@ def __init__(self, vnc_host, vnc_port, web_port, vm_info="", qemu_pid=None, audi
16541654 self .qmon_port = qmon_port
16551655 self .error_log_path = error_log_path
16561656 self .is_console_vnc = is_console_vnc
1657+ self .listen_addr = listen_addr
16571658 self .clients = set ()
16581659 self .serial_buffer = collections .deque (maxlen = 1024 * 100 ) # 100KB binary buffer (optimized for refresh speed)
16591660 self .serial_writer = None
@@ -1958,21 +1959,21 @@ async def run(self):
19581959 if self .is_console_vnc :
19591960 asyncio .create_task (self .serial_worker ())
19601961
1961- server = await asyncio .start_server (self .handle_client , '0.0.0.0' , self .web_port )
1962+ server = await asyncio .start_server (self .handle_client , self . listen_addr , self .web_port )
19621963 asyncio .create_task (self .monitor_qemu ())
19631964 async with server :
19641965 await server .serve_forever ()
19651966
1966- def start_vnc_web_proxy (vnc_port , web_port , vm_info = "" , qemu_pid = None , audio_enabled = False , qmon_port = None , error_log_path = None , is_console_vnc = False ):
1967+ def start_vnc_web_proxy (vnc_port , web_port , vm_info = "" , qemu_pid = None , audio_enabled = False , qmon_port = None , error_log_path = None , is_console_vnc = False , listen_addr = '127.0.0.1' ):
19671968 if error_log_path :
19681969 try :
19691970 with open (error_log_path , 'a' ) as f :
19701971 t = time .time ()
19711972 ts = time .strftime ("%Y-%m-%d %H:%M:%S" , time .localtime (t )) + ".{:03d}" .format (int (t % 1 * 1000 ))
1972- f .write ("[{}] [VNCProxy] Proxy starting. VNC/Serial: {}, Web: {}, QEMU PID: {}, Monitor Port: {}, Console Mode: {}\n " .format (ts , vnc_port , web_port , qemu_pid , qmon_port , is_console_vnc ))
1973+ f .write ("[{}] [VNCProxy] Proxy starting. VNC/Serial: {}, Web: {}, QEMU PID: {}, Monitor Port: {}, Console Mode: {}, Listen: {} \n " .format (ts , vnc_port , web_port , qemu_pid , qmon_port , is_console_vnc , listen_addr ))
19731974 except :
19741975 pass
1975- proxy = VNCWebProxy ('127.0.0.1' , vnc_port , web_port , vm_info , qemu_pid , audio_enabled , qmon_port , error_log_path , is_console_vnc )
1976+ proxy = VNCWebProxy ('127.0.0.1' , vnc_port , web_port , vm_info , qemu_pid , audio_enabled , qmon_port , error_log_path , is_console_vnc , listen_addr = listen_addr )
19761977 asyncio .run (proxy .run ())
19771978
19781979def fatal (msg ):
@@ -2025,6 +2026,9 @@ def print_usage():
20252026 --res, --resolution Set initial screen resolution (e.g., 1280x800). Default: 1280x800.
20262027 --mon <port> QEMU monitor telnet port (localhost).
20272028 --public Listen on 0.0.0.0 for mapped ports instead of 127.0.0.1.
2029+ --public-vnc Listen on 0.0.0.0 for the VNC web interface instead of 127.0.0.1.
2030+ --public-ssh Listen on 0.0.0.0 for the SSH port instead of 127.0.0.1.
2031+ --accept-vm-ssh Authorize the VM's public key on the host (enables reverse SSH).
20282032 --whpx (Windows) Attempt to use WHPX acceleration instead of TCG.
20292033 --debug Enable verbose debug logging.
20302034 --detach, -d Run QEMU in background.
@@ -3038,7 +3042,8 @@ def main():
30383042 qmon_port = int (sys .argv [7 ]) if len (sys .argv ) > 7 and sys .argv [7 ].isdigit () else None
30393043 error_log_path = sys .argv [8 ] if len (sys .argv ) > 8 else None
30403044 is_console_vnc = sys .argv [9 ] == '1' if len (sys .argv ) > 9 else False
3041- start_vnc_web_proxy (vnc_port , web_port , vm_info , qemu_pid , audio_enabled , qmon_port , error_log_path , is_console_vnc )
3045+ listen_addr = sys .argv [10 ] if len (sys .argv ) > 10 else '127.0.0.1'
3046+ start_vnc_web_proxy (vnc_port , web_port , vm_info , qemu_pid , audio_enabled , qmon_port , error_log_path , is_console_vnc , listen_addr = listen_addr )
30423047 except Exception as e :
30433048 # If we have an error log path, try to write to it even if startup fails
30443049 try :
@@ -3085,7 +3090,10 @@ def main():
30853090 'vga' : "" ,
30863091 'resolution' : "1280x800" ,
30873092 'snapshot' : False ,
3088- 'synctime' : None
3093+ 'synctime' : None ,
3094+ 'public_vnc' : False ,
3095+ 'public_ssh' : False ,
3096+ 'accept_vm_ssh' : False
30893097 }
30903098
30913099 ssh_passthrough = []
@@ -3194,6 +3202,12 @@ def main():
31943202 config ['debug' ] = True
31953203 elif arg == "--public" :
31963204 config ['public' ] = True
3205+ elif arg == "--public-vnc" :
3206+ config ['public_vnc' ] = True
3207+ elif arg == "--public-ssh" :
3208+ config ['public_ssh' ] = True
3209+ elif arg == "--accept-vm-ssh" :
3210+ config ['accept_vm_ssh' ] = True
31973211 elif arg == "--whpx" :
31983212 config ['whpx' ] = True
31993213 elif arg == "--serial" :
@@ -3724,10 +3738,15 @@ def cmd_exists(cmd):
37243738 if not config ['sshport' ]:
37253739 fatal ("No free port" )
37263740
3741+ if config ['public' ] or config ['public_ssh' ]:
3742+ ssh_addr = ""
3743+ else :
3744+ ssh_addr = "127.0.0.1"
3745+
37273746 if config ['public' ]:
3728- addr = ""
3747+ p_addr = ""
37293748 else :
3730- addr = "127.0.0.1"
3749+ p_addr = "127.0.0.1"
37313750
37323751 # Ensure serial port is allocated for background logging and VNC console
37333752 if not config ['serialport' ]:
@@ -3848,18 +3867,18 @@ def cmd_exists(cmd):
38483867 netdev_args = "user,id=net0,net=192.168.122.0/24,dhcpstart=192.168.122.50"
38493868 if not config .get ('enable_ipv6' ):
38503869 netdev_args += ",ipv6=off"
3851- netdev_args += ",hostfwd=tcp:{}:{}-:22" .format (addr , config ['sshport' ])
3870+ netdev_args += ",hostfwd=tcp:{}:{}-:22" .format (ssh_addr , config ['sshport' ])
38523871
38533872 # Add custom port mappings
38543873 for p in config ['ports' ]:
38553874 parts = p .split (':' )
38563875 # Format: host:guest (tcp default), tcp:host:guest, udp:host:guest
38573876 if len (parts ) == 2 :
38583877 # host:guest -> tcp:addr:host-:guest
3859- netdev_args += ",hostfwd=tcp:{}:{}-:{}" .format (addr , parts [0 ], parts [1 ])
3878+ netdev_args += ",hostfwd=tcp:{}:{}-:{}" .format (p_addr , parts [0 ], parts [1 ])
38603879 elif len (parts ) == 3 :
38613880 # proto:host:guest -> proto:addr:host-:guest
3862- netdev_args += ",hostfwd={}:{}:{}-:{}" .format (parts [0 ], addr , parts [1 ], parts [2 ])
3881+ netdev_args += ",hostfwd={}:{}:{}-:{}" .format (parts [0 ], p_addr , parts [1 ], parts [2 ])
38633882
38643883 args_qemu = []
38653884 if serial_chardev_def :
@@ -4157,7 +4176,8 @@ def start_vnc_proxy_for_pid(qemu_pid):
41574176 '1' if is_audio_enabled else '0' ,
41584177 config ['qmon' ] if config ['qmon' ] else "" ,
41594178 os .path .join (output_dir , "{}.vncproxy.err" .format (vm_name )),
4160- '1' if is_vnc_console else '0'
4179+ '1' if is_vnc_console else '0' ,
4180+ '0.0.0.0' if (config ['public' ] or config ['public_vnc' ]) else '127.0.0.1'
41614181 ]
41624182 popen_kwargs = {}
41634183 if IS_WINDOWS :
@@ -4225,7 +4245,7 @@ def fail_with_output(reason):
42254245 else :
42264246 os .chmod (ssh_dir , 0o700 )
42274247
4228- if vmpub_file and os .path .exists (vmpub_file ):
4248+ if ( config . get ( 'sync' ) == 'sshfs' or config . get ( 'accept_vm_ssh' )) and vmpub_file and os .path .exists (vmpub_file ):
42294249 with open (vmpub_file , 'r' ) as f :
42304250 pub = f .read ()
42314251 with open (os .path .join (ssh_dir , "authorized_keys" ), 'a' ) as f :
@@ -4663,18 +4683,19 @@ def supports_ansi_color(stream):
46634683 debuglog (config ['debug' ], "Detected host SSH port {}" .format (config ['hostsshport' ]))
46644684 if config ['hostsshport' ]:
46654685 host_port_line = " Port {}\n " .format (config ['hostsshport' ])
4666- vm_ssh_config = """
4686+ if config .get ('sync' ) == 'sshfs' or config .get ('accept_vm_ssh' ):
4687+ vm_ssh_config = """
46674688StrictHostKeyChecking=no
46684689
46694690Host host
46704691 HostName 192.168.122.2
46714692{host_port} User {user}
46724693 ServerAliveInterval 1
46734694""" .format (host_port = host_port_line , user = current_user )
4674-
4675- p = subprocess .Popen (ssh_base_cmd + ["cat - > .ssh/config" ], stdin = subprocess .PIPE )
4676- p .communicate (input = vm_ssh_config .encode ('utf-8' ))
4677- p .wait ()
4695+
4696+ p = subprocess .Popen (ssh_base_cmd + ["cat - > .ssh/config" ], stdin = subprocess .PIPE )
4697+ p .communicate (input = vm_ssh_config .encode ('utf-8' ))
4698+ p .wait ()
46784699 # OmniOS DNS configuration
46794700 if config ['os' ] == 'omnios' :
46804701 p = subprocess .Popen (ssh_base_cmd + ["sh" ], stdin = subprocess .PIPE )
0 commit comments