shill: Enable and disable reverse-path filtering

When an http proxy request is active (as well as portal check, when
that gets written), we need to initiate connections over a non-default
network interface.  For this we temporarily disable reverse-path
filtering on the interface during the duration of the request.

BUG=chromium-os:24141
TEST=New unit tests for HTTPProxy and Connection

Change-Id: Ife2ad775fd8a3d2fb48f860e804eeb442dc5c58a
Reviewed-on: https://gerrit.chromium.org/gerrit/12889
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Commit-Ready: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/http_proxy_unittest.cc b/http_proxy_unittest.cc
index 07e9cb7..d7f4ddb 100644
--- a/http_proxy_unittest.cc
+++ b/http_proxy_unittest.cc
@@ -14,6 +14,9 @@
 
 #include "shill/ip_address.h"
 #include "shill/mock_async_connection.h"
+#include "shill/mock_connection.h"
+#include "shill/mock_control.h"
+#include "shill/mock_device_info.h"
 #include "shill/mock_dns_client.h"
 #include "shill/mock_event_dispatcher.h"
 #include "shill/mock_sockets.h"
@@ -25,6 +28,7 @@
 using ::testing::AtLeast;
 using ::testing::DoAll;
 using ::testing::Invoke;
+using ::testing::NiceMock;
 using ::testing::Return;
 using ::testing::ReturnArg;
 using ::testing::ReturnNew;
@@ -82,11 +86,23 @@
 class HTTPProxyTest : public Test {
  public:
   HTTPProxyTest()
-      : server_async_connection_(NULL),
+      : interface_name_(kInterfaceName),
+        server_async_connection_(NULL),
         dns_servers_(kDNSServers, kDNSServers + 2),
         dns_client_(NULL),
-        proxy_(kInterfaceName, dns_servers_) { }
+        device_info_(new NiceMock<MockDeviceInfo>(
+            &control_,
+            reinterpret_cast<EventDispatcher*>(NULL),
+            reinterpret_cast<Manager*>(NULL))),
+        connection_(new StrictMock<MockConnection>(device_info_.get())),
+        proxy_(connection_) { }
  protected:
+  virtual void SetUp() {
+    EXPECT_CALL(*connection_.get(), interface_name())
+        .WillRepeatedly(ReturnRef(interface_name_));
+    EXPECT_CALL(*connection_.get(), dns_servers())
+        .WillRepeatedly(ReturnRef(dns_servers_));
+  }
   virtual void TearDown() {
     if (proxy_.sockets_) {
       ExpectStop();
@@ -152,9 +168,11 @@
     EXPECT_FALSE(proxy_.write_client_handler_.get());
     EXPECT_FALSE(proxy_.read_server_handler_.get());
     EXPECT_FALSE(proxy_.write_server_handler_.get());
+    EXPECT_FALSE(proxy_.is_route_requested_);
   }
   void ExpectReset() {
     EXPECT_FALSE(proxy_.accept_handler_.get());
+    EXPECT_EQ(proxy_.connection_.get(), connection_.get());
     EXPECT_FALSE(proxy_.dispatcher_);
     EXPECT_FALSE(proxy_.dns_client_.get());
     EXPECT_EQ(-1, proxy_.proxy_port_);
@@ -189,6 +207,9 @@
        EXPECT_CALL(*server_async_connection_, Stop())
            .Times(AtLeast(1));
      }
+     if (proxy_.is_route_requested_) {
+       EXPECT_CALL(*connection_.get(), ReleaseRouting());
+     }
    }
    void ExpectClientInput(int fd) {
     EXPECT_CALL(sockets(), Accept(kProxyFD, _, _))
@@ -291,7 +312,6 @@
         .WillOnce(ReturnNew<IOHandler>());
     ExpectRepeatedInputTimeout();
   }
-
   void ExpectTunnelClose() {
     EXPECT_CALL(sockets(), Close(kClientFD))
         .WillOnce(Return(0));
@@ -299,6 +319,12 @@
         .WillOnce(Return(0));
     ExpectStop();
   }
+  void ExpectRouteRequest() {
+    EXPECT_CALL(*connection_.get(), RequestRouting());
+  }
+  void ExpectRouteRelease() {
+    EXPECT_CALL(*connection_.get(), ReleaseRouting());
+  }
 
   // Callers for various private routines in the proxy
   bool StartProxy() {
@@ -369,6 +395,7 @@
   void SetupConnectWithRequest(const string &url, const string &http_version,
                                const string &extra_lines) {
     ExpectDNSRequest("www.chromium.org", true);
+    ExpectRouteRequest();
     ReadFromClient(CreateRequest(url, http_version, extra_lines));
     IPAddress addr(IPAddress::kFamilyIPv4);
     EXPECT_TRUE(addr.SetAddressFromString(kServerAddress));
@@ -393,12 +420,16 @@
   }
 
  private:
+  const string interface_name_;
   // Owned by the HTTPProxy, but tracked here for EXPECT().
   StrictMock<MockAsyncConnection> *server_async_connection_;
   vector<string> dns_servers_;
   // Owned by the HTTPProxy, but tracked here for EXPECT().
   StrictMock<MockDNSClient> *dns_client_;
   MockEventDispatcher dispatcher_;
+  MockControl control_;
+  scoped_ptr<MockDeviceInfo> device_info_;
+  scoped_refptr<MockConnection> connection_;
   HTTPProxy proxy_;
   StrictMock<MockSockets> sockets_;
 };
@@ -553,6 +584,7 @@
 
 TEST_F(HTTPProxyTest, DNSRequestFailure) {
   SetupClient();
+  ExpectRouteRequest();
   ExpectDNSRequest("www.chromium.org", false);
   ExpectClientResult();
   ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
@@ -561,6 +593,7 @@
 
 TEST_F(HTTPProxyTest, DNSRequestDelayedFailure) {
   SetupClient();
+  ExpectRouteRequest();
   ExpectDNSRequest("www.chromium.org", true);
   ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506"));
   ExpectClientResult();
@@ -573,6 +606,7 @@
 
 TEST_F(HTTPProxyTest, TrailingClientData) {
   SetupClient();
+  ExpectRouteRequest();
   ExpectDNSRequest("www.chromium.org", true);
   const string trailing_data("Trailing client data");
   ReadFromClient(CreateRequest("/", "1.1", "Host: www.chromium.org:40506") +
@@ -584,6 +618,7 @@
 
 TEST_F(HTTPProxyTest, LineContinuation) {
   SetupClient();
+  ExpectRouteRequest();
   ExpectDNSRequest("www.chromium.org", true);
   string text_to_keep("X-Long-Header: this is one line\r\n"
                       "\tand this is another");
@@ -598,6 +633,7 @@
 //      continuation.
 TEST_F(HTTPProxyTest, LineContinuationRemoval) {
   SetupClient();
+  ExpectRouteRequest();
   ExpectDNSRequest("www.chromium.org", true);
   string text_to_remove("remove this text please");
   ReadFromClient(CreateRequest("http://www.chromium.org/", "1.1",
@@ -634,6 +670,7 @@
   SetupClient();
   ExpectSyncConnect(kServerAddress, 999);
   ExpectRepeatedServerOutput();
+  ExpectRouteRequest();
   ReadFromClient(CreateRequest("/", "1.1",
                                StringPrintf("Host: %s:999", kServerAddress)));
   EXPECT_EQ(HTTPProxy::kStateTunnelData, GetProxyState());
@@ -730,6 +767,7 @@
       .WillOnce(Return(0));
   EXPECT_CALL(sockets(), Close(kServerFD))
       .WillOnce(Return(0));
+  ExpectRouteRelease();
   StopClient();
   ExpectClientReset();
   EXPECT_EQ(HTTPProxy::kStateWaitConnection, GetProxyState());