From efb3d0ec8b38918860ceb5f3249311c0f762d97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80?= <78488229+viktor138irk@users.noreply.github.com> Date: Wed, 6 May 2026 22:09:22 +0900 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BE=D0=BF=D1=80=D0=B5?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20IP=20VM=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20port=20forwarding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/network_core.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/web/network_core.py b/web/network_core.py index 606d4a8..e806bc3 100644 --- a/web/network_core.py +++ b/web/network_core.py @@ -143,9 +143,47 @@ def save_port_forwards(items: list[dict[str, Any]]) -> None: PORT_FORWARDS_FILE.write_text(json.dumps(items, ensure_ascii=False, indent=2)) +def vm_mac_addresses(vm_name: str) -> list[str]: + result = run_cmd(['virsh', 'domiflist', vm_name], timeout=8) + if not result['ok']: + return [] + macs: list[str] = [] + for line in result['stdout'].splitlines(): + match = re.search(r'([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}', line) + if match: + macs.append(match.group(0).lower()) + return macs + + +def resolve_vm_ip(vm_name: str) -> str | None: + result = run_cmd(['virsh', 'domifaddr', vm_name], timeout=8) + if result['ok']: + match = re.search(r'\b(192\.168\.100\.\d+|\d+\.\d+\.\d+\.\d+)/\d+', result['stdout']) + if match: + return match.group(1) + + leases = run_cmd(['virsh', 'net-dhcp-leases', NETWORK_NAME], timeout=8) + if not leases['ok']: + return None + macs = set(vm_mac_addresses(vm_name)) + for line in leases['stdout'].splitlines(): + low = line.lower() + if macs and not any(mac in low for mac in macs): + continue + match = re.search(r'\b(192\.168\.100\.\d+|\d+\.\d+\.\d+\.\d+)/\d+', line) + if match: + return match.group(1) + return None + + def add_port_forward(vm_name: str, guest_ip: str, external_port: int, guest_port: int, protocol: str, note: str = '') -> dict[str, Any]: if not vm_name or not re.fullmatch(r'[a-zA-Z0-9][a-zA-Z0-9_.-]{1,62}', vm_name): raise NetworkError('Некорректное имя VM') + if guest_ip == 'auto': + resolved_ip = resolve_vm_ip(vm_name) + if not resolved_ip: + raise NetworkError('Не удалось автоматически определить IP VM. Запусти VM, дождись DHCP, установи qemu-guest-agent или проверь DHCP leases на странице сети.') + guest_ip = resolved_ip if not valid_ip(guest_ip): raise NetworkError('Некорректный внутренний IP VM') if not valid_port(external_port) or not valid_port(guest_port):