diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-09 16:54:32 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-09 16:54:32 +0000 |
commit | 949db516ff98c3177ffe34f18941e1bef0cbfa2b (patch) | |
tree | 9ead4822499297e00358261624531c94e1095c32 | |
parent | 00070c73ac9346bd60307711bb38bbd2270b1a40 (diff) | |
download | chromium_src-949db516ff98c3177ffe34f18941e1bef0cbfa2b.zip chromium_src-949db516ff98c3177ffe34f18941e1bef0cbfa2b.tar.gz chromium_src-949db516ff98c3177ffe34f18941e1bef0cbfa2b.tar.bz2 |
Security restrictions for P2P UDP Sockets.
BUG=None
TEST=Unittests
Review URL: http://codereview.chromium.org/6800023
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81039 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | content/browser/renderer_host/p2p_socket_host.cc | 68 | ||||
-rw-r--r-- | content/browser/renderer_host/p2p_socket_host.h | 38 | ||||
-rw-r--r-- | content/browser/renderer_host/p2p_socket_host_udp.cc | 51 | ||||
-rw-r--r-- | content/browser/renderer_host/p2p_socket_host_udp.h | 17 | ||||
-rw-r--r-- | content/browser/renderer_host/p2p_socket_host_udp_unittest.cc | 300 |
6 files changed, 446 insertions, 29 deletions
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 232a384..ecfeb38 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1874,6 +1874,7 @@ '../content/browser/in_process_webkit/webkit_thread_unittest.cc', '../content/browser/plugin_service_unittest.cc', '../content/browser/renderer_host/audio_renderer_host_unittest.cc', + '../content/browser/renderer_host/p2p_socket_host_udp_unittest.cc', '../content/browser/renderer_host/render_view_host_unittest.cc', '../content/browser/renderer_host/render_widget_host_unittest.cc', '../content/browser/renderer_host/resource_dispatcher_host_unittest.cc', diff --git a/content/browser/renderer_host/p2p_socket_host.cc b/content/browser/renderer_host/p2p_socket_host.cc index c1e8849..39e0119 100644 --- a/content/browser/renderer_host/p2p_socket_host.cc +++ b/content/browser/renderer_host/p2p_socket_host.cc @@ -4,26 +4,86 @@ #include "content/browser/renderer_host/p2p_socket_host.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <winsock2.h> // for htonl +#else +#include <arpa/inet.h> +#endif + #include "content/browser/renderer_host/p2p_socket_host_udp.h" -P2PSocketHost::P2PSocketHost(P2PSocketsHost* host, int routing_id, int id) - : host_(host), routing_id_(routing_id), id_(id) { +namespace { +const int kStunHeaderSize = 20; +const uint32 kStunMagicCookie = 0x2112A442; +} // namespace + +P2PSocketHost::P2PSocketHost(IPC::Message::Sender* message_sender, + int routing_id, int id) + : message_sender_(message_sender), routing_id_(routing_id), id_(id) { } P2PSocketHost::~P2PSocketHost() { } +// Verifies that the packet |data| has a valid STUN header. +bool P2PSocketHost::GetStunPacketType( + const char* data, int data_size, StunMessageType* type) { + + if (data_size < kStunHeaderSize) + return false; + + // TODO(sergeyu): Fix libjingle to format STUN message according to + // RFC5389 and validate STUN magic cookie here. + // + // uint32 cookie = ntohl(*reinterpret_cast<const uint32*>(data + 4)); + // if (cookie != kStunMagicCookie) + // return false; + + uint16 length = ntohs(*reinterpret_cast<const uint16*>(data + 2)); + if (length != data_size - kStunHeaderSize) + return false; + + int message_type = ntohs(*reinterpret_cast<const uint16*>(data)); + + // Verify that the type is known: + switch (message_type) { + case STUN_BINDING_REQUEST: + case STUN_BINDING_RESPONSE: + case STUN_BINDING_ERROR_RESPONSE: + case STUN_SHARED_SECRET_REQUEST: + case STUN_SHARED_SECRET_RESPONSE: + case STUN_SHARED_SECRET_ERROR_RESPONSE: + case STUN_ALLOCATE_REQUEST: + case STUN_ALLOCATE_RESPONSE: + case STUN_ALLOCATE_ERROR_RESPONSE: + case STUN_SEND_REQUEST: + case STUN_SEND_RESPONSE: + case STUN_SEND_ERROR_RESPONSE: + case STUN_DATA_INDICATION: + *type = static_cast<StunMessageType>(message_type); + return true; + + default: + return false; + } +} + // static P2PSocketHost* P2PSocketHost::Create( - P2PSocketsHost* host, int routing_id, int id, P2PSocketType type) { + IPC::Message::Sender* message_sender, int routing_id, int id, + P2PSocketType type) { switch (type) { case P2P_SOCKET_UDP: - return new P2PSocketHostUdp(host, routing_id, id); + return new P2PSocketHostUdp(message_sender, routing_id, id); case P2P_SOCKET_TCP_SERVER: // TODO(sergeyu): Implement TCP sockets support. + NOTIMPLEMENTED(); return NULL; case P2P_SOCKET_TCP_CLIENT: + NOTIMPLEMENTED(); return NULL; } diff --git a/content/browser/renderer_host/p2p_socket_host.h b/content/browser/renderer_host/p2p_socket_host.h index 55af872e..0248b577 100644 --- a/content/browser/renderer_host/p2p_socket_host.h +++ b/content/browser/renderer_host/p2p_socket_host.h @@ -7,30 +7,50 @@ #include "content/common/p2p_sockets.h" +#include "ipc/ipc_message.h" #include "net/base/ip_endpoint.h" -class P2PSocketsHost; - // Base class for P2P sockets used by P2PSocketsHost. class P2PSocketHost { public: // Creates P2PSocketHost of the specific type. - static P2PSocketHost* Create(P2PSocketsHost* host, int routing_id, int id, - P2PSocketType type); + static P2PSocketHost* Create(IPC::Message::Sender* message_sender, + int routing_id, int id, P2PSocketType type); virtual ~P2PSocketHost(); // Initalizes the socket. Returns false when initiazations fails. virtual bool Init(const net::IPEndPoint& local_address) = 0; - // Sends |data| on the socket to |socket_address|. - virtual void Send(const net::IPEndPoint& socket_address, + // Sends |data| on the socket to |to|. + virtual void Send(const net::IPEndPoint& to, const std::vector<char>& data) = 0; protected: - P2PSocketHost(P2PSocketsHost* host, int routing_id, int id); - - P2PSocketsHost* host_; + enum StunMessageType { + STUN_BINDING_REQUEST = 0x0001, + STUN_BINDING_RESPONSE = 0x0101, + STUN_BINDING_ERROR_RESPONSE = 0x0111, + STUN_SHARED_SECRET_REQUEST = 0x0002, + STUN_SHARED_SECRET_RESPONSE = 0x0102, + STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112, + STUN_ALLOCATE_REQUEST = 0x0003, + STUN_ALLOCATE_RESPONSE = 0x0103, + STUN_ALLOCATE_ERROR_RESPONSE = 0x0113, + STUN_SEND_REQUEST = 0x0004, + STUN_SEND_RESPONSE = 0x0104, + STUN_SEND_ERROR_RESPONSE = 0x0114, + STUN_DATA_INDICATION = 0x0115 + }; + + P2PSocketHost(IPC::Message::Sender* message_sender, int routing_id, int id); + + // Verifies that the packet |data| has a valid STUN header. In case + // of success stores type of the message in |type|. + bool GetStunPacketType(const char* data, int data_size, + StunMessageType* type); + + IPC::Message::Sender* message_sender_; int routing_id_; int id_; diff --git a/content/browser/renderer_host/p2p_socket_host_udp.cc b/content/browser/renderer_host/p2p_socket_host_udp.cc index 9d9a063..05ef7ce 100644 --- a/content/browser/renderer_host/p2p_socket_host_udp.cc +++ b/content/browser/renderer_host/p2p_socket_host_udp.cc @@ -4,7 +4,6 @@ #include "content/browser/renderer_host/p2p_socket_host_udp.h" -#include "content/browser/renderer_host/p2p_sockets_host.h" #include "content/common/p2p_messages.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" @@ -12,13 +11,16 @@ namespace { +// UDP packets cannot be bigger than 64k. const int kReadBufferSize = 65536; } // namespace -P2PSocketHostUdp::P2PSocketHostUdp(P2PSocketsHost* host, int routing_id, int id) - : P2PSocketHost(host, routing_id, id), +P2PSocketHostUdp::P2PSocketHostUdp(IPC::Message::Sender* message_sender, + int routing_id, int id) + : P2PSocketHost(message_sender, routing_id, id), state_(STATE_UNINITIALIZED), + socket_(new net::UDPServerSocket(NULL, net::NetLog::Source())), send_pending_(false), ALLOW_THIS_IN_INITIALIZER_LIST( recv_callback_(this, &P2PSocketHostUdp::OnRecv)), @@ -34,9 +36,7 @@ P2PSocketHostUdp::~P2PSocketHostUdp() { } bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address) { - net::UDPServerSocket* socket = new net::UDPServerSocket( - NULL, net::NetLog::Source()); - socket_.reset(socket); + DCHECK_EQ(state_, STATE_UNINITIALIZED); int result = socket_->Listen(local_address); if (result < 0) { @@ -61,7 +61,7 @@ bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address) { recv_buffer_ = new net::IOBuffer(kReadBufferSize); DoRead(); - host_->Send(new P2PMsg_OnSocketCreated(routing_id_, id_, address)); + message_sender_->Send(new P2PMsg_OnSocketCreated(routing_id_, id_, address)); return true; } @@ -70,7 +70,7 @@ void P2PSocketHostUdp::OnError() { socket_.reset(); if (state_ == STATE_UNINITIALIZED || state_ == STATE_OPEN) - host_->Send(new P2PMsg_OnError(routing_id_, id_)); + message_sender_->Send(new P2PMsg_OnError(routing_id_, id_)); state_ = STATE_ERROR; } @@ -96,15 +96,30 @@ void P2PSocketHostUdp::DidCompleteRead(int result) { if (result > 0) { std::vector<char> data(recv_buffer_->data(), recv_buffer_->data() + result); - host_->Send(new P2PMsg_OnDataReceived(routing_id_, id_, - recv_address_, data)); + + if (authorized_peers_.find(recv_address_) == authorized_peers_.end()) { + P2PSocketHost::StunMessageType type; + bool stun = GetStunPacketType(&*data.begin(), data.size(), &type); + if (stun && (type == STUN_BINDING_REQUEST || + type == STUN_BINDING_RESPONSE)) { + authorized_peers_.insert(recv_address_); + } else if (!stun || type == STUN_DATA_INDICATION) { + LOG(ERROR) << "Received unexpected data packet from " + << recv_address_.ToString() + << " before STUN binding is finished."; + return; + } + } + + message_sender_->Send(new P2PMsg_OnDataReceived(routing_id_, id_, + recv_address_, data)); } else if (result < 0 && result != net::ERR_IO_PENDING) { LOG(ERROR) << "Error when reading from UDP socket: " << result; OnError(); } } -void P2PSocketHostUdp::Send(const net::IPEndPoint& socket_address, +void P2PSocketHostUdp::Send(const net::IPEndPoint& to, const std::vector<char>& data) { if (send_pending_) { // Silently drop packet if previous send hasn't finished. @@ -112,10 +127,20 @@ void P2PSocketHostUdp::Send(const net::IPEndPoint& socket_address, return; } + if (authorized_peers_.find(to) == authorized_peers_.end()) { + P2PSocketHost::StunMessageType type; + bool stun = GetStunPacketType(&*data.begin(), data.size(), &type); + if (!stun || type == STUN_DATA_INDICATION) { + LOG(ERROR) << "Page tried to send a data packet to " << to.ToString() + << " before STUN binding is finished."; + OnError(); + return; + } + } + scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data.size()); memcpy(buffer->data(), &data.begin()[0], data.size()); - int result = socket_->SendTo(buffer, data.size(), socket_address, - &send_callback_); + int result = socket_->SendTo(buffer, data.size(), to, &send_callback_); if (result == net::ERR_IO_PENDING) { send_pending_ = true; } else if (result < 0) { diff --git a/content/browser/renderer_host/p2p_socket_host_udp.h b/content/browser/renderer_host/p2p_socket_host_udp.h index ba57427..2fd300e 100644 --- a/content/browser/renderer_host/p2p_socket_host_udp.h +++ b/content/browser/renderer_host/p2p_socket_host_udp.h @@ -5,29 +5,36 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_UDP_H_ #define CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_UDP_H_ -#include "content/common/p2p_sockets.h" +#include <set> #include "base/message_loop.h" #include "content/browser/renderer_host/p2p_socket_host.h" +#include "content/common/p2p_sockets.h" +#include "net/base/ip_endpoint.h" #include "net/udp/udp_server_socket.h" class P2PSocketHostUdp : public P2PSocketHost { public: - P2PSocketHostUdp(P2PSocketsHost* host, int routing_id, int id); + P2PSocketHostUdp(IPC::Message::Sender* message_sender, + int routing_id, int id); virtual ~P2PSocketHostUdp(); // P2PSocketHost overrides. virtual bool Init(const net::IPEndPoint& local_address) OVERRIDE; - virtual void Send(const net::IPEndPoint& socket_address, + virtual void Send(const net::IPEndPoint& to, const std::vector<char>& data) OVERRIDE; private: + friend class P2PSocketHostUdpTest; + enum State { STATE_UNINITIALIZED, STATE_OPEN, STATE_ERROR, }; + typedef std::set<net::IPEndPoint> AuthorizedPeerSet; + void OnError(); void DoRead(); void DidCompleteRead(int result); @@ -42,6 +49,10 @@ class P2PSocketHostUdp : public P2PSocketHost { net::IPEndPoint recv_address_; bool send_pending_; + // Set of peer for which we have received STUN binding request or + // response. + AuthorizedPeerSet authorized_peers_; + net::CompletionCallbackImpl<P2PSocketHostUdp> recv_callback_; net::CompletionCallbackImpl<P2PSocketHostUdp> send_callback_; diff --git a/content/browser/renderer_host/p2p_socket_host_udp_unittest.cc b/content/browser/renderer_host/p2p_socket_host_udp_unittest.cc new file mode 100644 index 0000000..4fa3fec --- /dev/null +++ b/content/browser/renderer_host/p2p_socket_host_udp_unittest.cc @@ -0,0 +1,300 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <winsock2.h> // for htonl +#else +#include <arpa/inet.h> +#endif + +#include <deque> +#include <vector> + +#include "content/browser/renderer_host/p2p_socket_host_udp.h" +#include "content/common/p2p_messages.h" +#include "net/base/io_buffer.h" +#include "net/base/ip_endpoint.h" +#include "net/base/net_errors.h" +#include "net/udp/datagram_server_socket.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; +using ::testing::DeleteArg; +using ::testing::DoAll; +using ::testing::Return; + +namespace { + +const char kTestLocalIpAddress[] = "123.44.22.4"; +const char kTestIpAddress1[] = "123.44.22.31"; +const int kTestPort1 = 234; +const char kTestIpAddress2[] = "133.11.22.33"; +const int kTestPort2 = 543; + +const int kStunHeaderSize = 20; +const uint16 kStunBindingRequest = 0x0001; +const uint16 kStunBindingResponse = 0x0102; +const uint16 kStunBindingError = 0x0111; +const uint32 kStunMagicCookie = 0x2112A442; + +class FakeDatagramServerSocket : public net::DatagramServerSocket { + public: + typedef std::pair<net::IPEndPoint, std::vector<char> > UDPPacket; + + // P2PSocketHostUdp destroyes a socket on errors so sent packets + // need to be stored outside of this object. + explicit FakeDatagramServerSocket(std::deque<UDPPacket>* sent_packets) + : sent_packets_(sent_packets), recv_callback_(NULL) { + } + + virtual void Close() OVERRIDE { + } + + virtual int GetPeerAddress(net::IPEndPoint* address) const OVERRIDE { + NOTREACHED(); + return net::ERR_SOCKET_NOT_CONNECTED; + } + + virtual int GetLocalAddress(net::IPEndPoint* address) const OVERRIDE { + *address = address_; + return 0; + } + + virtual int Listen(const net::IPEndPoint& address) OVERRIDE { + address_ = address; + return 0; + } + + virtual int RecvFrom(net::IOBuffer* buf, int buf_len, + net::IPEndPoint* address, + net::CompletionCallback* callback) OVERRIDE { + CHECK(!recv_callback_); + if (incoming_packets_.size() > 0) { + scoped_refptr<net::IOBuffer> buffer(buf); + int size = std::min( + static_cast<int>(incoming_packets_.front().second.size()), buf_len); + memcpy(buffer->data(), &*incoming_packets_.front().second.begin(), size); + *address = incoming_packets_.front().first; + incoming_packets_.pop_front(); + return size; + } else { + recv_callback_ = callback; + recv_buffer_ = buf; + recv_size_ = buf_len; + recv_address_ = address; + return net::ERR_IO_PENDING; + } + } + + virtual int SendTo(net::IOBuffer* buf, int buf_len, + const net::IPEndPoint& address, + net::CompletionCallback* callback) OVERRIDE { + scoped_refptr<net::IOBuffer> buffer(buf); + std::vector<char> data_vector(buffer->data(), buffer->data() + buf_len); + sent_packets_->push_back(UDPPacket(address, data_vector)); + return buf_len; + } + + void ReceivePacket(const net::IPEndPoint& address, std::vector<char> data) { + if (recv_callback_) { + int size = std::min(recv_size_, static_cast<int>(data.size())); + memcpy(recv_buffer_->data(), &*data.begin(), size); + *recv_address_ = address; + net::CompletionCallback* cb = recv_callback_; + recv_callback_ = NULL; + recv_buffer_ = NULL; + cb->Run(size); + } else { + incoming_packets_.push_back(UDPPacket(address, data)); + } + } + + private: + net::IPEndPoint address_; + std::deque<UDPPacket>* sent_packets_; + std::deque<UDPPacket> incoming_packets_; + + scoped_refptr<net::IOBuffer> recv_buffer_; + net::IPEndPoint* recv_address_; + int recv_size_; + net::CompletionCallback* recv_callback_; +}; + +class MockIPCSender : public IPC::Message::Sender { + public: + MOCK_METHOD1(Send, bool(IPC::Message* msg)); +}; + +MATCHER_P(MatchMessage, type, "") { + return arg->type() == type; +} + +} // namespace + +class P2PSocketHostUdpTest : public testing::Test { + protected: + void SetUp() OVERRIDE { + EXPECT_CALL(sender_, Send( + MatchMessage(static_cast<uint32>(P2PMsg_OnSocketCreated::ID)))) + .WillOnce(DoAll(DeleteArg<0>(), Return(true))); + + socket_host_.reset(new P2PSocketHostUdp(&sender_, 0, 0)); + socket_ = new FakeDatagramServerSocket(&sent_packets_); + socket_host_->socket_.reset(socket_); + + net::IPAddressNumber local_ip; + ASSERT_TRUE(net::ParseIPLiteralToNumber(kTestLocalIpAddress, &local_ip)); + local_address_ = net::IPEndPoint(local_ip, kTestPort1); + socket_host_->Init(local_address_); + + net::IPAddressNumber ip1; + ASSERT_TRUE(net::ParseIPLiteralToNumber(kTestIpAddress1, &ip1)); + dest1_ = net::IPEndPoint(ip1, kTestPort1); + net::IPAddressNumber ip2; + ASSERT_TRUE(net::ParseIPLiteralToNumber(kTestIpAddress2, &ip2)); + dest2_ = net::IPEndPoint(ip2, kTestPort2); + } + + void CreateRandomPacket(std::vector<char>* packet) { + size_t size = kStunHeaderSize + rand() % 1000; + packet->resize(size); + for (size_t i = 0; i < size; i++) { + (*packet)[i] = rand() % 256; + } + // Always set the first bit to ensure that generated packet is not + // valid STUN packet. + (*packet)[0] = (*packet)[0] | 0x80; + } + + void CreateStunPacket(std::vector<char>* packet, uint16 type) { + CreateRandomPacket(packet); + *reinterpret_cast<uint16*>(&*packet->begin()) = htons(type); + *reinterpret_cast<uint16*>(&*packet->begin() + 2) = + htons(packet->size() - kStunHeaderSize); + *reinterpret_cast<uint32*>(&*packet->begin() + 4) = htonl(kStunMagicCookie); + } + + void CreateStunRequest(std::vector<char>* packet) { + CreateStunPacket(packet, kStunBindingRequest); + } + + void CreateStunResponse(std::vector<char>* packet) { + CreateStunPacket(packet, kStunBindingResponse); + } + + void CreateStunError(std::vector<char>* packet) { + CreateStunPacket(packet, kStunBindingError); + } + + std::deque<FakeDatagramServerSocket::UDPPacket> sent_packets_; + FakeDatagramServerSocket* socket_; // Owned by |socket_host_|. + scoped_ptr<P2PSocketHostUdp> socket_host_; + MockIPCSender sender_; + + net::IPEndPoint local_address_; + + net::IPEndPoint dest1_; + net::IPEndPoint dest2_; +}; + +// Verify that we can send STUN messages before we receive anything +// from the other side. +TEST_F(P2PSocketHostUdpTest, SendStunNoAuth) { + std::vector<char> packet1; + CreateStunRequest(&packet1); + socket_host_->Send(dest1_, packet1); + + std::vector<char> packet2; + CreateStunResponse(&packet2); + socket_host_->Send(dest1_, packet2); + + std::vector<char> packet3; + CreateStunError(&packet3); + socket_host_->Send(dest1_, packet3); + + ASSERT_EQ(sent_packets_.size(), 3U); + ASSERT_EQ(sent_packets_[0].second, packet1); + ASSERT_EQ(sent_packets_[1].second, packet2); + ASSERT_EQ(sent_packets_[2].second, packet3); +} + +// Verify that no data packets can be sent before STUN binding has +// finished. +TEST_F(P2PSocketHostUdpTest, SendDataNoAuth) { + EXPECT_CALL(sender_, Send( + MatchMessage(static_cast<uint32>(P2PMsg_OnError::ID)))) + .WillOnce(DoAll(DeleteArg<0>(), Return(true))); + + std::vector<char> packet; + CreateRandomPacket(&packet); + socket_host_->Send(dest1_, packet); + + ASSERT_EQ(sent_packets_.size(), 0U); +} + +// Verify that we can send data after we've received STUN request +// from the other side. +TEST_F(P2PSocketHostUdpTest, SendAfterStunRequest) { + EXPECT_CALL(sender_, Send( + MatchMessage(static_cast<uint32>(P2PMsg_OnDataReceived::ID)))) + .WillOnce(DoAll(DeleteArg<0>(), Return(true))); + + // Receive packet from |dest1_|. + std::vector<char> request_packet; + CreateStunRequest(&request_packet); + socket_->ReceivePacket(dest1_, request_packet); + + // Now we should be able to send any data to |dest1_|. + std::vector<char> packet; + CreateRandomPacket(&packet); + socket_host_->Send(dest1_, packet); + + ASSERT_EQ(1U, sent_packets_.size()); + ASSERT_EQ(dest1_, sent_packets_[0].first); +} + +// Verify that we can send data after we've received STUN response +// from the other side. +TEST_F(P2PSocketHostUdpTest, SendAfterStunResponse) { + EXPECT_CALL(sender_, Send( + MatchMessage(static_cast<uint32>(P2PMsg_OnDataReceived::ID)))) + .WillOnce(DoAll(DeleteArg<0>(), Return(true))); + + // Receive packet from |dest1_|. + std::vector<char> request_packet; + CreateStunRequest(&request_packet); + socket_->ReceivePacket(dest1_, request_packet); + + // Now we should be able to send any data to |dest1_|. + std::vector<char> packet; + CreateRandomPacket(&packet); + socket_host_->Send(dest1_, packet); + + ASSERT_EQ(1U, sent_packets_.size()); + ASSERT_EQ(dest1_, sent_packets_[0].first); +} + +// Verify messages still cannot be sent to an unathorized host after +// successful binding with different host. +TEST_F(P2PSocketHostUdpTest, SendAfterStunResponseDifferentHost) { + EXPECT_CALL(sender_, Send( + MatchMessage(static_cast<uint32>(P2PMsg_OnDataReceived::ID)))) + .WillOnce(DoAll(DeleteArg<0>(), Return(true))); + + // Receive packet from |dest1_|. + std::vector<char> request_packet; + CreateStunRequest(&request_packet); + socket_->ReceivePacket(dest1_, request_packet); + + // Should fail when trying to send the same packet to |dest2_|. + std::vector<char> packet; + CreateRandomPacket(&packet); + EXPECT_CALL(sender_, Send( + MatchMessage(static_cast<uint32>(P2PMsg_OnError::ID)))) + .WillOnce(DoAll(DeleteArg<0>(), Return(true))); + socket_host_->Send(dest2_, packet); +} |