This is an automated email from the ASF dual-hosted git repository.
maskit 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 f449d9837c header_rewrite: Add INBOUND_IP_SOURCE controller (#12246)
f449d9837c is described below
commit f449d9837cc4a16e8650bcbb16e2c980b3824922
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Wed Jul 9 11:44:23 2025 -0600
header_rewrite: Add INBOUND_IP_SOURCE controller (#12246)
* header_rewrite: Add INBOUND_IP_SOURCE controller
* Fix documentation format
* Fix documentation format
* Fix documentation format
* Initialize private slot index
* Add examples
Conflicts:
doc/admin-guide/plugins/header_rewrite.en.rst
---
doc/admin-guide/plugins/header_rewrite.en.rst | 39 ++++++++++++++++++++----
plugins/header_rewrite/conditions.cc | 44 +++++++++++++++++++++------
plugins/header_rewrite/conditions.h | 32 ++++++++++++++++---
plugins/header_rewrite/operators.cc | 12 ++++++++
plugins/header_rewrite/operators.h | 1 +
plugins/header_rewrite/statement.h | 11 ++++++-
6 files changed, 119 insertions(+), 20 deletions(-)
diff --git a/doc/admin-guide/plugins/header_rewrite.en.rst
b/doc/admin-guide/plugins/header_rewrite.en.rst
index be45b57c82..13be369d79 100644
--- a/doc/admin-guide/plugins/header_rewrite.en.rst
+++ b/doc/admin-guide/plugins/header_rewrite.en.rst
@@ -1147,12 +1147,16 @@ set-plugin-cntl
This operator lets you control the fundamental behavior of this plugin for a
particular transaction.
The available controllers are:
-================== =====================
=============================================================================================
-Controller Operators/Conditions Description
-================== =====================
=============================================================================================
-TIMEZONE ``NOW`` If ``GMT`` is passed, the operators
and conditions use GMT regardles of the timezone setting
- on your system. The default value is
``LOCAL``.
-================== =====================
=============================================================================================
++===================+========================+==============================================================================================+
+| Controller | Operators/Conditions | Description
|
++===================+========================+==============================================================================================+
+| TIMEZONE | ``NOW`` | If ``GMT`` is passed, the
operators and conditions use GMT regardles of the timezone setting |
+| | | on your system. The default
value is ``LOCAL``. |
++===================+========================+==============================================================================================+
+| INBOUND_IP_SOURCE | ``IP``, ``INBOUND``, | Selects which IP address to use
for the operators and conditions. Available sources are |
+| | ``CIDR``, and ``GEO`` | ``PEER`` (Uses the IP address
of the peer), and ``PROXY`` (Uses the IP address from PROXY |
+| | | protocol)
|
++===================+========================+==============================================================================================+
Operator Flags
--------------
@@ -1685,3 +1689,26 @@ This rule will deny all requests for URIs with the
``.php`` file extension::
cond %{REMAP_PSEUDO_HOOK} [AND]
cond %{CLIENT-URL:PATH} ="php" [EXT,NOCASE]
set-status 403
+
+Use GMT regardless of system timezone setting
+---------------------------------------------
+
+This rule will change the behavior of %{NOW}. It will always return time in
GMT.
+
+ cond %{READ_REQUEST_HDR_HOOK}
+ set-plugin-cntl TIMEZONE GMT
+
+ cond %{SEND_RESPONSE_HDR_HOOK}
+ set-header hour %{NOW:HOUR}
+
+Use IP address provided by PROXY protocol
+-----------------------------------------
+
+This rule will change the behavior of all header_rewrite conditions which use
the client's IP address on a connection.
+Those will pick the address provided by PROXY protocol, instead of the peer's
address.
+
+ cond %{READ_REQUEST_HDR_HOOK}
+ set-plugin-cntl INBOUND_IP_SOURCE PROXY
+
+ cond %{SEND_RESPONSE_HDR_HOOK}
+ set-header real-ip %{INBOUND:REMOTE-ADDR}
diff --git a/plugins/header_rewrite/conditions.cc
b/plugins/header_rewrite/conditions.cc
index 92033884d7..8a5a4185c4 100644
--- a/plugins/header_rewrite/conditions.cc
+++ b/plugins/header_rewrite/conditions.cc
@@ -34,6 +34,8 @@
#include "conditions.h"
#include "lulu.h"
+static const sockaddr *getClientAddr(TSHttpTxn txnp, int txn_private_slot);
+
// ConditionStatus
void
ConditionStatus::initialize(Parser &p)
@@ -560,7 +562,7 @@ ConditionIp::eval(const Resources &res)
switch (_ip_qual) {
case IP_QUAL_CLIENT:
- addr = TSHttpTxnClientAddrGet(res.txnp);
+ addr = getClientAddr(res.txnp, _txn_private_slot);
break;
case IP_QUAL_INBOUND:
addr = TSHttpTxnIncomingAddrGet(res.txnp);
@@ -598,7 +600,7 @@ ConditionIp::append_value(std::string &s, const Resources
&res)
switch (_ip_qual) {
case IP_QUAL_CLIENT:
- ip_set = (nullptr != getIP(TSHttpTxnClientAddrGet(res.txnp), ip));
+ ip_set = (nullptr != getIP(getClientAddr(res.txnp, _txn_private_slot),
ip));
break;
case IP_QUAL_INBOUND:
ip_set = (nullptr != getIP(TSHttpTxnIncomingAddrGet(res.txnp), ip));
@@ -830,9 +832,9 @@ void
ConditionGeo::append_value(std::string &s, const Resources &res)
{
if (is_int_type()) {
- s += std::to_string(get_geo_int(TSHttpTxnClientAddrGet(res.txnp)));
+ s += std::to_string(get_geo_int(getClientAddr(res.txnp,
_txn_private_slot)));
} else {
- s += get_geo_string(TSHttpTxnClientAddrGet(res.txnp));
+ s += get_geo_string(getClientAddr(res.txnp, _txn_private_slot));
}
Dbg(pi_dbg_ctl, "Appending GEO() to evaluation value -> %s", s.c_str());
}
@@ -844,7 +846,7 @@ ConditionGeo::eval(const Resources &res)
Dbg(pi_dbg_ctl, "Evaluating GEO()");
if (is_int_type()) {
- int64_t geo = get_geo_int(TSHttpTxnClientAddrGet(res.txnp));
+ int64_t geo = get_geo_int(getClientAddr(res.txnp, _txn_private_slot));
ret = static_cast<const Matchers<int64_t> *>(_matcher.get())->test(geo,
res);
} else {
@@ -1001,7 +1003,7 @@ ConditionCidr::eval(const Resources &res)
void
ConditionCidr::append_value(std::string &s, const Resources &res)
{
- struct sockaddr const *addr = TSHttpTxnClientAddrGet(res.txnp);
+ struct sockaddr const *addr = getClientAddr(res.txnp, _txn_private_slot);
if (addr) {
switch (addr->sa_family) {
@@ -1107,7 +1109,7 @@ ConditionInbound::eval(const Resources &res)
addr = TSHttpTxnIncomingAddrGet(res.txnp);
break;
case NET_QUAL_REMOTE_ADDR:
- addr = TSHttpTxnClientAddrGet(res.txnp);
+ addr = getClientAddr(res.txnp, _txn_private_slot);
break;
default:
// Only support actual IP addresses of course...
@@ -1154,10 +1156,10 @@ ConditionInbound::append_value(std::string &s, const
Resources &res, NetworkSess
zret = text;
} break;
case NET_QUAL_REMOTE_ADDR: {
- zret = getIP(TSHttpTxnClientAddrGet(res.txnp), text);
+ zret = getIP(getClientAddr(res.txnp, _txn_private_slot), text);
} break;
case NET_QUAL_REMOTE_PORT: {
- uint16_t port = getPort(TSHttpTxnClientAddrGet(res.txnp));
+ uint16_t port = getPort(getClientAddr(res.txnp, _txn_private_slot));
snprintf(text, sizeof(text), "%d", port);
zret = text;
} break;
@@ -1612,3 +1614,27 @@ ConditionLastCapture::eval(const Resources &res)
return static_cast<const MatcherType *>(_matcher.get())->test(s, res);
}
+
+static const struct sockaddr *
+getClientAddr(TSHttpTxn txnp, int txn_private_slot)
+{
+ const struct sockaddr *addr = nullptr;
+ int addr_len;
+
+ PrivateSlotData private_data;
+ private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(txnp,
txn_private_slot));
+ switch (private_data.ip_source) {
+ case IP_SRC_PEER:
+ addr = TSHttpTxnClientAddrGet(txnp);
+ break;
+ case IP_SRC_PROXY:
+ TSVConnPPInfoGet(TSHttpSsnClientVConnGet(TSHttpTxnSsnGet(txnp)),
TS_PP_INFO_SRC_ADDR, reinterpret_cast<const char **>(&addr),
+ &addr_len);
+ break;
+ default:
+ Dbg(pi_dbg_ctl, "Unknown IP source (%d) was specified",
private_data.ip_source);
+ addr = TSHttpTxnClientAddrGet(txnp);
+ break;
+ }
+ return addr;
+}
diff --git a/plugins/header_rewrite/conditions.h
b/plugins/header_rewrite/conditions.h
index 7317197bac..db8ae26cc3 100644
--- a/plugins/header_rewrite/conditions.h
+++ b/plugins/header_rewrite/conditions.h
@@ -378,6 +378,12 @@ public:
void append_value(std::string &s, const Resources &res) override;
protected:
+ bool
+ need_txn_private_slot() const override
+ {
+ return true;
+ }
+
bool eval(const Resources &res) override;
private:
@@ -472,6 +478,12 @@ private:
virtual std::string get_geo_string(const sockaddr *addr) const;
protected:
+ bool
+ need_txn_private_slot() const override
+ {
+ return true;
+ }
+
bool eval(const Resources &res) override;
GeoQualifiers _geo_qual = GEO_QUAL_COUNTRY;
bool _int_type = false;
@@ -523,6 +535,12 @@ public:
void append_value(std::string &s, const Resources &res) override;
protected:
+ bool
+ need_txn_private_slot() const override
+ {
+ return true;
+ }
+
bool eval(const Resources &res) override;
private:
@@ -547,18 +565,24 @@ public:
ConditionInbound(SelfType &) = delete;
SelfType &operator=(SelfType &) = delete;
- void initialize(Parser &p) override;
- void set_qualifier(const std::string &q) override;
- void append_value(std::string &s, const Resources &res) override;
- static void append_value(std::string &s, const Resources &res,
NetworkSessionQualifiers qual);
+ void initialize(Parser &p) override;
+ void set_qualifier(const std::string &q) override;
+ void append_value(std::string &s, const Resources &res) override;
static constexpr const char *TAG = "INBOUND";
protected:
+ bool
+ need_txn_private_slot() const override
+ {
+ return true;
+ }
+
bool eval(const Resources &res) override;
private:
NetworkSessionQualifiers _net_qual = NET_QUAL_STACK;
+ void append_value(std::string &s, const Resources &res,
NetworkSessionQualifiers qual);
};
class ConditionStringLiteral : public Condition
diff --git a/plugins/header_rewrite/operators.cc
b/plugins/header_rewrite/operators.cc
index 96d4898a21..edd40f5e01 100644
--- a/plugins/header_rewrite/operators.cc
+++ b/plugins/header_rewrite/operators.cc
@@ -1211,6 +1211,15 @@ OperatorSetPluginCntl::initialize(Parser &p)
} else {
TSError("[%s] Unknown value for TIMZEONE control: %s", PLUGIN_NAME,
value.c_str());
}
+ } else if (name == "INBOUND_IP_SOURCE") {
+ _name = PluginCtrl::INBOUND_IP_SOURCE;
+ if (value == "PEER") {
+ _value = IP_SRC_PEER;
+ } else if (value == "PROXY") {
+ _value = IP_SRC_PROXY;
+ } else {
+ TSError("[%s] Unknown value for INBOUND_IP_SOURCE control: %s",
PLUGIN_NAME, value.c_str());
+ }
}
}
@@ -1238,6 +1247,9 @@ OperatorSetPluginCntl::exec(const Resources &res) const
case PluginCtrl::TIMEZONE:
private_data.timezone = _value;
break;
+ case PluginCtrl::INBOUND_IP_SOURCE:
+ private_data.ip_source = _value;
+ break;
}
Dbg(pi_dbg_ctl, " Setting plugin control %d to %d",
static_cast<int>(_name), _value);
diff --git a/plugins/header_rewrite/operators.h
b/plugins/header_rewrite/operators.h
index 2d273b19b9..b0943b7e19 100644
--- a/plugins/header_rewrite/operators.h
+++ b/plugins/header_rewrite/operators.h
@@ -466,6 +466,7 @@ public:
enum class PluginCtrl {
TIMEZONE,
+ INBOUND_IP_SOURCE,
};
protected:
diff --git a/plugins/header_rewrite/statement.h
b/plugins/header_rewrite/statement.h
index bf1020451b..acbdcd69d0 100644
--- a/plugins/header_rewrite/statement.h
+++ b/plugins/header_rewrite/statement.h
@@ -208,8 +208,17 @@ private:
union PrivateSlotData {
uint64_t raw;
struct {
- uint64_t timezone : 1; // TIMEZONE_LOCAL, or TIMEZONE_GMT
+ uint64_t timezone : 1; // TIMEZONE_LOCAL, or TIMEZONE_GMT
+ uint64_t ip_source : 2; // IP_SRC_PEER, IP_SRC_PROXY, IP_SRC_FORWARDED, or
IP_SRC_PLUGIN
+ uint64_t unused : 61;
};
};
enum { TIMEZONE_LOCAL, TIMEZONE_GMT };
+
+enum {
+ IP_SRC_PEER, // Immediate connection
+ IP_SRC_PROXY, // PROXY protocl
+ // IP_SRC_FORWARDED, // Forwarded header field (TS core needs to support
the header first. It can be done by a plugin as well.)
+ // IP_SRC_PLUGIN // Plugin (Needs TS API to set and get a verified client
IP address)
+};