diff --git a/core/libs/prx/libSceNetCtl/Export.cpp b/core/libs/prx/libSceNetCtl/Export.cpp index 39fab2b0fb..cf9bb04870 100644 --- a/core/libs/prx/libSceNetCtl/Export.cpp +++ b/core/libs/prx/libSceNetCtl/Export.cpp @@ -70,7 +70,7 @@ static constexpr std::uint16_t STUN_ATTR_MAPPED_ADDRESS = 0x0001; static constexpr std::uint16_t STUN_ATTR_CHANGED_ADDRESS = 0x0005; static constexpr std::uint16_t STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020; static constexpr std::uint16_t STUN_ATTR_XOR_MAPPED_ADDRESS_LEGACY = 0x8020; -static constexpr std::uint16_t STUN_ATTR_OTHER_ADDRESS = 0x802b; +static constexpr std::uint16_t STUN_ATTR_OTHER_ADDRESS = 0x802c; static constexpr std::size_t STUN_HEADER_SIZE = 20; static constexpr std::size_t STUN_TRANSACTION_ID_SIZE = 12; static constexpr int STUN_DEFAULT_TIMEOUT_MS = 300; diff --git a/core/libs/tests/GuestNetCtl.cpp b/core/libs/tests/GuestNetCtl.cpp index 5da79b2fbf..f878b59ed0 100644 --- a/core/libs/tests/GuestNetCtl.cpp +++ b/core/libs/tests/GuestNetCtl.cpp @@ -418,7 +418,7 @@ StunTxId ReceiveStunBindingRequest(TestSocket serverSocket, sockaddr_in& client) return txId; } -void SendStunBindingResponse(TestSocket serverSocket, const sockaddr_in& client, const StunTxId& txId, std::uint32_t mappedAddr, std::uint16_t mappedHostPort, bool xorMapped, const sockaddr_in* otherServer = nullptr) { +void SendStunBindingResponse(TestSocket serverSocket, const sockaddr_in& client, const StunTxId& txId, std::uint32_t mappedAddr, std::uint16_t mappedHostPort, bool xorMapped, const sockaddr_in* otherServer = nullptr, std::uint16_t otherAttr = 0x0005) { const std::uint16_t effectivePort = mappedHostPort != 0 ? mappedHostPort : ntohs(client.sin_port); const std::uint32_t effectiveAddr = mappedAddr != 0 ? mappedAddr : client.sin_addr.s_addr; std::vector response(20, 0); @@ -429,7 +429,7 @@ void SendStunBindingResponse(TestSocket serverSocket, const sockaddr_in& client, std::memcpy(response.data() + 8, txId.data(), txId.size()); AppendStunAddressAttribute(response, xorMapped ? 0x0020 : 0x0001, effectiveAddr, effectivePort, xorMapped); if (otherServer) { - AppendStunAddressAttribute(response, 0x0005, otherServer->sin_addr.s_addr, ntohs(otherServer->sin_port), false); + AppendStunAddressAttribute(response, otherAttr, otherServer->sin_addr.s_addr, ntohs(otherServer->sin_port), false); } const auto attrLen = static_cast(response.size() - 20); response[2] = static_cast(attrLen >> 8); @@ -578,6 +578,47 @@ void CheckNatDiscovery(in_addr address) { Require(natInfo.nat_type == 3); Require(natInfo.mapped_addr == externalIp); + constexpr std::uint16_t kStunResponseOrigin = 0x802b; + constexpr std::uint16_t kStunOtherAddress = 0x802c; + + NetCtlSetStunServers_nid_no_patch(&server1Addr, 1, 1000); + StunTxId otherAddressTx1{}; + StunTxId otherAddressTx2{}; + bool otherAddressProbed = false; + std::thread otherAddressWorker([&] { + sockaddr_in firstClient{}; + otherAddressTx1 = ReceiveStunBindingRequest(server1, firstClient); + SendStunBindingResponse(server1, firstClient, otherAddressTx1, externalIp, 54321, false, &server2Addr, kStunOtherAddress); + if (WaitReadable(server2, 1500)) { + otherAddressProbed = true; + sockaddr_in secondClient{}; + otherAddressTx2 = ReceiveStunBindingRequest(server2, secondClient); + SendStunBindingResponse(server2, secondClient, otherAddressTx2, externalIp, 54322, false); + } + }); + natInfo = {sizeof(natInfo), 99, 99, 0}; + Require(sceNetCtlGetNatInfo(&natInfo) == 0); + otherAddressWorker.join(); + Require(otherAddressProbed); + RecordUniqueTransactionId(seenIds, otherAddressTx1); + RecordUniqueTransactionId(seenIds, otherAddressTx2); + Require(natInfo.stun_status == 2); + Require(natInfo.nat_type == 3); + Require(natInfo.mapped_addr == externalIp); + + NetCtlSetStunServers_nid_no_patch(&server1Addr, 1, 300); + StunTxId responseOriginTx{}; + std::thread responseOriginWorker([&] { + sockaddr_in client{}; + responseOriginTx = ReceiveStunBindingRequest(server1, client); + SendStunBindingResponse(server1, client, responseOriginTx, externalIp, 54321, false, &server2Addr, kStunResponseOrigin); + }); + natInfo = {sizeof(natInfo), 99, 99, 0}; + Require(sceNetCtlGetNatInfo(&natInfo) == 0); + responseOriginWorker.join(); + RecordUniqueTransactionId(seenIds, responseOriginTx); + Require(!WaitReadable(server2, 300)); + NetCtlSetStunServers_nid_no_patch(nullptr, 0, 0); CloseTestSocket(server1); CloseTestSocket(server2);