diff options
author | agayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-29 03:47:04 +0000 |
---|---|---|
committer | agayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-29 03:47:04 +0000 |
commit | 5370c013eb6372dbffe91de3fde793da6b74e4e1 (patch) | |
tree | f4a14d0380e1c673c1e0d54f75a192fc1b504b9e /net/udp/udp_socket_unittest.cc | |
parent | 034bda715a6756a9b07de1fe9db9ceb6caf73123 (diff) | |
download | chromium_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.cc | 97 |
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 |