Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(949)

Unified Diff: content/browser/renderer_host/p2p_socket_host_udp_unittest.cc

Issue 6800023: Security restrictions for P2P UDP Sockets. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: - Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/p2p_socket_host_udp_unittest.cc
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 0000000000000000000000000000000000000000..b8e25ddbae8efa15a9050fc1345a4e7609455123
--- /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/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 "content/browser/renderer_host/p2p_socket_host_udp.h"
jam 2011/04/08 23:38:57 nit: should move up
Sergey Ulanov 2011/04/09 00:52:36 Done.
+#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);
+}

Powered by Google App Engine
This is Rietveld 408576698