Be able to access proxy client IP (including Lua)
authorJonathan Frank <jfrank@fb.com>
Fri, 13 Feb 2015 17:59:56 +0000 (09:59 -0800)
committerAlecs King <int@fb.com>
Tue, 3 Mar 2015 03:19:25 +0000 (19:19 -0800)
Summary:
Pass TransportInfo object through connection setup.  This allows us to
pass along additional info from the setup if necessary.

Test Plan:
Run proxygen on my devserver listening on ipv4 and ipv6 for ports 80 and 443.
Configure it to run a lua request rule with the following lines:

io.stderr:write("jonlog: proxy " .. conn:getClientAddrOriginal() .. "\n")
io.stderr:write("jonlog: client " .. request:getClientIPStr() .. "\n")

Run haproxy also on my devserver, listening on ports 8555-8558, with each
forwarding to one of the four pairs (ipv4-localhost/ipv6-localhost, 80/443)

From my laptop, run curls against each of these four endpoints and make
sure that we print out "127.0.0.1" as the proxy IP, and my laptop's IP
as the client IP.

Reviewed By: cgheorghe@fb.com

Subscribers: jsedgwick, yfeldblum, trunkagent, ruibalp, bmatheny, folly-diffs@, dsp, nbm

FB internal diff: D1746590

Tasks: 5688127

Signature: t1:1746590:1423695880:f647964d95636a69a00304e144aef71ee0213d28

folly/wangle/acceptor/Acceptor.cpp
folly/wangle/acceptor/Acceptor.h
folly/wangle/acceptor/TransportInfo.h

index 010022cee828561a0d27f132679e42a20cd735bd..9345fb0720483f2fd3b62778f8e00faa35a9d64d 100644 (file)
@@ -57,9 +57,11 @@ class AcceptorHandshakeHelper :
   AcceptorHandshakeHelper(AsyncSSLSocket::UniquePtr socket,
                           Acceptor* acceptor,
                           const SocketAddress& clientAddr,
-                          std::chrono::steady_clock::time_point acceptTime)
+                          std::chrono::steady_clock::time_point acceptTime,
+                          TransportInfo& tinfo)
     : socket_(std::move(socket)), acceptor_(acceptor),
-      acceptTime_(acceptTime), clientAddr_(clientAddr) {
+      acceptTime_(acceptTime), clientAddr_(clientAddr),
+      tinfo_(tinfo) {
     acceptor_->downstreamConnectionManager_->addConnection(this, true);
     if(acceptor_->parseClientHello_)  {
       socket_->enableClientHelloParsing();
@@ -106,36 +108,41 @@ class AcceptorHandshakeHelper :
 
     // fill in SSL-related fields from TransportInfo
     // the other fields like RTT are filled in the Acceptor
-    TransportInfo tinfo;
-    tinfo.ssl = true;
-    tinfo.acceptTime = acceptTime_;
-    tinfo.sslSetupTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - acceptTime_);
-    tinfo.sslSetupBytesRead = sock->getRawBytesReceived();
-    tinfo.sslSetupBytesWritten = sock->getRawBytesWritten();
-    tinfo.sslServerName = sock->getSSLServerName() ?
+    tinfo_.ssl = true;
+    tinfo_.acceptTime = acceptTime_;
+    tinfo_.sslSetupTime = std::chrono::duration_cast<std::chrono::milliseconds>(
+      std::chrono::steady_clock::now() - acceptTime_
+    );
+    tinfo_.sslSetupBytesRead = sock->getRawBytesReceived();
+    tinfo_.sslSetupBytesWritten = sock->getRawBytesWritten();
+    tinfo_.sslServerName = sock->getSSLServerName() ?
       std::make_shared<std::string>(sock->getSSLServerName()) : nullptr;
-    tinfo.sslCipher = sock->getNegotiatedCipherName() ?
+    tinfo_.sslCipher = sock->getNegotiatedCipherName() ?
       std::make_shared<std::string>(sock->getNegotiatedCipherName()) : nullptr;
-    tinfo.sslVersion = sock->getSSLVersion();
-    tinfo.sslCertSize = sock->getSSLCertSize();
-    tinfo.sslResume = SSLUtil::getResumeState(sock);
-    tinfo.sslClientCiphers = std::make_shared<std::string>();
-    sock->getSSLClientCiphers(*tinfo.sslClientCiphers);
-    tinfo.sslServerCiphers = std::make_shared<std::string>();
-    sock->getSSLServerCiphers(*tinfo.sslServerCiphers);
-    tinfo.sslClientComprMethods =
+    tinfo_.sslVersion = sock->getSSLVersion();
+    tinfo_.sslCertSize = sock->getSSLCertSize();
+    tinfo_.sslResume = SSLUtil::getResumeState(sock);
+    tinfo_.sslClientCiphers = std::make_shared<std::string>();
+    sock->getSSLClientCiphers(*tinfo_.sslClientCiphers);
+    tinfo_.sslServerCiphers = std::make_shared<std::string>();
+    sock->getSSLServerCiphers(*tinfo_.sslServerCiphers);
+    tinfo_.sslClientComprMethods =
         std::make_shared<std::string>(sock->getSSLClientComprMethods());
-    tinfo.sslClientExts =
+    tinfo_.sslClientExts =
         std::make_shared<std::string>(sock->getSSLClientExts());
-    tinfo.sslNextProtocol = std::make_shared<std::string>();
-    tinfo.sslNextProtocol->assign(reinterpret_cast<const char*>(nextProto),
+    tinfo_.sslNextProtocol = std::make_shared<std::string>();
+    tinfo_.sslNextProtocol->assign(reinterpret_cast<const char*>(nextProto),
                                   nextProtoLength);
 
-    acceptor_->updateSSLStats(sock, tinfo.sslSetupTime, SSLErrorEnum::NO_ERROR);
+    acceptor_->updateSSLStats(
+      sock,
+      tinfo_.sslSetupTime,
+      SSLErrorEnum::NO_ERROR
+    );
     acceptor_->downstreamConnectionManager_->removeConnection(this);
     acceptor_->sslConnectionReady(std::move(socket_), clientAddr_,
         nextProto ? string((const char*)nextProto, nextProtoLength) :
-                                  empty_string, tinfo);
+                                  empty_string, tinfo_);
     delete this;
   }
 
@@ -155,6 +162,7 @@ class AcceptorHandshakeHelper :
   Acceptor* acceptor_;
   std::chrono::steady_clock::time_point acceptTime_;
   SocketAddress clientAddr_;
+  TransportInfo tinfo_;
   SSLErrorEnum sslError_{SSLErrorEnum::NO_ERROR};
 };
 
@@ -281,14 +289,16 @@ void Acceptor::onDoneAcceptingConnection(
     int fd,
     const SocketAddress& clientAddr,
     std::chrono::steady_clock::time_point acceptTime) noexcept {
-  processEstablishedConnection(fd, clientAddr, acceptTime);
+  TransportInfo tinfo;
+  processEstablishedConnection(fd, clientAddr, acceptTime, tinfo);
 }
 
 void
 Acceptor::processEstablishedConnection(
     int fd,
     const SocketAddress& clientAddr,
-    std::chrono::steady_clock::time_point acceptTime) noexcept {
+    std::chrono::steady_clock::time_point acceptTime,
+    TransportInfo& tinfo) noexcept {
   if (accConfig_.isSSL()) {
     CHECK(sslCtxManager_);
     AsyncSSLSocket::UniquePtr sslSock(
@@ -305,9 +315,13 @@ Acceptor::processEstablishedConnection(
       return;
     }
     new AcceptorHandshakeHelper(
-      std::move(sslSock), this, clientAddr, acceptTime);
+      std::move(sslSock),
+      this,
+      clientAddr,
+      acceptTime,
+      tinfo
+    );
   } else {
-    TransportInfo tinfo;
     tinfo.ssl = false;
     tinfo.acceptTime = acceptTime;
     AsyncSocket::UniquePtr sock(makeNewAsyncSocket(base_, fd));
index 23d8ee022e180aafe99b77fc1fde8567e5c5f37b..22c467197ac68fb1ffe514938bffcfad8328c556 100644 (file)
@@ -170,7 +170,8 @@ class Acceptor :
   void processEstablishedConnection(
     int fd,
     const SocketAddress& clientAddr,
-    std::chrono::steady_clock::time_point acceptTime
+    std::chrono::steady_clock::time_point acceptTime,
+    TransportInfo& tinfo
   ) noexcept;
 
   /**
index c02bac42fbbc5c22f1c062e459641af6507ee4b0..a3b99ca1a08558e39df1667ef3b56f6d5e5cf0f3 100644 (file)
@@ -123,6 +123,12 @@ struct TransportInfo {
    */
   int64_t totalBytes{0};
 
+  /**
+   * If the client passed through one of our L4 proxies (using PROXY Protocol),
+   * then this will contain the IP address of the proxy host.
+   */
+  std::shared_ptr<folly::SocketAddress> clientAddrOriginal;
+
   /**
    * header bytes read
    */