This is an automated email from the ASF dual-hosted git repository.

cmcfarlen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new dbff9defea Use ProxyProtocol SRC IP as Client IP (#12761)
dbff9defea is described below

commit dbff9defeaa589c89da3c7ad78238789ba9de9ef
Author: Chris McFarlen <[email protected]>
AuthorDate: Fri Jan 9 12:02:57 2026 -0600

    Use ProxyProtocol SRC IP as Client IP (#12761)
    
    * Restore old feature to copy PP src IP to remote ip of NetVConn, but this 
time the copy is configurable.  Expand autest to cover new setup
    Introduce get_client_addr to NetVConn, implement rchi log field, improve 
proxy protocol autests.
    
    * Use get_client_addr in some places it might matter.
    
    * rename get_client_addr to get_effective_remote_addr
    
    * PR fixes
---
 .../configuration/proxy-protocol.en.rst            |  3 ++
 doc/admin-guide/files/records.yaml.en.rst          |  1 +
 doc/admin-guide/logging/formatting.en.rst          |  8 ++--
 include/iocore/net/AcceptOptions.h                 |  3 +-
 include/iocore/net/NetVConnection.h                | 48 ++++++++++++++++++++--
 include/proxy/ProxySession.h                       |  3 ++
 include/proxy/ProxyTransaction.h                   | 17 ++++++++
 include/proxy/logging/LogAccess.h                  |  2 +
 include/records/RecHttp.h                          | 41 +++++++++---------
 include/ts/ts.h                                    |  1 +
 src/api/InkAPI.cc                                  | 10 ++++-
 src/iocore/net/SNIActionPerformer.cc               |  2 +-
 src/iocore/net/SSLClientUtils.cc                   |  8 ++--
 src/iocore/net/SSLDiags.cc                         |  2 +-
 src/iocore/net/SSLNetVConnection.cc                |  6 +--
 src/iocore/net/Server.cc                           |  6 ++-
 src/iocore/net/UnixNetAccept.cc                    |  6 +--
 src/proxy/ProxySession.cc                          | 13 ++++++
 src/proxy/http/HttpProxyServerMain.cc              | 11 ++---
 src/proxy/http2/Http2SessionAccept.cc              |  2 +-
 src/proxy/logging/Log.cc                           | 15 +++++++
 src/proxy/logging/LogAccess.cc                     | 30 +++++++++++++-
 src/records/RecHttp.cc                             | 35 +++++++++-------
 .../gold_tests/autest-site/trafficserver.test.ext  | 10 +++--
 .../gold_tests/proxy_protocol/gold/access-cp.gold  |  7 ++++
 .../proxy_protocol/gold/access-nocp.gold           |  7 ++++
 tests/gold_tests/proxy_protocol/gold/access.gold   |  7 ----
 .../proxy_protocol/proxy_protocol.test.py          | 35 +++++++++-------
 28 files changed, 253 insertions(+), 86 deletions(-)

diff --git a/doc/admin-guide/configuration/proxy-protocol.en.rst 
b/doc/admin-guide/configuration/proxy-protocol.en.rst
index 9aea649e35..4263d9e771 100644
--- a/doc/admin-guide/configuration/proxy-protocol.en.rst
+++ b/doc/admin-guide/configuration/proxy-protocol.en.rst
@@ -56,6 +56,9 @@ By default, |TS| uses client's IP address that is from the 
peer when it applies
 enable PROXY protocol and want to apply ACL against the IP address delivered 
by PROXY protocol, you need to have ``PROXY`` in
 :ts:cv:`proxy.config.acl.subjects`.
 
+If you specify the server_ports flag `pp-clnt` then the client IP address used 
for the
+transaction will be the one provided by proxy protocol.
+
 1. HTTP Forwarded Header
 
 The client IP address in the PROXY protocol header is passed to the origin 
server via an HTTP `Forwarded:
diff --git a/doc/admin-guide/files/records.yaml.en.rst 
b/doc/admin-guide/files/records.yaml.en.rst
index 360cfc5fc0..2221d4ceee 100644
--- a/doc/admin-guide/files/records.yaml.en.rst
+++ b/doc/admin-guide/files/records.yaml.en.rst
@@ -786,6 +786,7 @@ HTTP Engine
    ip-resolve   Value           IP address resolution style.
    proto        Value           List of supported session protocols.
    pp                           Enable Proxy Protocol.
+   pp-clnt                      Use the Proxy Protocol SRC IP as the client IP.
    ssl                          SSL terminated.
    quic                         QUIC terminated.
    tr-full                      Fully transparent (inbound and outbound)
diff --git a/doc/admin-guide/logging/formatting.en.rst 
b/doc/admin-guide/logging/formatting.en.rst
index 3df372979f..bac1fbeeb6 100644
--- a/doc/admin-guide/logging/formatting.en.rst
+++ b/doc/admin-guide/logging/formatting.en.rst
@@ -499,16 +499,19 @@ incoming/outgoing ports, and network interfaces used 
during transactions.
 Field Source         Description
 ===== ============== ==========================================================
 chi   Client         IP address of the client's host. If :ref:`Proxy Protocol 
<proxy-protocol>`
-                     is used, this represents the IP address of the peer, 
rather than
-                     the client IP behind the peer.
+                     is configured with the pp-clnt flag, this represents the 
proxy protocol SRC IP address, otherwise
+                     the IP is that of the connected peer.
 chih  Client         IP address of the client's host, in hexadecimal.
 chiv  Client         IP address of the client's host verified by a plugin. If 
not available,
                      ``chi`` is used.
+rchi  Remote Client  This is alway the IP address of the inbound remote peer.
+rchh  Remote Client  The IP address of the inbound remote peer in hexadecimal.
 hii   Proxy          IP address for the proxy's incoming interface (to which
                      the client connected).
 hiih  Proxy          IP address for the proxy's incoming interface (to which
                      the client connected), in hexadecimal.
 chp   Client         Port number of the client's host.
+rchp  Remote Client  Port number of the inbound remote peer.
 php   Proxy Response TCP port number from which |TS| serviced the request.
 pqsi  Proxy Request  IP address from which |TS| issued the proxy request to the
                      origin server. Cache hits will result in a value of ``0``.
@@ -529,7 +532,6 @@ ppd   Proxy Protocol Destination IP received via Proxy 
Protocol context from the
       Dest IP        to the |TS|
 ppa   Proxy Protocol The Authority TLV from Proxy Protocol context from the LB
       Authority      to the |TS|
-
 ===== ============== ==========================================================
 
 .. note::
diff --git a/include/iocore/net/AcceptOptions.h 
b/include/iocore/net/AcceptOptions.h
index ed3c1d727d..5300027341 100644
--- a/include/iocore/net/AcceptOptions.h
+++ b/include/iocore/net/AcceptOptions.h
@@ -85,5 +85,6 @@ struct AcceptOptions {
   bool f_mptcp = false;
 
   /// Proxy Protocol enabled
-  bool f_proxy_protocol = false;
+  bool f_proxy_protocol            = false;
+  bool f_proxy_protocol_client_src = false;
 };
diff --git a/include/iocore/net/NetVConnection.h 
b/include/iocore/net/NetVConnection.h
index 9f3178fa75..fedb7328ad 100644
--- a/include/iocore/net/NetVConnection.h
+++ b/include/iocore/net/NetVConnection.h
@@ -26,6 +26,7 @@
 #include "iocore/net/NetVCOptions.h"
 #include "iocore/net/ProxyProtocol.h"
 
+#include <cstdint>
 #include <string_view>
 #include <optional>
 
@@ -282,6 +283,12 @@ public:
   /** Returns local port. */
   uint16_t get_local_port();
 
+  /** Returns remote sockaddr storage. */
+  sockaddr const   *get_effective_remote_addr();
+  IpEndpoint const &get_client_endpoint();
+
+  uint16_t get_client_port();
+
   /** Returns remote sockaddr storage. */
   sockaddr const   *get_remote_addr();
   IpEndpoint const &get_remote_endpoint();
@@ -426,11 +433,18 @@ public:
   {
     return is_proxy_protocol;
   }
+  /// Get the proxy protocol copy src IP flag
+  bool
+  get_is_proxy_protocol_cp_src() const
+  {
+    return is_proxy_protocol_cp_src;
+  }
   /// Set the proxy protocol enabled flag on the port
   void
-  set_is_proxy_protocol(bool state = true)
+  set_is_proxy_protocol(bool state, bool cp_src_ip)
   {
-    is_proxy_protocol = state;
+    is_proxy_protocol        = state;
+    is_proxy_protocol_cp_src = cp_src_ip;
   }
 
   virtual int
@@ -523,7 +537,8 @@ protected:
   /// Set if this connection is transparent.
   bool is_transparent = false;
   /// Set if proxy protocol is enabled
-  bool is_proxy_protocol = false;
+  bool is_proxy_protocol        = false;
+  bool is_proxy_protocol_cp_src = false;
   /// This is essentially a tri-state, we leave it undefined to mean no MPTCP 
support
   std::optional<bool> mptcp_state;
   /// Set if the next write IO that empties the write buffer should generate 
an event.
@@ -693,6 +708,33 @@ NetVConnection::_set_service(QUICSupport *instance)
   this->_set_service(NetVConnection::Service::QUIC, instance);
 }
 
+inline sockaddr const *
+NetVConnection::get_effective_remote_addr()
+{
+  if (pp_info.version != ProxyProtocolVersion::UNDEFINED && 
is_proxy_protocol_cp_src) {
+    return get_proxy_protocol_src_addr();
+  } else {
+    return get_remote_addr();
+  }
+}
+
+inline IpEndpoint const &
+NetVConnection::get_client_endpoint()
+{
+  if (pp_info.version != ProxyProtocolVersion::UNDEFINED && 
is_proxy_protocol_cp_src) {
+    return pp_info.src_addr;
+  } else {
+    return remote_addr;
+  }
+}
+
+/// @return The remote port in host order.
+inline uint16_t
+NetVConnection::get_client_port()
+{
+  return ats_ip_port_host_order(this->get_effective_remote_addr());
+}
+
 inline sockaddr const *
 NetVConnection::get_remote_addr()
 {
diff --git a/include/proxy/ProxySession.h b/include/proxy/ProxySession.h
index d3267045de..a94bdf4dd4 100644
--- a/include/proxy/ProxySession.h
+++ b/include/proxy/ProxySession.h
@@ -23,6 +23,7 @@
 
 #pragma once
 
+#include "tscore/ink_inet.h"
 #include "tscore/ink_platform.h"
 #include "tscore/ink_resolver.h"
 #include "tscore/TSSystemState.h"
@@ -116,6 +117,8 @@ public:
   virtual uint64_t get_received_frame_count(uint64_t type) const;
 
   // Replicate NetVConnection API
+  virtual sockaddr const *get_client_addr() const;
+  virtual uint16_t        get_client_port() const;
   virtual sockaddr const *get_remote_addr() const;
   virtual sockaddr const *get_local_addr();
 
diff --git a/include/proxy/ProxyTransaction.h b/include/proxy/ProxyTransaction.h
index 8238b1c5c9..c81f73be98 100644
--- a/include/proxy/ProxyTransaction.h
+++ b/include/proxy/ProxyTransaction.h
@@ -24,6 +24,7 @@
 #pragma once
 
 #include "proxy/ProxySession.h"
+#include <cstdint>
 #include <string_view>
 
 class HttpSM;
@@ -131,6 +132,10 @@ public:
   void            set_verified_client_addr(const sockaddr *addr);
   sockaddr const *get_verified_client_addr() const;
 
+  // this is the client address for the transaction, which may not be the same 
as the connection remote address
+  sockaddr const *get_client_addr() const;
+  uint16_t        get_client_port() const;
+
   // This function must return a non-negative number that is different for two 
in-progress transactions with the same proxy_ssn
   // session.
   //
@@ -336,6 +341,18 @@ ProxyTransaction::get_verified_client_addr() const
   return reinterpret_cast<const struct sockaddr *>(&_verified_addr);
 }
 
+inline sockaddr const *
+ProxyTransaction::get_client_addr() const
+{
+  return _proxy_ssn ? _proxy_ssn->get_client_addr() : nullptr;
+}
+
+inline uint16_t
+ProxyTransaction::get_client_port() const
+{
+  return _proxy_ssn ? _proxy_ssn->get_client_port() : 0;
+}
+
 inline void
 ProxyTransaction::set_verified_client_addr(const sockaddr *addr)
 {
diff --git a/include/proxy/logging/LogAccess.h 
b/include/proxy/logging/LogAccess.h
index b71c91ae88..0cdd6e1098 100644
--- a/include/proxy/logging/LogAccess.h
+++ b/include/proxy/logging/LogAccess.h
@@ -126,6 +126,8 @@ public:
   int marshal_host_interface_ip(char *);             // STR
   int marshal_client_host_ip_verified(char *);       // STR
   int marshal_client_host_port(char *);              // INT
+  int marshal_remote_host_ip(char *);                // STR
+  int marshal_remote_host_port(char *);              // STR
   int marshal_client_auth_user_name(char *);         // STR
   int marshal_client_req_timestamp_sec(char *);      // INT
   int marshal_client_req_timestamp_ms(char *);       // INT
diff --git a/include/records/RecHttp.h b/include/records/RecHttp.h
index 3efa034bac..6f6b24c328 100644
--- a/include/records/RecHttp.h
+++ b/include/records/RecHttp.h
@@ -265,6 +265,8 @@ public:
   uint8_t       m_family = AF_INET;           ///< IP address family.
   /// True if proxy protocol is required on incoming requests.
   bool m_proxy_protocol = false;
+  /// True if the port should use the proxy protocol src address as the 
connection remote address
+  bool m_proxy_protocol_client_src = false;
   /// True if inbound connects (from client) are transparent.
   bool m_inbound_transparent_p = false;
   /// True if outbound connections (to origin servers) are transparent.
@@ -415,25 +417,26 @@ public:
   static const char *const DEFAULT_VALUE;
 
   // Keywords (lower case versions, but compares should be case insensitive)
-  static const char *const OPT_FD_PREFIX;               ///< Prefix for file 
descriptor value.
-  static const char *const OPT_OUTBOUND_IP_PREFIX;      ///< Prefix for 
inbound IP address.
-  static const char *const OPT_INBOUND_IP_PREFIX;       ///< Prefix for 
outbound IP address.
-  static const char *const OPT_IPV6;                    ///< IPv6.
-  static const char *const OPT_IPV4;                    ///< IPv4
-  static const char *const OPT_TRANSPARENT_INBOUND;     ///< Inbound 
transparent.
-  static const char *const OPT_TRANSPARENT_OUTBOUND;    ///< Outbound 
transparent.
-  static const char *const OPT_TRANSPARENT_FULL;        ///< Full transparency.
-  static const char *const OPT_TRANSPARENT_PASSTHROUGH; ///< Pass-through 
non-HTTP.
-  static const char *const OPT_ALLOW_PLAIN;             ///< Backup to plain 
HTTP.
-  static const char *const OPT_SSL;                     ///< SSL (experimental)
-  static const char *const OPT_QUIC;                    ///< QUIC 
(experimental)
-  static const char *const OPT_PROXY_PROTO;             ///< Proxy Protocol
-  static const char *const OPT_PLUGIN;                  ///< Protocol Plugin 
handle (experimental)
-  static const char *const OPT_BLIND_TUNNEL;            ///< Blind tunnel.
-  static const char *const OPT_COMPRESSED;              ///< Compressed.
-  static const char *const OPT_HOST_RES_PREFIX;         ///< Set DNS family 
preference.
-  static const char *const OPT_PROTO_PREFIX;            ///< Transport layer 
protocols.
-  static const char *const OPT_MPTCP;                   ///< MPTCP.
+  static const char *const OPT_FD_PREFIX;                 ///< Prefix for file 
descriptor value.
+  static const char *const OPT_OUTBOUND_IP_PREFIX;        ///< Prefix for 
inbound IP address.
+  static const char *const OPT_INBOUND_IP_PREFIX;         ///< Prefix for 
outbound IP address.
+  static const char *const OPT_IPV6;                      ///< IPv6.
+  static const char *const OPT_IPV4;                      ///< IPv4
+  static const char *const OPT_TRANSPARENT_INBOUND;       ///< Inbound 
transparent.
+  static const char *const OPT_TRANSPARENT_OUTBOUND;      ///< Outbound 
transparent.
+  static const char *const OPT_TRANSPARENT_FULL;          ///< Full 
transparency.
+  static const char *const OPT_TRANSPARENT_PASSTHROUGH;   ///< Pass-through 
non-HTTP.
+  static const char *const OPT_ALLOW_PLAIN;               ///< Backup to plain 
HTTP.
+  static const char *const OPT_SSL;                       ///< SSL 
(experimental)
+  static const char *const OPT_QUIC;                      ///< QUIC 
(experimental)
+  static const char *const OPT_PROXY_PROTO;               ///< Proxy Protocol
+  static const char *const OPT_PLUGIN;                    ///< Protocol Plugin 
handle (experimental)
+  static const char *const OPT_BLIND_TUNNEL;              ///< Blind tunnel.
+  static const char *const OPT_COMPRESSED;                ///< Compressed.
+  static const char *const OPT_HOST_RES_PREFIX;           ///< Set DNS family 
preference.
+  static const char *const OPT_PROTO_PREFIX;              ///< Transport layer 
protocols.
+  static const char *const OPT_MPTCP;                     ///< MPTCP.
+  static const char *const OPT_PROXY_PROTO_CLIENT_SRC_IP; ///< The Proxy 
protocol SRC IP address is used as the client's IP address
 
   static std::vector<self> &m_global; ///< Global ("default") data.
 
diff --git a/include/ts/ts.h b/include/ts/ts.h
index 3227f1cf18..d62d5d8156 100644
--- a/include/ts/ts.h
+++ b/include/ts/ts.h
@@ -2036,6 +2036,7 @@ TSVConn TSTransformOutputVConnGet(TSVConn connp);
 /* --------------------------------------------------------------------------
    Net VConnections */
 struct sockaddr const *TSNetVConnRemoteAddrGet(TSVConn vc);
+struct sockaddr const *TSNetVConnClientAddrGet(TSVConn vc);
 
 /**
     Opens a network connection to the host specified by ip on the port
diff --git a/src/api/InkAPI.cc b/src/api/InkAPI.cc
index cabfb5309d..1c832eb9dd 100644
--- a/src/api/InkAPI.cc
+++ b/src/api/InkAPI.cc
@@ -4692,7 +4692,7 @@ TSHttpSsnClientAddrGet(TSHttpSsn ssnp)
   if (cs == nullptr) {
     return nullptr;
   }
-  return cs->get_remote_addr();
+  return cs->get_client_addr();
 }
 sockaddr const *
 TSHttpTxnClientAddrGet(TSHttpTxn txnp)
@@ -6168,6 +6168,14 @@ TSNetVConnRemoteAddrGet(TSVConn connp)
   return vc->get_remote_addr();
 }
 
+sockaddr const *
+TSNetVConnClientAddrGet(TSVConn connp)
+{
+  sdk_assert(sdk_sanity_check_iocore_structure(connp) == TS_SUCCESS);
+  NetVConnection *vc = reinterpret_cast<NetVConnection *>(connp);
+  return vc->get_effective_remote_addr();
+}
+
 TSAction
 TSNetConnect(TSCont contp, sockaddr const *addr)
 {
diff --git a/src/iocore/net/SNIActionPerformer.cc 
b/src/iocore/net/SNIActionPerformer.cc
index 3b30db815d..d0ea144f18 100644
--- a/src/iocore/net/SNIActionPerformer.cc
+++ b/src/iocore/net/SNIActionPerformer.cc
@@ -417,7 +417,7 @@ SNI_IpAllow::SNIAction(SSL &ssl, ActionItem::Context const 
& /* ctx ATS_UNUSED *
   const sockaddr *client_ip = nullptr;
   for (int i = 0; i < IpAllow::Subject::MAX_SUBJECTS; ++i) {
     if (IpAllow::Subject::PEER == IpAllow::subjects[i]) {
-      client_ip = ssl_vc->get_remote_addr();
+      client_ip = ssl_vc->get_effective_remote_addr();
       break;
     } else if (IpAllow::Subject::PROXY == IpAllow::subjects[i] &&
                ssl_vc->get_proxy_protocol_version() != 
ProxyProtocolVersion::UNDEFINED) {
diff --git a/src/iocore/net/SSLClientUtils.cc b/src/iocore/net/SSLClientUtils.cc
index f1b75ff56e..fe08b43a4f 100644
--- a/src/iocore/net/SSLClientUtils.cc
+++ b/src/iocore/net/SSLClientUtils.cc
@@ -81,7 +81,7 @@ verify_callback(int signature_ok, X509_STORE_CTX *ctx)
       Dbg(dbg_ctl_ssl_verify, "verification error:num=%d:%s:depth=%d", err, 
X509_verify_cert_error_string(err), depth);
       const char *sni_name;
       char        buff[INET6_ADDRSTRLEN];
-      ats_ip_ntop(netvc->get_remote_addr(), buff, INET6_ADDRSTRLEN);
+      ats_ip_ntop(netvc->get_effective_remote_addr(), buff, INET6_ADDRSTRLEN);
       if (netvc->options.sni_servername) {
         sni_name = netvc->options.sni_servername.get();
       } else {
@@ -110,7 +110,7 @@ verify_callback(int signature_ok, X509_STORE_CTX *ctx)
       sni_name = reinterpret_cast<unsigned char 
*>(netvc->options.sni_servername.get());
     } else {
       sni_name = reinterpret_cast<unsigned char *>(buff);
-      ats_ip_ntop(netvc->get_remote_addr(), buff, INET6_ADDRSTRLEN);
+      ats_ip_ntop(netvc->get_effective_remote_addr(), buff, INET6_ADDRSTRLEN);
     }
     if (validate_hostname(cert, sni_name, false, &matched_name)) {
       Dbg(dbg_ctl_ssl_verify, "Hostname %s verified OK, matched %s", sni_name, 
matched_name);
@@ -118,7 +118,7 @@ verify_callback(int signature_ok, X509_STORE_CTX *ctx)
     } else { // Name validation failed
       // Get the server address if we did't already compute it
       if (netvc->options.sni_servername) {
-        ats_ip_ntop(netvc->get_remote_addr(), buff, INET6_ADDRSTRLEN);
+        ats_ip_ntop(netvc->get_effective_remote_addr(), buff, 
INET6_ADDRSTRLEN);
       }
       // If we got here the verification failed
       Warning("SNI (%s) not in certificate. Action=%s server=%s(%s)", 
sni_name, enforce_mode ? "Terminate" : "Continue",
@@ -141,7 +141,7 @@ verify_callback(int signature_ok, X509_STORE_CTX *ctx)
       sni_name = reinterpret_cast<unsigned char 
*>(netvc->options.sni_servername.get());
     } else {
       sni_name = reinterpret_cast<unsigned char *>(buff);
-      ats_ip_ntop(netvc->get_remote_addr(), buff, INET6_ADDRSTRLEN);
+      ats_ip_ntop(netvc->get_effective_remote_addr(), buff, INET6_ADDRSTRLEN);
     }
     Warning("TS_EVENT_SSL_VERIFY_SERVER plugin failed the origin certificate 
check for %s.  Action=%s SNI=%s",
             netvc->options.ssl_servername.get(), enforce_mode ? "Terminate" : 
"Continue", sni_name);
diff --git a/src/iocore/net/SSLDiags.cc b/src/iocore/net/SSLDiags.cc
index 7883fe6b42..5fb24644a8 100644
--- a/src/iocore/net/SSLDiags.cc
+++ b/src/iocore/net/SSLDiags.cc
@@ -164,7 +164,7 @@ SSLDiagnostic(const SourceLocation &loc, bool debug, 
SSLNetVConnection *vc, cons
   ip_text_buffer ip_buf = {'\0'};
 
   if (vc) {
-    ats_ip_ntop(vc->get_remote_addr(), ip_buf, sizeof(ip_buf));
+    ats_ip_ntop(vc->get_effective_remote_addr(), ip_buf, sizeof(ip_buf));
   }
 
   es = reinterpret_cast<unsigned long>(pthread_self());
diff --git a/src/iocore/net/SSLNetVConnection.cc 
b/src/iocore/net/SSLNetVConnection.cc
index 787936fb76..c4aeb44a89 100644
--- a/src/iocore/net/SSLNetVConnection.cc
+++ b/src/iocore/net/SSLNetVConnection.cc
@@ -356,10 +356,8 @@ SSLNetVConnection::read_raw_data()
       if (pp_ipmap->count() > 0) {
         Dbg(dbg_ctl_proxyprotocol, "proxy protocol has a configured allowlist 
of trusted IPs - checking");
 
-        // At this point, using get_remote_addr() will return the ip of the
-        // proxy source IP, not the Proxy Protocol client ip. Since we are
-        // checking the ip of the actual source of this connection, this is
-        // what we want now.
+        // Using get_remote_addr() will return the ip of the
+        // proxy source IP, not the Proxy Protocol client ip.
         if (!pp_ipmap->contains(swoc::IPAddr(get_remote_addr()))) {
           Dbg(dbg_ctl_proxyprotocol, "Source IP is NOT in the configured 
allowlist of trusted IPs - closing connection");
           r = -ENOTCONN; // Need a quick close/exit here to refuse the 
connection!!!!!!!!!
diff --git a/src/iocore/net/Server.cc b/src/iocore/net/Server.cc
index 3cd85df3a0..fff587df2b 100644
--- a/src/iocore/net/Server.cc
+++ b/src/iocore/net/Server.cc
@@ -291,7 +291,11 @@ Server::setup_fd_for_listen(bool non_blocking, const 
NetProcessor::AcceptOptions
   }
 
   if (opt.f_proxy_protocol) {
-    Dbg(dbg_ctl_proxyprotocol, "Proxy Protocol enabled.");
+    if (opt.f_proxy_protocol_client_src) {
+      Dbg(dbg_ctl_proxyprotocol, "Proxy Protocol enabled(Using src IP as 
remote IP).");
+    } else {
+      Dbg(dbg_ctl_proxyprotocol, "Proxy Protocol enabled.");
+    }
   }
 
 #if defined(TCP_MAXSEG)
diff --git a/src/iocore/net/UnixNetAccept.cc b/src/iocore/net/UnixNetAccept.cc
index 94a8864854..cea9df7879 100644
--- a/src/iocore/net/UnixNetAccept.cc
+++ b/src/iocore/net/UnixNetAccept.cc
@@ -145,7 +145,7 @@ net_accept(NetAccept *na, void *ep, bool blockable)
     vc->submit_time = ink_get_hrtime();
     vc->action_     = *na->action_;
     vc->set_is_transparent(na->opt.f_inbound_transparent);
-    vc->set_is_proxy_protocol(na->opt.f_proxy_protocol);
+    vc->set_is_proxy_protocol(na->opt.f_proxy_protocol, 
na->opt.f_proxy_protocol_client_src);
     vc->set_context(NET_VCONNECTION_IN);
     if (na->opt.f_mptcp) {
       vc->set_mptcp_state(); // Try to get the MPTCP state, and update 
accordingly
@@ -432,7 +432,7 @@ NetAccept::do_blocking_accept(EThread *t)
     vc->submit_time = ink_get_hrtime();
     vc->action_     = *action_;
     vc->set_is_transparent(opt.f_inbound_transparent);
-    vc->set_is_proxy_protocol(opt.f_proxy_protocol);
+    vc->set_is_proxy_protocol(opt.f_proxy_protocol, 
opt.f_proxy_protocol_client_src);
     vc->options.sockopt_flags        = opt.sockopt_flags;
     vc->options.packet_mark          = opt.packet_mark;
     vc->options.packet_tos           = opt.packet_tos;
@@ -598,7 +598,7 @@ NetAccept::acceptFastEvent(int event, void *ep)
     vc->submit_time = ink_get_hrtime();
     vc->action_     = *action_;
     vc->set_is_transparent(opt.f_inbound_transparent);
-    vc->set_is_proxy_protocol(opt.f_proxy_protocol);
+    vc->set_is_proxy_protocol(opt.f_proxy_protocol, 
opt.f_proxy_protocol_client_src);
     vc->options.sockopt_flags        = opt.sockopt_flags;
     vc->options.packet_mark          = opt.packet_mark;
     vc->options.packet_tos           = opt.packet_tos;
diff --git a/src/proxy/ProxySession.cc b/src/proxy/ProxySession.cc
index fd1620b409..a19afe5feb 100644
--- a/src/proxy/ProxySession.cc
+++ b/src/proxy/ProxySession.cc
@@ -26,6 +26,7 @@
 #include "proxy/ProxySession.h"
 #include "iocore/net/TLSBasicSupport.h"
 #include "private/SSLProxySession.h"
+#include <cstdint>
 
 std::map<int, std::function<PoolableSession *()>> ProtocolSessionCreateMap;
 
@@ -286,6 +287,18 @@ ProxySession::get_version(HTTPHdr &hdr) const
   return hdr.version_get();
 }
 
+sockaddr const *
+ProxySession::get_client_addr() const
+{
+  return _vc ? _vc->get_effective_remote_addr() : nullptr;
+}
+
+uint16_t
+ProxySession::get_client_port() const
+{
+  return _vc ? _vc->get_client_endpoint().host_order_port() : 0;
+}
+
 sockaddr const *
 ProxySession::get_remote_addr() const
 {
diff --git a/src/proxy/http/HttpProxyServerMain.cc 
b/src/proxy/http/HttpProxyServerMain.cc
index d726937ee7..3f9dc8e984 100644
--- a/src/proxy/http/HttpProxyServerMain.cc
+++ b/src/proxy/http/HttpProxyServerMain.cc
@@ -143,11 +143,12 @@ make_net_accept_options(const HttpProxyPort *port, 
unsigned nthreads)
 #endif
 
   if (port) {
-    net.f_inbound_transparent = port->m_inbound_transparent_p;
-    net.f_mptcp               = port->m_mptcp;
-    net.ip_family             = port->m_family;
-    net.local_port            = port->m_port;
-    net.f_proxy_protocol      = port->m_proxy_protocol;
+    net.f_inbound_transparent       = port->m_inbound_transparent_p;
+    net.f_mptcp                     = port->m_mptcp;
+    net.ip_family                   = port->m_family;
+    net.local_port                  = port->m_port;
+    net.f_proxy_protocol            = port->m_proxy_protocol;
+    net.f_proxy_protocol_client_src = port->m_proxy_protocol_client_src;
 
     if (port->m_inbound_ip.isValid()) {
       net.local_ip = port->m_inbound_ip;
diff --git a/src/proxy/http2/Http2SessionAccept.cc 
b/src/proxy/http2/Http2SessionAccept.cc
index f8306c9d1b..a7a5ad0fb9 100644
--- a/src/proxy/http2/Http2SessionAccept.cc
+++ b/src/proxy/http2/Http2SessionAccept.cc
@@ -46,7 +46,7 @@ Http2SessionAccept::accept(NetVConnection *netvc, MIOBuffer 
*iobuf, IOBufferRead
 
   for (int i = 0; i < IpAllow::Subject::MAX_SUBJECTS; ++i) {
     if (IpAllow::Subject::PEER == IpAllow::subjects[i]) {
-      client_ip = netvc->get_remote_addr();
+      client_ip = netvc->get_effective_remote_addr();
       break;
     } else if (IpAllow::Subject::PROXY == IpAllow::subjects[i] &&
                netvc->get_proxy_protocol_version() != 
ProxyProtocolVersion::UNDEFINED) {
diff --git a/src/proxy/logging/Log.cc b/src/proxy/logging/Log.cc
index ca56f27c5a..35d2c87187 100644
--- a/src/proxy/logging/Log.cc
+++ b/src/proxy/logging/Log.cc
@@ -347,6 +347,21 @@ Log::init_fields()
   global_field_list.add(field, false);
   field_symbol_hash.emplace("chiv", field);
 
+  // remote client (Not necessarily the requesting client IP - See proxy 
protocol)
+  field = new LogField("remote_host_ip", "rchi", LogField::IP, 
&LogAccess::marshal_remote_host_ip, &LogAccess::unmarshal_ip_to_str);
+  global_field_list.add(field, false);
+  field_symbol_hash.emplace("rchi", field);
+
+  field = new LogField("remote_host_port", "rchp", LogField::sINT, 
&LogAccess::marshal_remote_host_port,
+                       &LogAccess::unmarshal_int_to_str);
+  global_field_list.add(field, false);
+  field_symbol_hash.emplace("rchp", field);
+
+  field =
+    new LogField("remote_host_ip_hex", "rchh", LogField::IP, 
&LogAccess::marshal_remote_host_ip, &LogAccess::unmarshal_ip_to_hex);
+  global_field_list.add(field, false);
+  field_symbol_hash.emplace("rchh", field);
+
   // interface ip
 
   field =
diff --git a/src/proxy/logging/LogAccess.cc b/src/proxy/logging/LogAccess.cc
index 50991eada3..0754be1c21 100644
--- a/src/proxy/logging/LogAccess.cc
+++ b/src/proxy/logging/LogAccess.cc
@@ -1441,6 +1441,21 @@ LogAccess::marshal_plugin_identity_tag(char *buf)
 
 int
 LogAccess::marshal_client_host_ip(char *buf)
+{
+  if (m_http_sm) {
+    auto txn = m_http_sm->get_ua_txn();
+    if (txn) {
+      sockaddr const *addr = txn->get_client_addr();
+      if (addr && ats_is_ip(addr)) {
+        return marshal_ip(buf, addr);
+      }
+    }
+  }
+  return INK_MIN_ALIGN;
+}
+
+int
+LogAccess::marshal_remote_host_ip(char *buf)
 {
   return marshal_ip(buf, &m_http_sm->t_state.client_info.src_addr.sa);
 }
@@ -1463,7 +1478,7 @@ LogAccess::marshal_client_host_ip_verified(char *buf)
       }
     }
   }
-  return marshal_ip(buf, &m_http_sm->t_state.client_info.src_addr.sa);
+  return marshal_client_host_ip(buf);
 }
 
 /*-------------------------------------------------------------------------
@@ -1658,6 +1673,19 @@ LogAccess::marshal_proxy_protocol_authority(char *buf)
   -------------------------------------------------------------------------*/
 int
 LogAccess::marshal_client_host_port(char *buf)
+{
+  if (m_http_sm) {
+    auto txn = m_http_sm->get_ua_txn();
+    if (txn) {
+      uint16_t port = txn->get_client_port();
+      marshal_int(buf, port);
+    }
+  }
+  return INK_MIN_ALIGN;
+}
+
+int
+LogAccess::marshal_remote_host_port(char *buf)
 {
   if (buf) {
     uint16_t port = m_http_sm->t_state.client_info.src_addr.host_order_port();
diff --git a/src/records/RecHttp.cc b/src/records/RecHttp.cc
index 64a828b73f..57cb822c99 100644
--- a/src/records/RecHttp.cc
+++ b/src/records/RecHttp.cc
@@ -182,20 +182,21 @@ const char *const HttpProxyPort::OPT_INBOUND_IP_PREFIX  = 
"ip-in";
 const char *const HttpProxyPort::OPT_HOST_RES_PREFIX    = "ip-resolve";
 const char *const HttpProxyPort::OPT_PROTO_PREFIX       = "proto";
 
-const char *const HttpProxyPort::OPT_IPV6                    = "ipv6";
-const char *const HttpProxyPort::OPT_IPV4                    = "ipv4";
-const char *const HttpProxyPort::OPT_TRANSPARENT_INBOUND     = "tr-in";
-const char *const HttpProxyPort::OPT_TRANSPARENT_OUTBOUND    = "tr-out";
-const char *const HttpProxyPort::OPT_TRANSPARENT_FULL        = "tr-full";
-const char *const HttpProxyPort::OPT_TRANSPARENT_PASSTHROUGH = "tr-pass";
-const char *const HttpProxyPort::OPT_ALLOW_PLAIN             = "allow-plain";
-const char *const HttpProxyPort::OPT_SSL                     = "ssl";
-const char *const HttpProxyPort::OPT_PROXY_PROTO             = "pp";
-const char *const HttpProxyPort::OPT_PLUGIN                  = "plugin";
-const char *const HttpProxyPort::OPT_BLIND_TUNNEL            = "blind";
-const char *const HttpProxyPort::OPT_COMPRESSED              = "compressed";
-const char *const HttpProxyPort::OPT_MPTCP                   = "mptcp";
-const char *const HttpProxyPort::OPT_QUIC                    = "quic";
+const char *const HttpProxyPort::OPT_IPV6                      = "ipv6";
+const char *const HttpProxyPort::OPT_IPV4                      = "ipv4";
+const char *const HttpProxyPort::OPT_TRANSPARENT_INBOUND       = "tr-in";
+const char *const HttpProxyPort::OPT_TRANSPARENT_OUTBOUND      = "tr-out";
+const char *const HttpProxyPort::OPT_TRANSPARENT_FULL          = "tr-full";
+const char *const HttpProxyPort::OPT_TRANSPARENT_PASSTHROUGH   = "tr-pass";
+const char *const HttpProxyPort::OPT_ALLOW_PLAIN               = "allow-plain";
+const char *const HttpProxyPort::OPT_SSL                       = "ssl";
+const char *const HttpProxyPort::OPT_PROXY_PROTO               = "pp";
+const char *const HttpProxyPort::OPT_PLUGIN                    = "plugin";
+const char *const HttpProxyPort::OPT_BLIND_TUNNEL              = "blind";
+const char *const HttpProxyPort::OPT_COMPRESSED                = "compressed";
+const char *const HttpProxyPort::OPT_MPTCP                     = "mptcp";
+const char *const HttpProxyPort::OPT_QUIC                      = "quic";
+const char *const HttpProxyPort::OPT_PROXY_PROTO_CLIENT_SRC_IP = "pp-clnt";
 
 // File local constants.
 namespace
@@ -465,6 +466,8 @@ HttpProxyPort::processOptions(const char *opts)
       } else {
         Warning("Multipath TCP requested [%s] in port descriptor '%s' but it 
is not supported by this host.", item, opts);
       }
+    } else if (0 == strcasecmp(OPT_PROXY_PROTO_CLIENT_SRC_IP, item)) {
+      m_proxy_protocol_client_src = true;
     } else if (nullptr != (value = this->checkPrefix(item, 
OPT_HOST_RES_PREFIX, OPT_HOST_RES_PREFIX_LEN))) {
       this->processFamilyPreference(value);
       host_res_set_p = true;
@@ -659,6 +662,10 @@ HttpProxyPort::print(char *out, size_t n)
     zret += snprintf(out + zret, n - zret, ":%s", OPT_PROXY_PROTO);
   }
 
+  if (m_proxy_protocol_client_src) {
+    zret += snprintf(out + zret, n - zret, ":%s", 
OPT_PROXY_PROTO_CLIENT_SRC_IP);
+  }
+
   if (m_outbound_transparent_p && m_inbound_transparent_p) {
     zret += snprintf(out + zret, n - zret, ":%s", OPT_TRANSPARENT_FULL);
   } else if (m_inbound_transparent_p) {
diff --git a/tests/gold_tests/autest-site/trafficserver.test.ext 
b/tests/gold_tests/autest-site/trafficserver.test.ext
index 8cd39944f1..a41f8948ce 100755
--- a/tests/gold_tests/autest-site/trafficserver.test.ext
+++ b/tests/gold_tests/autest-site/trafficserver.test.ext
@@ -59,6 +59,7 @@ def MakeATSProcess(
         use_traffic_out=True,
         dump_runroot=True,
         enable_proxy_protocol=False,
+        enable_proxy_protocol_cp_src=False,
         disable_log_checks=False):
     """Create a traffic server process.
 
@@ -433,11 +434,14 @@ def MakeATSProcess(
             port_str += " {ssl_port}:quic {ssl_portv6}:quic:ipv6".format(
                 ssl_port=p.Variables.ssl_port, 
ssl_portv6=p.Variables.ssl_portv6)
         if enable_proxy_protocol:
-            port_str += f" {p.Variables.proxy_protocol_port}:pp 
{p.Variables.proxy_protocol_portv6}:pp:ipv6"
+            ppcfg = "pp"
+            if enable_proxy_protocol_cp_src:
+                ppcfg += ":pp-clnt"
+            port_str += f" {p.Variables.proxy_protocol_port}:{ppcfg} 
{p.Variables.proxy_protocol_portv6}:{ppcfg}:ipv6"
             if enable_tls:
-                port_str += f" {p.Variables.proxy_protocol_ssl_port}:pp:ssl 
{p.Variables.proxy_protocol_ssl_portv6}:pp:ssl:ipv6"
+                port_str += f" 
{p.Variables.proxy_protocol_ssl_port}:{ppcfg}:ssl 
{p.Variables.proxy_protocol_ssl_portv6}:{ppcfg}:ssl:ipv6"
             if enable_uds:
-                port_str += f" {uds_path}:pp"
+                port_str += f" {uds_path}:{ppcfg}"
         elif enable_uds:
             port_str += f" {uds_path}"
         #p.Env['PROXY_CONFIG_HTTP_SERVER_PORTS'] = port_str
diff --git a/tests/gold_tests/proxy_protocol/gold/access-cp.gold 
b/tests/gold_tests/proxy_protocol/gold/access-cp.gold
new file mode 100644
index 0000000000..b84f06e4d2
--- /dev/null
+++ b/tests/gold_tests/proxy_protocol/gold/access-cp.gold
@@ -0,0 +1,7 @@
+127.0.0.1 127.0.0.1 127.0.0.1
+127.0.0.1 127.0.0.1 127.0.0.1
+127.0.0.1 127.0.0.1 127.0.0.1
+127.0.0.1 127.0.0.1 127.0.0.1
+198.51.100.1 198.51.100.1 127.0.0.1
+127.0.0.1 0 127.0.0.1
+127.0.0.1 0 127.0.0.1
diff --git a/tests/gold_tests/proxy_protocol/gold/access-nocp.gold 
b/tests/gold_tests/proxy_protocol/gold/access-nocp.gold
new file mode 100644
index 0000000000..7d705c4735
--- /dev/null
+++ b/tests/gold_tests/proxy_protocol/gold/access-nocp.gold
@@ -0,0 +1,7 @@
+127.0.0.1 127.0.0.1 127.0.0.1
+127.0.0.1 127.0.0.1 127.0.0.1
+127.0.0.1 127.0.0.1 127.0.0.1
+127.0.0.1 127.0.0.1 127.0.0.1
+127.0.0.1 198.51.100.1 127.0.0.1
+127.0.0.1 0 127.0.0.1
+127.0.0.1 0 127.0.0.1
diff --git a/tests/gold_tests/proxy_protocol/gold/access.gold 
b/tests/gold_tests/proxy_protocol/gold/access.gold
deleted file mode 100644
index ba2abf3cf7..0000000000
--- a/tests/gold_tests/proxy_protocol/gold/access.gold
+++ /dev/null
@@ -1,7 +0,0 @@
-127.0.0.1 127.0.0.1
-127.0.0.1 127.0.0.1
-127.0.0.1 127.0.0.1
-127.0.0.1 127.0.0.1
-127.0.0.1 198.51.100.1
-127.0.0.1 0
-127.0.0.1 0
diff --git a/tests/gold_tests/proxy_protocol/proxy_protocol.test.py 
b/tests/gold_tests/proxy_protocol/proxy_protocol.test.py
index 430569428d..bd008b9a6f 100644
--- a/tests/gold_tests/proxy_protocol/proxy_protocol.test.py
+++ b/tests/gold_tests/proxy_protocol/proxy_protocol.test.py
@@ -27,15 +27,21 @@ class ProxyProtocolInTest:
 
     replay_file = "replay/proxy_protocol_in.replay.yaml"
 
-    def __init__(self):
-        self.setupOriginServer()
-        self.setupTS()
-
-    def setupOriginServer(self):
-        self.server = Test.MakeVerifierServerProcess("pp-in-server", 
self.replay_file)
-
-    def setupTS(self):
-        self.ts = Test.MakeATSProcess("ts_in", enable_tls=True, 
enable_cache=False, enable_proxy_protocol=True)
+    def __init__(self, name, enable_cp=False):
+        self.setupOriginServer(name)
+        self.setupTS(name, enable_cp)
+        self.name = name
+
+    def setupOriginServer(self, name):
+        self.server = Test.MakeVerifierServerProcess(f"pp-in-server-{name}", 
self.replay_file)
+
+    def setupTS(self, name, enable_cp):
+        self.ts = Test.MakeATSProcess(
+            f"ts_in_{name}",
+            enable_tls=True,
+            enable_cache=False,
+            enable_proxy_protocol=True,
+            enable_proxy_protocol_cp_src=enable_cp)
 
         self.ts.addDefaultSSLFiles()
         self.ts.Disk.ssl_multicert_config.AddLine("dest_ip=* 
ssl_cert_name=server.pem ssl_key_name=server.key")
@@ -57,7 +63,7 @@ class ProxyProtocolInTest:
 logging:
   formats:
     - name: access
-      format: '%<chi> %<pps>'
+      format: '%<chi> %<pps> %<rchi>'
 
   logs:
     - filename: access
@@ -65,9 +71,9 @@ logging:
 '''.split("\n"))
 
     def runTraffic(self):
-        tr = Test.AddTestRun("Verify correct handling of incoming PROXY 
header.")
+        tr = Test.AddTestRun(f"Verify correct handling of incoming PROXY 
header. {self.name}")
         tr.AddVerifierClientProcess(
-            "pp-in-client",
+            f"pp-in-client-{self.name}",
             self.replay_file,
             http_ports=[self.ts.Variables.proxy_protocol_port],
             https_ports=[self.ts.Variables.proxy_protocol_ssl_port])
@@ -80,7 +86,7 @@ logging:
         """
         check access log
         """
-        Test.Disk.File(os.path.join(self.ts.Variables.LOGDIR, 'access.log'), 
exists=True, content='gold/access.gold')
+        Test.Disk.File(os.path.join(self.ts.Variables.LOGDIR, 'access.log'), 
exists=True, content=f"gold/access-{self.name}.gold")
 
         # Wait for log file to appear, then wait one extra second to make sure
         # TS is done writing it.
@@ -219,7 +225,8 @@ class ProxyProtocolOutTest:
         self.setLogExpectations(tr)
 
 
-ProxyProtocolInTest().run()
+ProxyProtocolInTest("nocp", False).run()
+ProxyProtocolInTest("cp", True).run()
 
 # non-tunnling HTTP to origin
 ProxyProtocolOutTest(pp_version=-1, is_tunnel=False, 
is_tls_to_origin=False).run()


Reply via email to