Skip to content

Commit e842dca

Browse files
author
neil
committed
security
1 parent b047bd7 commit e842dca

File tree

1 file changed

+40
-19
lines changed

1 file changed

+40
-19
lines changed

anyvm.py

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,7 +1644,7 @@ def fatal(msg):
16441644
class 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

19781979
def 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 = """
46674688
StrictHostKeyChecking=no
46684689
46694690
Host 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

Comments
 (0)