-
Notifications
You must be signed in to change notification settings - Fork 1.7k
do-not-merge: virtionet port mapping POC #40145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/wsl-for-apps
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -101,7 +101,6 @@ HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int | |||||||||||||||||||||||||||
| return S_OK; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| int result = 0; | ||||||||||||||||||||||||||||
| const auto ipAddress = (addr.si_family == AF_INET) ? reinterpret_cast<const void*>(&addr.Ipv4.sin_addr) | ||||||||||||||||||||||||||||
| : reinterpret_cast<const void*>(&addr.Ipv6.sin6_addr); | ||||||||||||||||||||||||||||
| const bool loopback = INET_IS_ADDR_LOOPBACK(addr.si_family, ipAddress); | ||||||||||||||||||||||||||||
|
|
@@ -111,10 +110,12 @@ HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int | |||||||||||||||||||||||||||
| // Only intercepting 127.0.0.1; any other loopback address will remain on 'lo'. | ||||||||||||||||||||||||||||
| if (addr.Ipv4.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||||||
| return S_OK; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const auto guestPort = INETADDR_PORT(reinterpret_cast<const SOCKADDR*>(&addr)); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if (WI_IsFlagSet(m_flags, VirtioNetworkingFlags::LocalhostRelay) && (unspecified || loopback)) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| SOCKADDR_INET localAddr = addr; | ||||||||||||||||||||||||||||
|
|
@@ -130,57 +131,102 @@ HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int | |||||||||||||||||||||||||||
| localAddr.Ipv6.sin6_port = addr.Ipv6.sin6_port; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| result = ModifyOpenPorts(c_loopbackDeviceName, localAddr, protocol, allocate); | ||||||||||||||||||||||||||||
| LOG_HR_IF_MSG( | ||||||||||||||||||||||||||||
| E_FAIL, result != S_OK, "Failure adding localhost relay port %d", INETADDR_PORT(reinterpret_cast<const SOCKADDR*>(&localAddr))); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| try | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| const auto addrStr = wsl::windows::common::string::SockAddrInetToString(localAddr); | ||||||||||||||||||||||||||||
| ModifyOpenPorts(c_loopbackDeviceName, addrStr.c_str(), guestPort, guestPort, protocol, allocate); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| catch (...) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| LOG_CAUGHT_EXCEPTION_MSG("Failure adding localhost relay port %d", guestPort); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if (!loopback) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| const int localResult = ModifyOpenPorts(c_eth0DeviceName, addr, protocol, allocate); | ||||||||||||||||||||||||||||
| LOG_HR_IF_MSG(E_FAIL, localResult != S_OK, "Failure adding relay port %d", INETADDR_PORT(reinterpret_cast<const SOCKADDR*>(&addr))); | ||||||||||||||||||||||||||||
| if (result == 0) | ||||||||||||||||||||||||||||
| try | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| const auto addrStr = wsl::windows::common::string::SockAddrInetToString(addr); | ||||||||||||||||||||||||||||
| ModifyOpenPorts(c_eth0DeviceName, addrStr.c_str(), guestPort, guestPort, protocol, allocate); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| catch (...) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| result = localResult; | ||||||||||||||||||||||||||||
| LOG_CAUGHT_EXCEPTION_MSG("Failure adding relay port %d", guestPort); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||||||
| return S_OK; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| int VirtioNetworking::ModifyOpenPorts(_In_ PCWSTR tag, _In_ const SOCKADDR_INET& addr, _In_ int protocol, _In_ bool isOpen) const | ||||||||||||||||||||||||||||
| uint16_t VirtioNetworking::ModifyOpenPorts( | ||||||||||||||||||||||||||||
| _In_ PCWSTR tag, _In_opt_ PCSTR hostAddress, _In_ uint16_t HostPort, _In_ uint16_t GuestPort, _In_ int protocol, _In_ bool isOpen) const | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported bind protocol %d", protocol); | ||||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| THROW_HR_IF_MSG( | ||||||||||||||||||||||||||||
| HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), | ||||||||||||||||||||||||||||
| protocol != IPPROTO_TCP && protocol != IPPROTO_UDP, | ||||||||||||||||||||||||||||
| "Unsupported bind protocol %d", | ||||||||||||||||||||||||||||
| protocol); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| auto lock = m_lock.lock_exclusive(); | ||||||||||||||||||||||||||||
| const auto server = m_guestDeviceManager->GetRemoteFileSystem(VIRTIO_NET_CLASS_ID, c_defaultDeviceTag); | ||||||||||||||||||||||||||||
| if (server) | ||||||||||||||||||||||||||||
| THROW_HR_IF(E_NOT_SET, !server); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // format: tag={tag}[;host_port={port}];guest_port={port}[;listen_addr={addr}|;allocate=false][;udp] | ||||||||||||||||||||||||||||
| std::wstring portString = std::format(L"tag={};guest_port={};listen_addr={}", tag, GuestPort, hostAddress); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if (HostPort != WSLC_EPHEMERAL_PORT) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| std::wstring portString = std::format(L"tag={};port_number={}", tag, INETADDR_PORT(reinterpret_cast<const SOCKADDR*>(&addr))); | ||||||||||||||||||||||||||||
| if (protocol == IPPROTO_UDP) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| portString += L";udp"; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| portString += std::format(L";host_port={}", HostPort); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if (!isOpen) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| portString += L";allocate=false"; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| const auto addrStr = wsl::windows::common::string::SockAddrInetToWstring(addr); | ||||||||||||||||||||||||||||
| portString += std::format(L";listen_addr={}", addrStr); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| if (!isOpen) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| portString += L";allocate=false"; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+175
to
+186
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if (protocol == IPPROTO_UDP) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| portString += L";udp"; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const HRESULT addShareResult = server->AddShare(portString.c_str(), nullptr, 0); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| LOG_IF_FAILED(server->AddShare(portString.c_str(), nullptr, 0)); | ||||||||||||||||||||||||||||
| if (HostPort == WSLC_EPHEMERAL_PORT && isOpen && SUCCEEDED(addShareResult)) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
|
Comment on lines
+195
to
+196
|
||||||||||||||||||||||||||||
| if (HostPort == WSLC_EPHEMERAL_PORT && isOpen && SUCCEEDED(addShareResult)) | |
| { | |
| if (HostPort == WSLC_EPHEMERAL_PORT && isOpen) | |
| { | |
| THROW_IF_FAILED_MSG(addShareResult, "Failed to set virtionet port mapping: %ls", portString.c_str()); | |
| constexpr HRESULT c_maxEncodedEphemeralPortResult = S_OK + UINT16_MAX; | |
| THROW_HR_IF_MSG( | |
| E_UNEXPECTED, | |
| addShareResult < S_OK || addShareResult > c_maxEncodedEphemeralPortResult, | |
| "Unexpected AddShare success code for ephemeral port mapping: 0x%08x (%ls)", | |
| static_cast<unsigned int>(addShareResult), | |
| portString.c_str()); |
Copilot
AI
Apr 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VirtioNetworking::UnmapPort ignores the provided ListenAddress (it converts it to wide but then never uses it) and calls ModifyOpenPorts with hostAddress=nullptr. This produces a portString with an empty listen_addr, which is unlikely to match the mapping created by MapPort and may cause unmap to fail or leak the mapping. Pass the same ListenAddress through to ModifyOpenPorts (or, if listen_addr should not be present for allocate=false, update ModifyOpenPorts to omit listen_addr when isOpen==false and ensure unmap uses the expected format).
| ModifyOpenPorts(c_eth0DeviceName, nullptr, HostPort, GuestPort, Protocol, false); | |
| ModifyOpenPorts(c_eth0DeviceName, listenAddrW.c_str(), HostPort, GuestPort, Protocol, false); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,10 @@ class HcsVirtualMachine | |
| IFACEMETHOD(DetachDisk)(_In_ ULONG Lun) override; | ||
| IFACEMETHOD(AddShare)(_In_ LPCWSTR WindowsPath, _In_ BOOL ReadOnly, _Out_ GUID* ShareId) override; | ||
| IFACEMETHOD(RemoveShare)(_In_ REFGUID ShareId) override; | ||
| IFACEMETHOD(MapVirtioNetPort) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think for naming just MapPort and UnmapPort would be better. |
||
| (_In_ USHORT HostPort, _In_ USHORT GuestPort, _In_ int Protocol, _In_ LPCSTR ListenAddress, _Out_ USHORT* AllocatedHostPort) override; | ||
| IFACEMETHOD(UnmapVirtioNetPort) | ||
| (_In_ USHORT HostPort, _In_ USHORT GuestPort, _In_ int Protocol, _In_ LPCSTR ListenAddress) override; | ||
|
|
||
| private: | ||
| struct DiskInfo | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
listen_addr is interpolated into a semicolon-delimited options string that gets parsed on the guest side. Since MapVirtioNetPort’s ListenAddress ultimately comes from a caller-supplied string, it would be safer to validate/normalize it to a real IPv4/IPv6 address (e.g., via inet_pton/InetPton) and reject values containing ';' or other delimiters so a malformed address can’t perturb option parsing.