summaryrefslogtreecommitdiffstats
path: root/net/udp/udp_socket_unittest.cc
diff options
context:
space:
mode:
authoragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-29 03:47:04 +0000
committeragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-29 03:47:04 +0000
commit5370c013eb6372dbffe91de3fde793da6b74e4e1 (patch)
treef4a14d0380e1c673c1e0d54f75a192fc1b504b9e /net/udp/udp_socket_unittest.cc
parent034bda715a6756a9b07de1fe9db9ceb6caf73123 (diff)
downloadchromium_src-5370c013eb6372dbffe91de3fde793da6b74e4e1.zip
chromium_src-5370c013eb6372dbffe91de3fde793da6b74e4e1.tar.gz
chromium_src-5370c013eb6372dbffe91de3fde793da6b74e4e1.tar.bz2
Add support for random UDP source port selection to avoid birthday attacks in DNS implementation.
BUG=60149 TEST=net_unittests Review URL: http://codereview.chromium.org/7202011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90925 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/udp/udp_socket_unittest.cc')
-rw-r--r--net/udp/udp_socket_unittest.cc97
1 files changed, 94 insertions, 3 deletions
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc
index 459b35d..9fe870f 100644
--- a/net/udp/udp_socket_unittest.cc
+++ b/net/udp/udp_socket_unittest.cc
@@ -6,7 +6,10 @@
#include "net/udp/udp_server_socket.h"
#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
#include "base/metrics/histogram.h"
+#include "base/stl_util-inl.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
@@ -136,7 +139,10 @@ TEST_F(UDPSocketTest, Connect) {
// Setup the client.
IPEndPoint server_address;
CreateUDPAddress("127.0.0.1", kPort, &server_address);
- UDPClientSocket client(NULL, NetLog::Source());
+ UDPClientSocket client(DatagramSocket::DEFAULT_BIND,
+ RandIntCallback(),
+ NULL,
+ NetLog::Source());
rv = client.Connect(server_address);
EXPECT_EQ(OK, rv);
@@ -157,6 +163,85 @@ TEST_F(UDPSocketTest, Connect) {
DCHECK(simple_message == str);
}
+// In this test, we verify that random binding logic works, which attempts
+// to bind to a random port and returns if succeeds, otherwise retries for
+// |kBindRetries| number of times.
+
+// To generate the scenario, we first create |kBindRetries| number of
+// UDPClientSockets with default binding policy and connect to the same
+// peer and save the used port numbers. Then we get rid of the last
+// socket, making sure that the local port it was bound to is available.
+// Finally, we create a socket with random binding policy, passing it a
+// test PRNG that would serve used port numbers in the array, one after
+// another. At the end, we make sure that the test socket was bound to the
+// port that became available after deleting the last socket with default
+// binding policy.
+
+// We do not test the randomness of bound ports, but that we are using
+// passed in PRNG correctly, thus, it's the duty of PRNG to produce strong
+// random numbers.
+static const int kBindRetries = 10;
+
+class TestPrng {
+ public:
+ explicit TestPrng(const std::deque<int>& numbers) : numbers_(numbers) {}
+ int GetNext(int /* min */, int /* max */) {
+ DCHECK(!numbers_.empty());
+ int rv = numbers_.front();
+ numbers_.pop_front();
+ return rv;
+ }
+ private:
+ std::deque<int> numbers_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestPrng);
+};
+
+TEST_F(UDPSocketTest, ConnectRandomBind) {
+ std::vector<UDPClientSocket*> sockets;
+ IPEndPoint peer_address;
+ CreateUDPAddress("192.168.1.13", 53, &peer_address);
+
+ // Create and connect sockets and save port numbers.
+ std::deque<int> used_ports;
+ for (int i = 0; i < kBindRetries; ++i) {
+ UDPClientSocket* socket =
+ new UDPClientSocket(DatagramSocket::DEFAULT_BIND,
+ RandIntCallback(),
+ NULL,
+ NetLog::Source());
+ sockets.push_back(socket);
+ EXPECT_EQ(OK, socket->Connect(peer_address));
+
+ IPEndPoint client_address;
+ EXPECT_EQ(OK, socket->GetLocalAddress(&client_address));
+ used_ports.push_back(client_address.port());
+ }
+
+ // Free the last socket, its local port is still in |used_ports|.
+ delete sockets.back();
+ sockets.pop_back();
+
+ TestPrng test_prng(used_ports);
+ RandIntCallback rand_int_cb =
+ base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
+
+ // Create a socket with random binding policy and connect.
+ scoped_ptr<UDPClientSocket> test_socket(
+ new UDPClientSocket(DatagramSocket::RANDOM_BIND,
+ rand_int_cb,
+ NULL,
+ NetLog::Source()));
+ EXPECT_EQ(OK, test_socket->Connect(peer_address));
+
+ // Make sure that the last port number in the |used_ports| was used.
+ IPEndPoint client_address;
+ EXPECT_EQ(OK, test_socket->GetLocalAddress(&client_address));
+ EXPECT_EQ(used_ports.back(), client_address.port());
+
+ STLDeleteElements(&sockets);
+}
+
// In this test, we verify that connect() on a socket will have the effect
// of filtering reads on this socket only to data read from the destination
// we connected to.
@@ -187,7 +272,10 @@ TEST_F(UDPSocketTest, VerifyConnectBindsAddr) {
// Setup the client, connected to server 1.
IPEndPoint server_address;
CreateUDPAddress("127.0.0.1", kPort1, &server_address);
- UDPClientSocket client(NULL, NetLog::Source());
+ UDPClientSocket client(DatagramSocket::DEFAULT_BIND,
+ RandIntCallback(),
+ NULL,
+ NetLog::Source());
rv = client.Connect(server_address);
EXPECT_EQ(OK, rv);
@@ -240,7 +328,10 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
net::ParseIPLiteralToNumber(tests[i].local_address, &ip_number);
net::IPEndPoint local_address(ip_number, 80);
- UDPClientSocket client(NULL, NetLog::Source());
+ UDPClientSocket client(DatagramSocket::DEFAULT_BIND,
+ RandIntCallback(),
+ NULL,
+ NetLog::Source());
int rv = client.Connect(remote_address);
if (tests[i].may_fail && rv == ERR_ADDRESS_UNREACHABLE) {
// Connect() may return ERR_ADDRESS_UNREACHABLE for IPv6