fix(libSceNetCtl): read the STUN OTHER-ADDRESS attribute from 0x802c per RFC 5780

STUN_ATTR_OTHER_ADDRESS was 0x802b. RFC 5780 section 9.1 registers
0x802b as RESPONSE-ORIGIN and 0x802c as OTHER-ADDRESS (section 7.4 notes
that OTHER-ADDRESS reuses the 0x0005 number of RFC 3489 CHANGED-ADDRESS,
which stays accepted).

ParseStunBindingResponse therefore ignored the alternate server a binding
response advertised in OTHER-ADDRESS, and decoded a RESPONSE-ORIGIN (the
address the response was sent from) as the alternate server.

GuestNetCtl.cpp gains two cases: a response carrying OTHER-ADDRESS (0x802c)
makes sceNetCtlGetNatInfo probe the advertised server, and a response
carrying RESPONSE-ORIGIN (0x802b) makes it probe nothing.
This commit is contained in:
Sher Jan committed 2026-11-06 11:40:57 +05:00
1 parent ab213704ee
commit 6ddd82ff60
2 files changed
+44 -3

No files matched your search

+1 -1
View File
@@ -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;
+43 -2
View File
@@ -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<std::uint8_t> 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<std::uint16_t>(response.size() - 20);
response[2] = static_cast<std::uint8_t>(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);