diff --git a/api/transport/stun.cc b/api/transport/stun.cc index f774e989b6..0f86267ec2 100644 --- a/api/transport/stun.cc +++ b/api/transport/stun.cc @@ -31,6 +31,7 @@ namespace cricket { namespace { const int k127Utf8CharactersLengthInBytes = 508; +const int kDefaultMaxAttributeLength = 508; const int kMessageIntegrityAttributeLength = 20; const int kTheoreticalMaximumAttributeLength = 65535; @@ -67,6 +68,12 @@ bool LengthValid(int type, int length) { case STUN_ATTR_SOFTWARE: return length <= k127Utf8CharactersLengthInBytes; // RFC 8489 section 14.14 + case STUN_ATTR_ORIGIN: + // 0x802F is unassigned by IANA. + // RESPONSE-ORIGIN is defined in RFC 5780 section 7.3, but does not + // specify a maximum length. It's an URL, so return an arbitrary + // restriction. + return length <= kDefaultMaxAttributeLength; case STUN_ATTR_DATA: // No length restriction in RFC; it's the content of an UDP datagram, // which in theory can be up to 65.535 bytes. @@ -613,6 +620,8 @@ StunAttributeValueType StunMessage::GetAttributeValueType(int type) const { return STUN_VALUE_ADDRESS; case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32; + case STUN_ATTR_ORIGIN: + return STUN_VALUE_BYTE_STRING; case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32; case STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED: diff --git a/api/transport/stun.h b/api/transport/stun.h index 766b9ec368..b5f9ce1a6c 100644 --- a/api/transport/stun.h +++ b/api/transport/stun.h @@ -62,6 +62,7 @@ enum StunAttributeType { STUN_ATTR_SOFTWARE = 0x8022, // ByteString STUN_ATTR_ALTERNATE_SERVER = 0x8023, // Address STUN_ATTR_FINGERPRINT = 0x8028, // UInt32 + STUN_ATTR_ORIGIN = 0x802F, // ByteString STUN_ATTR_RETRANSMIT_COUNT = 0xFF00 // UInt32 }; diff --git a/api/transport/stun_unittest.cc b/api/transport/stun_unittest.cc index e180703817..bf791f257d 100644 --- a/api/transport/stun_unittest.cc +++ b/api/transport/stun_unittest.cc @@ -199,6 +199,20 @@ static const unsigned char kStunMessageWithErrorAttribute[] = { 0x69, 0x7a, 0x65, 0x64 }; +static const unsigned char kStunMessageWithOriginAttribute[] = { + 0x00, 0x01, 0x00, 0x18, // message header (binding request), length 24 + 0x21, 0x12, 0xA4, 0x42, // magic cookie + 0x29, 0x1f, 0xcd, 0x7c, // transaction id + 0xba, 0x58, 0xab, 0xd7, + 0xf2, 0x41, 0x01, 0x00, + 0x80, 0x2f, 0x00, 0x12, // origin attribute (length 18) + 0x68, 0x74, 0x74, 0x70, // http://example.com + 0x3A, 0x2F, 0x2F, 0x65, + 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x00, 0x00, +}; + // Sample messages with an invalid length Field // The actual length in bytes of the invalid messages (including STUN header) @@ -537,6 +551,7 @@ const in_addr kIPv4TestAddress1 = {{{0x0ac, 0x017, 0x044, 0x0e6}}}; const char kTestUserName1[] = "abcdefgh"; const char kTestUserName2[] = "abc"; const char kTestErrorReason[] = "Unauthorized"; +const char kTestOrigin[] = "http://example.com"; const int kTestErrorClass = 4; const int kTestErrorNumber = 1; const int kTestErrorCode = 401; @@ -1082,6 +1097,15 @@ TEST_F(StunTest, ReadMessageWithAnUnknownAttribute) { EXPECT_EQ(kTestUserName2, username->GetString()); } +TEST_F(StunTest, ReadMessageWithOriginAttribute) { + StunMessage msg; + size_t size = ReadStunMessage(&msg, kStunMessageWithOriginAttribute); + CheckStunHeader(msg, STUN_BINDING_REQUEST, size); + const StunByteStringAttribute* origin = msg.GetByteString(STUN_ATTR_ORIGIN); + ASSERT_TRUE(origin != NULL); + EXPECT_EQ(kTestOrigin, origin->GetString()); +} + TEST_F(StunTest, WriteMessageWithAnErrorCodeAttribute) { StunMessage msg; size_t size = sizeof(kStunMessageWithErrorAttribute); @@ -1128,6 +1152,25 @@ TEST_F(StunTest, WriteMessageWithAUInt16ListAttribute) { memcmp(out.Data(), kStunMessageWithUInt16ListAttribute, size - 2)); } +TEST_F(StunTest, WriteMessageWithOriginAttribute) { + StunMessage msg; + size_t size = sizeof(kStunMessageWithOriginAttribute); + + msg.SetType(STUN_BINDING_REQUEST); + msg.SetTransactionID( + std::string(reinterpret_cast(kTestTransactionId1), + kStunTransactionIdLength)); + auto origin = + std::make_unique(STUN_ATTR_ORIGIN, kTestOrigin); + msg.AddAttribute(std::move(origin)); + + rtc::ByteBufferWriter out; + EXPECT_TRUE(msg.Write(&out)); + ASSERT_EQ(size, out.Length()); + // Check everything up to the padding + ASSERT_EQ(0, memcmp(out.Data(), kStunMessageWithOriginAttribute, size - 2)); +} + // Test that we fail to read messages with invalid lengths. void CheckFailureToRead(const unsigned char* testcase, size_t length) { StunMessage msg; diff --git a/p2p/base/fake_port_allocator.h b/p2p/base/fake_port_allocator.h index 6366ea84db..83b27dbafe 100644 --- a/p2p/base/fake_port_allocator.h +++ b/p2p/base/fake_port_allocator.h @@ -36,10 +36,11 @@ class TestUDPPort : public UDPPort { uint16_t max_port, const std::string& username, const std::string& password, + const std::string& origin, bool emit_localhost_for_anyaddress) { TestUDPPort* port = new TestUDPPort(thread, factory, network, min_port, max_port, username, - password, emit_localhost_for_anyaddress); + password, origin, emit_localhost_for_anyaddress); if (!port->Init()) { delete port; port = nullptr; @@ -55,6 +56,7 @@ class TestUDPPort : public UDPPort { uint16_t max_port, const std::string& username, const std::string& password, + const std::string& origin, bool emit_localhost_for_anyaddress) : UDPPort(thread, factory, @@ -63,6 +65,7 @@ class TestUDPPort : public UDPPort { max_port, username, password, + origin, emit_localhost_for_anyaddress) {} }; @@ -112,7 +115,8 @@ class FakePortAllocatorSession : public PortAllocatorSession { ? ipv6_network_ : ipv4_network_; port_.reset(TestUDPPort::Create(network_thread_, factory_, &network, 0, 0, - username(), password(), false)); + username(), password(), std::string(), + false)); RTC_DCHECK(port_); port_->SubscribePortDestroyed( [this](PortInterface* port) { OnPortDestroyed(port); }); diff --git a/p2p/base/port_allocator.h b/p2p/base/port_allocator.h index 08584d988b..1f37e86c65 100644 --- a/p2p/base/port_allocator.h +++ b/p2p/base/port_allocator.h @@ -581,6 +581,17 @@ class RTC_EXPORT PortAllocator : public sigslot::has_slots<> { return turn_port_prune_policy_; } + // Gets/Sets the Origin value used for WebRTC STUN requests. + const std::string& origin() const { + CheckRunOnValidThreadIfInitialized(); + return origin_; + } + + void set_origin(const std::string& origin) { + CheckRunOnValidThreadIfInitialized(); + origin_ = origin; + } + webrtc::TurnCustomizer* turn_customizer() { CheckRunOnValidThreadIfInitialized(); return turn_customizer_; diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc index 338a54ca48..52153d8c90 100644 --- a/p2p/base/port_unittest.cc +++ b/p2p/base/port_unittest.cc @@ -506,7 +506,8 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> { std::unique_ptr CreateUdpPort(const SocketAddress& addr, PacketSocketFactory* socket_factory) { return UDPPort::Create(&main_, socket_factory, MakeNetwork(addr), 0, 0, - username_, password_, true, absl::nullopt); + username_, password_, std::string(), true, + absl::nullopt); } std::unique_ptr CreateTcpPort(const SocketAddress& addr) { return CreateTcpPort(addr, &socket_factory_); @@ -521,7 +522,8 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> { ServerAddresses stun_servers; stun_servers.insert(kStunAddr); return StunPort::Create(&main_, factory, MakeNetwork(addr), 0, 0, username_, - password_, stun_servers, absl::nullopt); + password_, stun_servers, std::string(), + absl::nullopt); } std::unique_ptr CreateRelayPort(const SocketAddress& addr, ProtocolType int_proto, @@ -546,7 +548,7 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> { return TurnPort::Create(&main_, socket_factory, MakeNetwork(addr), 0, 0, username_, password_, ProtocolAddress(server_addr, int_proto), - kRelayCredentials, 0, {}, {}, nullptr, nullptr); + kRelayCredentials, 0, "", {}, {}, nullptr, nullptr); } std::unique_ptr CreateNatServer(const SocketAddress& addr, rtc::NATType type) { diff --git a/p2p/base/stun_port.cc b/p2p/base/stun_port.cc index f2b12f734f..7ae0557f95 100644 --- a/p2p/base/stun_port.cc +++ b/p2p/base/stun_port.cc @@ -13,7 +13,6 @@ #include #include -#include "absl/memory/memory.h" #include "api/transport/stun.h" #include "p2p/base/connection.h" #include "p2p/base/p2p_constants.h" @@ -157,6 +156,7 @@ UDPPort::UDPPort(rtc::Thread* thread, rtc::AsyncPacketSocket* socket, const std::string& username, const std::string& password, + const std::string& origin, bool emit_local_for_anyaddress) : Port(thread, LOCAL_PORT_TYPE, factory, network, username, password), requests_(thread), @@ -165,7 +165,9 @@ UDPPort::UDPPort(rtc::Thread* thread, ready_(false), stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL), dscp_(rtc::DSCP_NO_CHANGE), - emit_local_for_anyaddress_(emit_local_for_anyaddress) {} + emit_local_for_anyaddress_(emit_local_for_anyaddress) { + requests_.set_origin(origin); +} UDPPort::UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, @@ -174,6 +176,7 @@ UDPPort::UDPPort(rtc::Thread* thread, uint16_t max_port, const std::string& username, const std::string& password, + const std::string& origin, bool emit_local_for_anyaddress) : Port(thread, LOCAL_PORT_TYPE, @@ -189,7 +192,9 @@ UDPPort::UDPPort(rtc::Thread* thread, ready_(false), stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL), dscp_(rtc::DSCP_NO_CHANGE), - emit_local_for_anyaddress_(emit_local_for_anyaddress) {} + emit_local_for_anyaddress_(emit_local_for_anyaddress) { + requests_.set_origin(origin); +} bool UDPPort::Init() { stun_keepalive_lifetime_ = GetStunKeepaliveLifetime(); @@ -605,11 +610,12 @@ std::unique_ptr StunPort::Create( const std::string& username, const std::string& password, const ServerAddresses& servers, + const std::string& origin, absl::optional stun_keepalive_interval) { // Using `new` to access a non-public constructor. - auto port = - absl::WrapUnique(new StunPort(thread, factory, network, min_port, - max_port, username, password, servers)); + auto port = absl::WrapUnique(new StunPort(thread, factory, network, min_port, + max_port, username, password, + servers, origin)); port->set_stun_keepalive_delay(stun_keepalive_interval); if (!port->Init()) { return nullptr; @@ -624,7 +630,8 @@ StunPort::StunPort(rtc::Thread* thread, uint16_t max_port, const std::string& username, const std::string& password, - const ServerAddresses& servers) + const ServerAddresses& servers, + const std::string& origin) : UDPPort(thread, factory, network, @@ -632,6 +639,7 @@ StunPort::StunPort(rtc::Thread* thread, max_port, username, password, + origin, false) { // UDPPort will set these to local udp, updating these to STUN. set_type(STUN_PORT_TYPE); diff --git a/p2p/base/stun_port.h b/p2p/base/stun_port.h index af9d04dc03..5a76767b42 100644 --- a/p2p/base/stun_port.h +++ b/p2p/base/stun_port.h @@ -32,22 +32,6 @@ static const int HIGH_COST_PORT_KEEPALIVE_LIFETIME = 2 * 60 * 1000; // Communicates using the address on the outside of a NAT. class UDPPort : public Port { public: - // TODO(bugs.webrtc.org/12132) remove once downstream tests are fixed. - ABSL_DEPRECATED("Use variant without origin attribute below") - static std::unique_ptr Create( - rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - rtc::AsyncPacketSocket* socket, - const std::string& username, - const std::string& password, - const std::string& /*unused, was origin*/, - bool emit_local_for_anyaddress, - absl::optional stun_keepalive_interval) { - return Create(thread, factory, network, socket, username, password, - emit_local_for_anyaddress, stun_keepalive_interval); - } - static std::unique_ptr Create( rtc::Thread* thread, rtc::PacketSocketFactory* factory, @@ -55,12 +39,13 @@ class UDPPort : public Port { rtc::AsyncPacketSocket* socket, const std::string& username, const std::string& password, + const std::string& origin, bool emit_local_for_anyaddress, absl::optional stun_keepalive_interval) { // Using `new` to access a non-public constructor. - auto port = - absl::WrapUnique(new UDPPort(thread, factory, network, socket, username, - password, emit_local_for_anyaddress)); + auto port = absl::WrapUnique(new UDPPort(thread, factory, network, socket, + username, password, origin, + emit_local_for_anyaddress)); port->set_stun_keepalive_delay(stun_keepalive_interval); if (!port->Init()) { return nullptr; @@ -68,23 +53,6 @@ class UDPPort : public Port { return port; } - // TODO(bugs.webrtc.org/12132) remove once downstream tests are fixed. - ABSL_DEPRECATED("Use variant without origin attribute below") - static std::unique_ptr Create( - rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - uint16_t min_port, - uint16_t max_port, - const std::string& username, - const std::string& password, - const std::string& /*unused, was origin*/, - bool emit_local_for_anyaddress, - absl::optional stun_keepalive_interval) { - return Create(thread, factory, network, min_port, max_port, username, - password, emit_local_for_anyaddress, stun_keepalive_interval); - } - static std::unique_ptr Create( rtc::Thread* thread, rtc::PacketSocketFactory* factory, @@ -93,12 +61,13 @@ class UDPPort : public Port { uint16_t max_port, const std::string& username, const std::string& password, + const std::string& origin, bool emit_local_for_anyaddress, absl::optional stun_keepalive_interval) { // Using `new` to access a non-public constructor. - auto port = absl::WrapUnique(new UDPPort(thread, factory, network, min_port, - max_port, username, password, - emit_local_for_anyaddress)); + auto port = absl::WrapUnique( + new UDPPort(thread, factory, network, min_port, max_port, username, + password, origin, emit_local_for_anyaddress)); port->set_stun_keepalive_delay(stun_keepalive_interval); if (!port->Init()) { return nullptr; @@ -157,6 +126,7 @@ class UDPPort : public Port { uint16_t max_port, const std::string& username, const std::string& password, + const std::string& origin, bool emit_local_for_anyaddress); UDPPort(rtc::Thread* thread, @@ -165,6 +135,7 @@ class UDPPort : public Port { rtc::AsyncPacketSocket* socket, const std::string& username, const std::string& password, + const std::string& origin, bool emit_local_for_anyaddress); bool Init(); @@ -303,6 +274,7 @@ class StunPort : public UDPPort { const std::string& username, const std::string& password, const ServerAddresses& servers, + const std::string& origin, absl::optional stun_keepalive_interval); void PrepareAddress() override; @@ -315,7 +287,8 @@ class StunPort : public UDPPort { uint16_t max_port, const std::string& username, const std::string& password, - const ServerAddresses& servers); + const ServerAddresses& servers, + const std::string& origin); }; } // namespace cricket diff --git a/p2p/base/stun_port_unittest.cc b/p2p/base/stun_port_unittest.cc index d483bafd84..5ee707b22b 100644 --- a/p2p/base/stun_port_unittest.cc +++ b/p2p/base/stun_port_unittest.cc @@ -77,7 +77,7 @@ class StunPortTestBase : public ::testing::Test, public sigslot::has_slots<> { stun_port_ = cricket::StunPort::Create( rtc::Thread::Current(), &socket_factory_, &network_, 0, 0, rtc::CreateRandomString(16), rtc::CreateRandomString(22), stun_servers, - absl::nullopt); + std::string(), absl::nullopt); stun_port_->set_stun_keepalive_delay(stun_keepalive_delay_); // If `stun_keepalive_lifetime_` is negative, let the stun port // choose its lifetime from the network type. @@ -103,8 +103,8 @@ class StunPortTestBase : public ::testing::Test, public sigslot::has_slots<> { socket_->SignalReadPacket.connect(this, &StunPortTestBase::OnReadPacket); stun_port_ = cricket::UDPPort::Create( rtc::Thread::Current(), &socket_factory_, &network_, socket_.get(), - rtc::CreateRandomString(16), rtc::CreateRandomString(22), false, - absl::nullopt); + rtc::CreateRandomString(16), rtc::CreateRandomString(22), std::string(), + false, absl::nullopt); ASSERT_TRUE(stun_port_ != NULL); ServerAddresses stun_servers; stun_servers.insert(server_addr); diff --git a/p2p/base/stun_request.cc b/p2p/base/stun_request.cc index b271daa6ba..0dd85c6944 100644 --- a/p2p/base/stun_request.cc +++ b/p2p/base/stun_request.cc @@ -59,6 +59,7 @@ void StunRequestManager::Send(StunRequest* request) { void StunRequestManager::SendDelayed(StunRequest* request, int delay) { request->set_manager(this); RTC_DCHECK(requests_.find(request->id()) == requests_.end()); + request->set_origin(origin_); request->Construct(); requests_[request->id()] = request; if (delay > 0) { @@ -212,6 +213,10 @@ StunRequest::~StunRequest() { void StunRequest::Construct() { if (msg_->type() == 0) { + if (!origin_.empty()) { + msg_->AddAttribute( + std::make_unique(STUN_ATTR_ORIGIN, origin_)); + } Prepare(msg_); RTC_DCHECK(msg_->type() != 0); } diff --git a/p2p/base/stun_request.h b/p2p/base/stun_request.h index b417c705cd..566478c349 100644 --- a/p2p/base/stun_request.h +++ b/p2p/base/stun_request.h @@ -67,6 +67,9 @@ class StunRequestManager { bool empty() { return requests_.empty(); } + // Set the Origin header for outgoing stun messages. + void set_origin(const std::string& origin) { origin_ = origin; } + // Raised when there are bytes to be sent. sigslot::signal3 SignalSendPacket; @@ -75,6 +78,7 @@ class StunRequestManager { rtc::Thread* const thread_; RequestMap requests_; + std::string origin_; friend class StunRequest; }; @@ -101,6 +105,10 @@ class StunRequest : public rtc::MessageHandler { return msg_->reduced_transaction_id(); } + // the origin value + const std::string& origin() const { return origin_; } + void set_origin(const std::string& origin) { origin_ = origin; } + // Returns the STUN type of the request message. int type(); @@ -116,6 +124,7 @@ class StunRequest : public rtc::MessageHandler { protected: int count_; bool timeout_; + std::string origin_; // Fills in a request object to be sent. Note that request's transaction ID // will already be set and cannot be changed. diff --git a/p2p/base/turn_port.cc b/p2p/base/turn_port.cc index 07c1060432..b7d37b31b1 100644 --- a/p2p/base/turn_port.cc +++ b/p2p/base/turn_port.cc @@ -223,6 +223,7 @@ TurnPort::TurnPort(rtc::Thread* thread, const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::string& origin, webrtc::TurnCustomizer* customizer) : Port(thread, RELAY_PORT_TYPE, factory, network, username, password), server_address_(server_address), @@ -238,6 +239,7 @@ TurnPort::TurnPort(rtc::Thread* thread, allocate_mismatch_retries_(0), turn_customizer_(customizer) { request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); + request_manager_.set_origin(origin); } TurnPort::TurnPort(rtc::Thread* thread, @@ -250,6 +252,7 @@ TurnPort::TurnPort(rtc::Thread* thread, const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::string& origin, const std::vector& tls_alpn_protocols, const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer, @@ -277,6 +280,7 @@ TurnPort::TurnPort(rtc::Thread* thread, allocate_mismatch_retries_(0), turn_customizer_(customizer) { request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); + request_manager_.set_origin(origin); } TurnPort::~TurnPort() { diff --git a/p2p/base/turn_port.h b/p2p/base/turn_port.h index 934c65d0b0..18633735f6 100644 --- a/p2p/base/turn_port.h +++ b/p2p/base/turn_port.h @@ -51,25 +51,6 @@ class TurnPort : public Port { STATE_DISCONNECTED, // TCP connection died, cannot send/receive any // packets. }; - - // TODO(bugs.webrtc.org/12132) remove once downstream tests are fixed. - static std::unique_ptr Create( - rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - rtc::AsyncPacketSocket* socket, - const std::string& username, // ice username. - const std::string& password, // ice password. - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority, - const std::string& /*unused, was origin*/, - const std::string& origin, - webrtc::TurnCustomizer* customizer) { - return Create(thread, factory, network, socket, username, password, - server_address, credentials, server_priority, customizer); - } - // Create a TURN port using the shared UDP socket, `socket`. static std::unique_ptr Create( rtc::Thread* thread, @@ -81,6 +62,7 @@ class TurnPort : public Port { const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::string& origin, webrtc::TurnCustomizer* customizer) { // Do basic parameter validation. if (credentials.username.size() > kMaxTurnUsernameLength) { @@ -95,11 +77,10 @@ class TurnPort : public Port { return nullptr; } // Using `new` to access a non-public constructor. - return absl::WrapUnique( - new TurnPort(thread, factory, network, socket, username, password, - server_address, credentials, server_priority, customizer)); + return absl::WrapUnique(new TurnPort( + thread, factory, network, socket, username, password, server_address, + credentials, server_priority, origin, customizer)); } - // TODO(steveanton): Remove once downstream clients have moved to `Create`. static std::unique_ptr CreateUnique( rtc::Thread* thread, @@ -111,32 +92,11 @@ class TurnPort : public Port { const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::string& origin, webrtc::TurnCustomizer* customizer) { return Create(thread, factory, network, socket, username, password, - server_address, credentials, server_priority, customizer); - } - - // TODO(bugs.webrtc.org/12132) remove once downstream tests are fixed. - static std::unique_ptr Create( - rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - uint16_t min_port, - uint16_t max_port, - const std::string& username, // ice username. - const std::string& password, // ice password. - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority, - const std::string& /*unused, was origin*/, - const std::vector& tls_alpn_protocols, - const std::vector& tls_elliptic_curves, - webrtc::TurnCustomizer* customizer, - rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr) { - return Create(thread, factory, network, min_port, max_port, username, - password, server_address, credentials, server_priority, - tls_alpn_protocols, tls_elliptic_curves, customizer, - tls_cert_verifier); + server_address, credentials, server_priority, origin, + customizer); } // Create a TURN port that will use a new socket, bound to `network` and @@ -152,6 +112,7 @@ class TurnPort : public Port { const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::string& origin, const std::vector& tls_alpn_protocols, const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer, @@ -169,12 +130,12 @@ class TurnPort : public Port { return nullptr; } // Using `new` to access a non-public constructor. - return absl::WrapUnique(new TurnPort( - thread, factory, network, min_port, max_port, username, password, - server_address, credentials, server_priority, tls_alpn_protocols, - tls_elliptic_curves, customizer, tls_cert_verifier)); + return absl::WrapUnique( + new TurnPort(thread, factory, network, min_port, max_port, username, + password, server_address, credentials, server_priority, + origin, tls_alpn_protocols, tls_elliptic_curves, + customizer, tls_cert_verifier)); } - // TODO(steveanton): Remove once downstream clients have moved to `Create`. static std::unique_ptr CreateUnique( rtc::Thread* thread, @@ -187,13 +148,14 @@ class TurnPort : public Port { const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::string& origin, const std::vector& tls_alpn_protocols, const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer, rtc::SSLCertificateVerifier* tls_cert_verifier = nullptr) { return Create(thread, factory, network, min_port, max_port, username, password, server_address, credentials, server_priority, - tls_alpn_protocols, tls_elliptic_curves, customizer, + origin, tls_alpn_protocols, tls_elliptic_curves, customizer, tls_cert_verifier); } @@ -305,6 +267,7 @@ class TurnPort : public Port { const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::string& origin, webrtc::TurnCustomizer* customizer); TurnPort(rtc::Thread* thread, @@ -317,6 +280,7 @@ class TurnPort : public Port { const ProtocolAddress& server_address, const RelayCredentials& credentials, int server_priority, + const std::string& origin, const std::vector& tls_alpn_protocols, const std::vector& tls_elliptic_curves, webrtc::TurnCustomizer* customizer, diff --git a/p2p/base/turn_port_unittest.cc b/p2p/base/turn_port_unittest.cc index e441657592..7854fdb986 100644 --- a/p2p/base/turn_port_unittest.cc +++ b/p2p/base/turn_port_unittest.cc @@ -85,6 +85,7 @@ static const char kIcePwd1[] = "TESTICEPWD00000000000001"; static const char kIcePwd2[] = "TESTICEPWD00000000000002"; static const char kTurnUsername[] = "test"; static const char kTurnPassword[] = "test"; +static const char kTestOrigin[] = "http://example.com"; // This test configures the virtual socket server to simulate delay so that we // can verify operations take no more than the expected number of round trips. static constexpr unsigned int kSimulatedRtt = 50; @@ -258,14 +259,25 @@ class TurnPortTest : public ::testing::Test, const std::string& password, const ProtocolAddress& server_address) { return CreateTurnPortWithAllParams(MakeNetwork(kLocalAddr1), username, - password, server_address); + password, server_address, std::string()); } bool CreateTurnPort(const rtc::SocketAddress& local_address, const std::string& username, const std::string& password, const ProtocolAddress& server_address) { return CreateTurnPortWithAllParams(MakeNetwork(local_address), username, - password, server_address); + password, server_address, std::string()); + } + + // Should be identical to CreateTurnPort but specifies an origin value + // when creating the instance of TurnPort. + bool CreateTurnPortWithOrigin(const rtc::SocketAddress& local_address, + const std::string& username, + const std::string& password, + const ProtocolAddress& server_address, + const std::string& origin) { + return CreateTurnPortWithAllParams(MakeNetwork(local_address), username, + password, server_address, origin); } bool CreateTurnPortWithNetwork(rtc::Network* network, @@ -273,7 +285,7 @@ class TurnPortTest : public ::testing::Test, const std::string& password, const ProtocolAddress& server_address) { return CreateTurnPortWithAllParams(network, username, password, - server_address); + server_address, std::string()); } // Version of CreateTurnPort that takes all possible parameters; all other @@ -282,11 +294,12 @@ class TurnPortTest : public ::testing::Test, bool CreateTurnPortWithAllParams(rtc::Network* network, const std::string& username, const std::string& password, - const ProtocolAddress& server_address) { + const ProtocolAddress& server_address, + const std::string& origin) { RelayCredentials credentials(username, password); turn_port_ = TurnPort::Create( &main_, &socket_factory_, network, 0, 0, kIceUfrag1, kIcePwd1, - server_address, credentials, 0, {}, {}, turn_customizer_.get()); + server_address, credentials, 0, origin, {}, {}, turn_customizer_.get()); if (!turn_port_) { return false; } @@ -318,9 +331,10 @@ class TurnPortTest : public ::testing::Test, } RelayCredentials credentials(username, password); - turn_port_ = TurnPort::Create( - &main_, &socket_factory_, MakeNetwork(kLocalAddr1), socket_.get(), - kIceUfrag1, kIcePwd1, server_address, credentials, 0, nullptr); + turn_port_ = + TurnPort::Create(&main_, &socket_factory_, MakeNetwork(kLocalAddr1), + socket_.get(), kIceUfrag1, kIcePwd1, server_address, + credentials, 0, std::string(), nullptr); // This TURN port will be the controlling. turn_port_->SetIceRole(ICEROLE_CONTROLLING); ConnectSignals(); @@ -347,9 +361,9 @@ class TurnPortTest : public ::testing::Test, void CreateUdpPort() { CreateUdpPort(kLocalAddr2); } void CreateUdpPort(const SocketAddress& address) { - udp_port_ = - UDPPort::Create(&main_, &socket_factory_, MakeNetwork(address), 0, 0, - kIceUfrag2, kIcePwd2, false, absl::nullopt); + udp_port_ = UDPPort::Create(&main_, &socket_factory_, MakeNetwork(address), + 0, 0, kIceUfrag2, kIcePwd2, std::string(), + false, absl::nullopt); // UDP port will be controlled. udp_port_->SetIceRole(ICEROLE_CONTROLLED); udp_port_->SignalPortComplete.connect(this, @@ -1537,6 +1551,17 @@ TEST_F(TurnPortTest, TestCandidateAddressFamilyMatch) { EXPECT_EQ(nullptr, conn); } +TEST_F(TurnPortTest, TestOriginHeader) { + CreateTurnPortWithOrigin(kLocalAddr1, kTurnUsername, kTurnPassword, + kTurnUdpProtoAddr, kTestOrigin); + turn_port_->PrepareAddress(); + EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); + ASSERT_GT(turn_server_.server()->allocations().size(), 0U); + SocketAddress local_address = turn_port_->GetLocalAddress(); + ASSERT_TRUE(turn_server_.FindAllocation(local_address) != NULL); + EXPECT_EQ(kTestOrigin, turn_server_.FindAllocation(local_address)->origin()); +} + // Test that a CreatePermission failure will result in the connection being // pruned and failed. TEST_F(TurnPortTest, TestConnectionFailedAndPrunedOnCreatePermissionFailure) { diff --git a/p2p/base/turn_server.cc b/p2p/base/turn_server.cc index 41ee43c543..fd9cd16138 100644 --- a/p2p/base/turn_server.cc +++ b/p2p/base/turn_server.cc @@ -655,6 +655,11 @@ void TurnServerAllocation::HandleAllocateRequest(const TurnMessage* msg) { msg->GetByteString(STUN_ATTR_USERNAME); RTC_DCHECK(username_attr != NULL); username_ = username_attr->GetString(); + const StunByteStringAttribute* origin_attr = + msg->GetByteString(STUN_ATTR_ORIGIN); + if (origin_attr) { + origin_ = origin_attr->GetString(); + } // Figure out the lifetime and start the allocation timer. int lifetime_secs = ComputeLifetime(msg); diff --git a/p2p/base/turn_server.h b/p2p/base/turn_server.h index e197a8e603..7942c09af9 100644 --- a/p2p/base/turn_server.h +++ b/p2p/base/turn_server.h @@ -79,6 +79,7 @@ class TurnServerAllocation : public rtc::MessageHandlerAutoCleanup, const std::string& key() const { return key_; } const std::string& transaction_id() const { return transaction_id_; } const std::string& username() const { return username_; } + const std::string& origin() const { return origin_; } const std::string& last_nonce() const { return last_nonce_; } void set_last_nonce(const std::string& nonce) { last_nonce_ = nonce; } @@ -134,6 +135,7 @@ class TurnServerAllocation : public rtc::MessageHandlerAutoCleanup, std::string key_; std::string transaction_id_; std::string username_; + std::string origin_; std::string last_nonce_; PermissionList perms_; ChannelList channels_; diff --git a/p2p/client/basic_port_allocator.cc b/p2p/client/basic_port_allocator.cc index 5a26934b03..2a601d5191 100644 --- a/p2p/client/basic_port_allocator.cc +++ b/p2p/client/basic_port_allocator.cc @@ -1430,14 +1430,14 @@ void AllocationSequence::CreateUDPPorts() { port = UDPPort::Create( session_->network_thread(), session_->socket_factory(), network_, udp_socket_.get(), session_->username(), session_->password(), - emit_local_candidate_for_anyaddress, + session_->allocator()->origin(), emit_local_candidate_for_anyaddress, session_->allocator()->stun_candidate_keepalive_interval()); } else { port = UDPPort::Create( session_->network_thread(), session_->socket_factory(), network_, session_->allocator()->min_port(), session_->allocator()->max_port(), session_->username(), session_->password(), - emit_local_candidate_for_anyaddress, + session_->allocator()->origin(), emit_local_candidate_for_anyaddress, session_->allocator()->stun_candidate_keepalive_interval()); } @@ -1502,6 +1502,7 @@ void AllocationSequence::CreateStunPorts() { session_->network_thread(), session_->socket_factory(), network_, session_->allocator()->min_port(), session_->allocator()->max_port(), session_->username(), session_->password(), config_->StunServers(), + session_->allocator()->origin(), session_->allocator()->stun_candidate_keepalive_interval()); if (port) { session_->AddAllocatedPort(port.release(), this); @@ -1563,6 +1564,7 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) { args.password = session_->password(); args.server_address = &(*relay_port); args.config = &config; + args.origin = session_->allocator()->origin(); args.turn_customizer = session_->allocator()->turn_customizer(); std::unique_ptr port; diff --git a/p2p/client/relay_port_factory_interface.h b/p2p/client/relay_port_factory_interface.h index e4fac81690..c1cf51e5c3 100644 --- a/p2p/client/relay_port_factory_interface.h +++ b/p2p/client/relay_port_factory_interface.h @@ -43,8 +43,6 @@ struct CreateRelayPortArgs { const RelayServerConfig* config; std::string username; std::string password; - // TODO(bugs.webrtc.org/12132) remove once downstream tests are fixed. - ABSL_DEPRECATED("stun origin support is going away") std::string origin; webrtc::TurnCustomizer* turn_customizer; }; diff --git a/p2p/client/turn_port_factory.cc b/p2p/client/turn_port_factory.cc index feaada3a1c..fd3420c016 100644 --- a/p2p/client/turn_port_factory.cc +++ b/p2p/client/turn_port_factory.cc @@ -26,7 +26,8 @@ std::unique_ptr TurnPortFactory::Create( auto port = TurnPort::CreateUnique( args.network_thread, args.socket_factory, args.network, udp_socket, args.username, args.password, *args.server_address, - args.config->credentials, args.config->priority, args.turn_customizer); + args.config->credentials, args.config->priority, args.origin, + args.turn_customizer); if (!port) return nullptr; port->SetTlsCertPolicy(args.config->tls_cert_policy); @@ -40,7 +41,7 @@ std::unique_ptr TurnPortFactory::Create(const CreateRelayPortArgs& args, auto port = TurnPort::CreateUnique( args.network_thread, args.socket_factory, args.network, min_port, max_port, args.username, args.password, *args.server_address, - args.config->credentials, args.config->priority, + args.config->credentials, args.config->priority, args.origin, args.config->tls_alpn_protocols, args.config->tls_elliptic_curves, args.turn_customizer, args.config->tls_cert_verifier); if (!port)