Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the WSLC Client SDK’s container port-mapping path to support custom host binding addresses (including IPv6) instead of always binding to 127.0.0.1, and relaxes/updates validation around the windowsAddress field.
Changes:
- Convert
windowsAddress(IPv4/IPv6) into a string binding address forWSLCPortMappingduring container creation. - Add input validation for
windowsAddress->ss_familyinWslcSetContainerSettingsPortMappings.
| if (internalPort.windowsAddress->ss_family == AF_INET) | ||
| { | ||
| const auto* addr4 = reinterpret_cast<const sockaddr_in*>(internalPort.windowsAddress); | ||
| THROW_HR_IF_NULL(E_UNEXPECTED, inet_ntop(AF_INET, &addr4->sin_addr, addrBuf, sizeof(addrBuf))); | ||
| convertedPort.Family = AF_INET; | ||
| } | ||
| else | ||
| { | ||
| const auto* addr6 = reinterpret_cast<const sockaddr_in6*>(internalPort.windowsAddress); | ||
| THROW_HR_IF_NULL(E_UNEXPECTED, inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, sizeof(addrBuf))); | ||
| convertedPort.Family = AF_INET6; | ||
| } |
There was a problem hiding this comment.
internalPort.windowsAddress->ss_family is treated as IPv6 for any value other than AF_INET, and the code unconditionally casts to sockaddr_in6. If the family is neither AF_INET nor AF_INET6 (or the caller passes a malformed sockaddr), this becomes an invalid cast and can lead to undefined behavior/crashes. Add an explicit AF_INET6 branch and return/throw E_INVALIDARG (or similar) for unsupported families before casting.
| if (internalPort.windowsAddress->ss_family == AF_INET) | |
| { | |
| const auto* addr4 = reinterpret_cast<const sockaddr_in*>(internalPort.windowsAddress); | |
| THROW_HR_IF_NULL(E_UNEXPECTED, inet_ntop(AF_INET, &addr4->sin_addr, addrBuf, sizeof(addrBuf))); | |
| convertedPort.Family = AF_INET; | |
| } | |
| else | |
| { | |
| const auto* addr6 = reinterpret_cast<const sockaddr_in6*>(internalPort.windowsAddress); | |
| THROW_HR_IF_NULL(E_UNEXPECTED, inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, sizeof(addrBuf))); | |
| convertedPort.Family = AF_INET6; | |
| } | |
| const auto family = internalPort.windowsAddress->ss_family; | |
| if (family == AF_INET) | |
| { | |
| const auto* addr4 = reinterpret_cast<const sockaddr_in*>(internalPort.windowsAddress); | |
| THROW_HR_IF_NULL(E_UNEXPECTED, inet_ntop(AF_INET, &addr4->sin_addr, addrBuf, sizeof(addrBuf))); | |
| convertedPort.Family = AF_INET; | |
| } | |
| else if (family == AF_INET6) | |
| { | |
| const auto* addr6 = reinterpret_cast<const sockaddr_in6*>(internalPort.windowsAddress); | |
| THROW_HR_IF_NULL(E_UNEXPECTED, inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, sizeof(addrBuf))); | |
| convertedPort.Family = AF_INET6; | |
| } | |
| else | |
| { | |
| // Unsupported or invalid address family; avoid invalid cast. | |
| THROW_HR(E_INVALIDARG); | |
| } |
| const auto family = portMappings[i].windowsAddress->ss_family; | ||
| RETURN_HR_IF(E_INVALIDARG, family != AF_INET && family != AF_INET6); | ||
| } | ||
| RETURN_HR_IF(E_NOTIMPL, portMappings[i].protocol != 0); |
There was a problem hiding this comment.
WslcSetContainerSettingsPortMappings currently rejects any protocol value other than 0 (WSLC_PORT_PROTOCOL_TCP) via RETURN_HR_IF(E_NOTIMPL, portMappings[i].protocol != 0);. This makes WSLC_PORT_PROTOCOL_UDP unusable even though the public header documents UDP support and WslcCreateContainer maps non-TCP to IPPROTO_UDP. Update validation to accept both WSLC_PORT_PROTOCOL_TCP and WSLC_PORT_PROTOCOL_UDP (and return E_INVALIDARG for out-of-range values).
| RETURN_HR_IF(E_NOTIMPL, portMappings[i].protocol != 0); | |
| RETURN_HR_IF( | |
| E_INVALIDARG, | |
| portMappings[i].protocol != WSLC_PORT_PROTOCOL_TCP && portMappings[i].protocol != WSLC_PORT_PROTOCOL_UDP); |
| if (internalPort.windowsAddress != nullptr) | ||
| { | ||
| char addrBuf[INET6_ADDRSTRLEN]{}; | ||
| if (internalPort.windowsAddress->ss_family == AF_INET) | ||
| { | ||
| const auto* addr4 = reinterpret_cast<const sockaddr_in*>(internalPort.windowsAddress); | ||
| THROW_HR_IF_NULL(E_UNEXPECTED, inet_ntop(AF_INET, &addr4->sin_addr, addrBuf, sizeof(addrBuf))); | ||
| convertedPort.Family = AF_INET; | ||
| } | ||
| else | ||
| { | ||
| const auto* addr6 = reinterpret_cast<const sockaddr_in6*>(internalPort.windowsAddress); | ||
| THROW_HR_IF_NULL(E_UNEXPECTED, inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, sizeof(addrBuf))); | ||
| convertedPort.Family = AF_INET6; | ||
| } | ||
| bindingAddressStrings[i] = addrBuf; | ||
| convertedPort.BindingAddress = bindingAddressStrings[i].c_str(); | ||
| } | ||
| else | ||
| { | ||
| convertedPort.Family = AF_INET; | ||
| convertedPort.BindingAddress = "127.0.0.1"; | ||
| } |
There was a problem hiding this comment.
This change adds support for custom binding addresses (including IPv6) when creating containers, but there are existing TAEF SDK tests for port mapping that currently only cover the default IPv4 localhost TCP case. Please add/extend tests to cover: (1) a mapping with windowsAddress set (IPv4 and IPv6) and (2) UDP mappings, to prevent regressions in address-family handling and string conversion.
| convertedPort.Family = AF_INET; | ||
| convertedPort.BindingAddress = "127.0.0.1"; |
There was a problem hiding this comment.
Should we just leave these unset if not provided? If the default behavior is "all addresses" this will force localhost only when no address is provided.
Summary of the Pull Request
PR Checklist
Detailed Description of the Pull Request / Additional comments
Validation Steps Performed