| Index: webrtc/p2p/base/turnport_unittest.cc
|
| diff --git a/webrtc/p2p/base/turnport_unittest.cc b/webrtc/p2p/base/turnport_unittest.cc
|
| index edb345447bf592187f7da4857ff823cd7ec9039d..a8153eed268a8ec851bb0a213b7453fc4f251f4e 100644
|
| --- a/webrtc/p2p/base/turnport_unittest.cc
|
| +++ b/webrtc/p2p/base/turnport_unittest.cc
|
| @@ -29,6 +29,7 @@
|
| #include "webrtc/base/helpers.h"
|
| #include "webrtc/base/logging.h"
|
| #include "webrtc/base/physicalsocketserver.h"
|
| +#include "webrtc/base/socketadapters.h"
|
| #include "webrtc/base/socketaddress.h"
|
| #include "webrtc/base/ssladapter.h"
|
| #include "webrtc/base/thread.h"
|
| @@ -441,6 +442,57 @@ class TurnPortTest : public testing::Test,
|
| ASSERT_EQ(0U, turn_port_->Candidates().size());
|
| }
|
|
|
| + // A certain security exploit works by redirecting to a loopback address,
|
| + // which doesn't ever actually make sense. So redirects to loopback should
|
| + // be treated as errors.
|
| + // See: https://bugs.chromium.org/p/chromium/issues/detail?id=649118
|
| + void TestTurnAlternateServerLoopback(ProtocolType protocol_type, bool ipv6) {
|
| + const SocketAddress& local_address = ipv6 ? kLocalIPv6Addr : kLocalAddr1;
|
| + const SocketAddress& server_address =
|
| + ipv6 ? kTurnIPv6IntAddr : kTurnIntAddr;
|
| +
|
| + std::vector<rtc::SocketAddress> redirect_addresses;
|
| + SocketAddress loopback_address(ipv6 ? "::1" : "127.0.0.1",
|
| + TURN_SERVER_PORT);
|
| + redirect_addresses.push_back(loopback_address);
|
| +
|
| + // Make a socket and bind it to the local port, to make extra sure no
|
| + // packet is sent to this address.
|
| + std::unique_ptr<rtc::Socket> loopback_socket(ss_->CreateSocket(
|
| + protocol_type == PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM));
|
| + ASSERT_NE(nullptr, loopback_socket.get());
|
| + ASSERT_EQ(0, loopback_socket->Bind(loopback_address));
|
| + if (protocol_type == PROTO_TCP) {
|
| + ASSERT_EQ(0, loopback_socket->Listen(1));
|
| + }
|
| +
|
| + TestTurnRedirector redirector(redirect_addresses);
|
| +
|
| + turn_server_.AddInternalSocket(server_address, protocol_type);
|
| + turn_server_.set_redirect_hook(&redirector);
|
| + CreateTurnPort(local_address, kTurnUsername, kTurnPassword,
|
| + ProtocolAddress(server_address, protocol_type));
|
| +
|
| + turn_port_->PrepareAddress();
|
| + EXPECT_TRUE_SIMULATED_WAIT(
|
| + turn_error_,
|
| + (protocol_type == PROTO_TCP ? kSimulatedRtt * 3 : kSimulatedRtt * 2),
|
| + fake_clock_);
|
| +
|
| + // Wait for some extra time, and make sure no packets were received on the
|
| + // loopback port we created (or in the case of TCP, no connection attempt
|
| + // occurred).
|
| + SIMULATED_WAIT(false, kSimulatedRtt, fake_clock_);
|
| + if (protocol_type == PROTO_UDP) {
|
| + char buf[1];
|
| + EXPECT_EQ(-1, loopback_socket->Recv(&buf, 1, nullptr));
|
| + } else {
|
| + std::unique_ptr<rtc::Socket> accepted_socket(
|
| + loopback_socket->Accept(nullptr));
|
| + EXPECT_EQ(nullptr, accepted_socket.get());
|
| + }
|
| + }
|
| +
|
| void TestTurnConnection(ProtocolType protocol_type) {
|
| // Create ports and prepare addresses.
|
| PrepareTurnAndUdpPorts(protocol_type);
|
| @@ -917,6 +969,23 @@ TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetitionTCP) {
|
| TestTurnAlternateServerDetectRepetition(PROTO_TCP);
|
| }
|
|
|
| +// Test catching the case of a redirect to loopback.
|
| +TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackUdpIpv4) {
|
| + TestTurnAlternateServerLoopback(PROTO_UDP, false);
|
| +}
|
| +
|
| +TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackUdpIpv6) {
|
| + TestTurnAlternateServerLoopback(PROTO_UDP, true);
|
| +}
|
| +
|
| +TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackTcpIpv4) {
|
| + TestTurnAlternateServerLoopback(PROTO_TCP, false);
|
| +}
|
| +
|
| +TEST_F(TurnPortTest, TestTurnAlternateServerLoopbackTcpIpv6) {
|
| + TestTurnAlternateServerLoopback(PROTO_TCP, true);
|
| +}
|
| +
|
| // Do a TURN allocation and try to send a packet to it from the outside.
|
| // The packet should be dropped. Then, try to send a packet from TURN to the
|
| // outside. It should reach its destination. Finally, try again from the
|
|
|