You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2017/07/09 21:25:56 UTC
[trafficserver] branch master updated: header_rewrite: Add
"INBOUND" condition for data on the inbound network connection.
This is an automated email from the ASF dual-hosted git repository.
amc 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 cbca361 header_rewrite: Add "INBOUND" condition for data on the inbound network connection.
cbca361 is described below
commit cbca36172be9da8e1c5378b6160d028a7bdbe449
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Fri Jul 7 17:22:00 2017 -0500
header_rewrite: Add "INBOUND" condition for data on the inbound network connection.
---
doc/_build/html/.gitignore | 0
doc/admin-guide/plugins/header_rewrite.en.rst | 115 +++++++++++++++++-------
plugins/header_rewrite/conditions.cc | 123 ++++++++++++++++++++++++++
plugins/header_rewrite/conditions.h | 25 ++++++
plugins/header_rewrite/expander.cc | 21 +++++
plugins/header_rewrite/factory.cc | 2 +
plugins/header_rewrite/statement.h | 13 +++
7 files changed, 265 insertions(+), 34 deletions(-)
diff --git a/doc/_build/html/.gitignore b/doc/_build/html/.gitignore
deleted file mode 100644
index e69de29..0000000
diff --git a/doc/admin-guide/plugins/header_rewrite.en.rst b/doc/admin-guide/plugins/header_rewrite.en.rst
index 76127b0..418498c 100644
--- a/doc/admin-guide/plugins/header_rewrite.en.rst
+++ b/doc/admin-guide/plugins/header_rewrite.en.rst
@@ -16,6 +16,7 @@
under the License.
.. include:: ../../common.defs
+.. highlight:: none
.. _admin-plugins-header-rewrite:
@@ -183,7 +184,7 @@ CLIENT-IP
Remote IP address, as a string, of the client connection for the current
transaction.
-This condition is *deprecated* as of ATS v7.1.x, please use %{IP:CLIENT} instead.
+This condition is *deprecated* as of ATS v7.1.x, please use `%{INBOUND:REMOTE-ADDR}` instead.
CLIENT-URL
~~~~~~~~~~
@@ -276,7 +277,7 @@ ID
This condition provides access to three identifier values that ATS uses
internally for things like logging and debugging. Since these are IDs, they
are mostly useful as a value (operand) to other operators. The three types of
-IDs are
+IDs are ::
%{ID:REQUEST} A unique, sequence number for the transaction
%{ID:PROCESS} A UUID string, generated every time ATS restarts
@@ -287,6 +288,43 @@ arguments to another operator. For example::
set-header ATS-Req-UUID %{ID:UNIQUE}
+INBOUND
+~~~~~~~
+::
+
+ cond %{INBOUND:TLS} /./
+
+This condition provides access to information about the inbound (client, user agent) connection to ATS.
+The data that can be checked is ::
+
+ %{INBOUND:LOCAL-ADDR} The local (ATS) address for the connection. Equivalent to %{IP:INBOUND}.
+ %{INBOUND:LOCAL-PORT} The local (ATS) port for the connection. Equivalent to %{INCOMING-PORT}.
+ %{INBOUND:REMOTE-ADDR} The client address for the connection. Equivalent to %{IP::CLIENT}.
+ %{INBOUND:REMOTE-PORT} The client port for the connection.
+ %{INBOUND:TLS} The TLS protocol if the connection is over TLS, otherwise the empty string.
+ %{INBOUND:H2} The string "h2" if the connection is HTTP/2, otherwise the empty string.
+ %{INBOUND:IPV4} The string "ipv4" if the connection is IPv4, otherwise the emtpy string.
+ %{INBOUND:IPV6} The string "ipv6" if the connection is IPv6, otherwise the empty string.
+ %{INBOUND:IP-FAMILY} The IP family, either "ipv4" or "ipv6".
+ %{INBOUND:STACK} The full protocol stack separated by ','.
+
+All of the tags generated by this condition are from the :ref:`protocol stack tags <protocol_tags>`.
+
+Because of the implicit match rules, using these as conditions is a bit unexpected. The condition
+listed above will be true if the inbound connection is over TLS because ``%{INBOUND:TLS}`` will only
+return a non-empty string for TLS connections. In contrast ::
+
+ cond %{INBOUND:TLS}
+
+will be true for *non*-TLS connections because it will be true when ``%{INBOUND:TLS}`` is the empty
+string. This happens because the default matching is equality and the default value the empty
+string. Therefore the condition is treated as if it were ::
+
+ cond %{INBOUND:TLS}=""
+
+which is true when the connection is not TLS. The arguments ``H2``, ``IPV4``, and ``IPV6`` work the
+same way.
+
INCOMING-PORT
~~~~~~~~~~~~~
@@ -297,6 +335,8 @@ INCOMING-PORT
TCP port, as a decimal integer, on which the incoming client connection was
made.
+This condition is *deprecated* as of ATS v8.0.x, please use ``%{INBOUND:LOCAL-PORT}`` instead.
+
IP
~~
::
@@ -307,15 +347,14 @@ This is one of four possible IPs associated with the transaction, with the
possible parts being
::
- %{IP:CLIENT} Clients IP
- %{IP:INBOUND} ATS's server IP the client connected to
- %{IP:SERVER} Upstream (next-hop) server IP (typically origin, or parent)
- %{IP:OUTBOUND} ATS's outbound IP, that was used to connect upstream (next-hop)
+ %{IP:CLIENT} Client's IP address. Equivalent to %{INBOUND:REMOTE-ADDR}.
+ %{IP:INBOUND} ATS's IP address to which the client connected. Equivalent to %{INBOUND:LOCAL-ADDR}
+ %{IP:SERVER} Upstream (next-hop) server IP address (typically origin, or parent)
+ %{IP:OUTBOUND} ATS's outbound IP address, that was used to connect upstream (next-hop)
-Note that both %{IP:SERVER} and %{IP:OUTBOUND} can be unset, in which case the
+Note that both `%{IP:SERVER}` and `%{IP:OUTBOUND}` can be unset, in which case the
empty string is returned. The common use for this condition is
-actually as a value to an operator, e.g.
-::
+actually as a value to an operator, e.g. ::
cond %{SEND_RESPONSE_HDR_HOOK}
set-header X-Client-IP %{IP:CLIENT}
@@ -445,12 +484,8 @@ TXN-COUNT
cond %{TXN-COUNT} <operand>
-Returns the current HTTP client session, which permits detection of requests
-which are sharing a client session. Shared client sessions occur when multiple
-simultaneous requests are received for the same cache object. Instead of
-contacting the origin server separately for each of those client requests, one
-origin connection is used to fulfill all of the requests assigned to the shared
-client session.
+Returns the number of transactions (including the current one) that have been sent on the current
+client connection. This can be used to detect if the current transaction is the first transaction.
URL
~~~
@@ -735,20 +770,31 @@ QSA Append the results of the rule to the query string.
Variable Expansion
------------------
-Only limited variable expansion is supported in `add-header`_ and `set-header`_
-. Supported substitutions are currently:
-
-============ ==================================================================
-Variable Description
-============ ==================================================================
-%<proto> Protocol
-%<port> Port
-%<chi> Client IP
-%<cqhl> Client request length
-%<cqhm> Client HTTP method
-%<cque> Client effective URI
-%<cquup> Client unmapped URI path
-============ ==================================================================
+Only limited variable expansion is supported in `add-header`_ and `set-header`_ . Supported
+substitutions are currently:
+
+======================= ==================================================================================
+Variable Description
+======================= ==================================================================================
+%<proto> Protocol
+%<port> Port
+%<chi> Client IP
+%<cqhl> Client request length
+%<cqhm> Client HTTP method
+%<cque> Client effective URI
+%<cquup> Client unmapped URI path
+%<INBOUND:LOCAL-ADDR> The local (ATS) address for the inbound connection.
+%<INBOUND:LOCAL-PORT> The local (ATS) port for the inbound connection.
+%<INBOUND:REMOTE-ADDR> The client address for the inbound connectoin.
+%<INBOUND:REMOTE-PORT> The client port for the inbound connectoin.
+%<INBOUND:TLS> The TLS protocol for the inbound connection if it is over TLS, otherwise the
+ empty string.
+%<INBOUND:H2> The string "h2" if the inbound connection is HTTP/2, otherwise the empty string.
+%<INBOUND:IPV4> The string "ipv4" if the inbound connection is IPv4, otherwise the emtpy string.
+%<INBOUND:IPV6> The string "ipv6" if the inbound connection is IPv6, otherwise the empty string.
+%<INBOUND:IP-FAMILY> The IP family of the inbound connection (either "ipv4" or "ipv6").
+%<INBOUND:STACK> The full protocol stack of the inbound connection separated by ','.
+======================= ==================================================================================
Variables to be expanded must be enclosed in double quotes ``"``, as in this example using the arbitrary header
``Custom-Client-IP``::
@@ -1057,7 +1103,7 @@ Useless Example From Purpose
Even that useless example from `Purpose`_ in the beginning of this document is
possible to accomplish::
- cond %{INCOMING-PORT} =8090
+ cond %{INBOUND:LOCAL-PORT} =8090
cond %{METHOD} =HEAD
cond %{CLIENT-HEADER:Accept-Language} /es-py/ [NOT]
cond %{STATUS} =304 [OR]
@@ -1069,7 +1115,7 @@ Add Cache Control Headers Based on Origin Path
This rule adds cache control headers to CDN responses based matching the origin
path. One provides a max age and the other provides a “no-cache” statement to
-two different file paths.::
+two different file paths. ::
cond %{SEND_RESPONSE_HDR_HOOK}
cond %{PATH} /examplepath1/
@@ -1104,8 +1150,9 @@ already set to some value, and the status code is a 2xx::
Add HSTS
--------
-Add the HTTP Strict Transport Security (HSTS) header if it does not exist: ::
+Add the HTTP Strict Transport Security (HSTS) header if it does not exist and the inbound connection is TLS::
cond %{READ_RESPONSE_HDR_HOOK} [AND]
- cond %{HEADER:Strict-Transport-Security} =""
- set-header Strict-Transport-Security "Strict-Transport-Security: max-age=63072000; includeSubDomains; preload"
+ cond %{HEADER:Strict-Transport-Security} ="" [AND]
+ cond %{INBOUND:TLS} /./
+ set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
diff --git a/plugins/header_rewrite/conditions.cc b/plugins/header_rewrite/conditions.cc
index 6b95892..f2f81cb 100644
--- a/plugins/header_rewrite/conditions.cc
+++ b/plugins/header_rewrite/conditions.cc
@@ -24,6 +24,7 @@
#include <arpa/inet.h>
#include <cctype>
#include <sstream>
+#include <array>
#include "ts/ts.h"
@@ -1181,3 +1182,125 @@ ConditionId::eval(const Resources &res)
return rval;
}
}
+
+void
+ConditionInbound::initialize(Parser &p)
+{
+ Condition::initialize(p);
+
+ MatcherType *match = new MatcherType(_cond_op);
+
+ match->set(p.get_arg());
+ _matcher = match;
+}
+
+void
+ConditionInbound::set_qualifier(const std::string &q)
+{
+ Condition::set_qualifier(q);
+
+ TSDebug(PLUGIN_NAME, "\tParsing %%{%s:%s} qualifier", TAG, q.c_str());
+
+ if (q == "LOCAL-ADDR") {
+ _net_qual = NET_QUAL_LOCAL_ADDR;
+ } else if (q == "LOCAL-PORT") {
+ _net_qual = NET_QUAL_LOCAL_PORT;
+ } else if (q == "REMOTE-ADDR") {
+ _net_qual = NET_QUAL_REMOTE_ADDR;
+ } else if (q == "REMOTE-PORT") {
+ _net_qual = NET_QUAL_REMOTE_PORT;
+ } else if (q == "TLS") {
+ _net_qual = NET_QUAL_TLS;
+ } else if (q == "H2") {
+ _net_qual = NET_QUAL_H2;
+ } else if (q == "IPV4") {
+ _net_qual = NET_QUAL_IPV4;
+ } else if (q == "IPV6") {
+ _net_qual = NET_QUAL_IPV6;
+ } else if (q == "IP-FAMILY") {
+ _net_qual = NET_QUAL_IP_FAMILY;
+ } else if (q == "STACK") {
+ _net_qual = NET_QUAL_STACK;
+ } else {
+ TSError("[%s] Unknown %s() qualifier: %s", PLUGIN_NAME, TAG, q.c_str());
+ }
+}
+
+bool
+ConditionInbound::eval(const Resources &res)
+{
+ std::string s;
+
+ append_value(s, res);
+ bool rval = static_cast<const Matchers<std::string> *>(_matcher)->test(s);
+
+ TSDebug(PLUGIN_NAME, "Evaluating %s(): %s - rval: %d", TAG, s.c_str(), rval);
+
+ return rval;
+}
+
+void
+ConditionInbound::append_value(std::string &s, const Resources &res)
+{
+ this->append_value(s, res, _net_qual);
+}
+
+void
+ConditionInbound::append_value(std::string &s, const Resources &res, NetworkSessionQualifiers qual)
+{
+ const char *zret = nullptr;
+ char text[INET6_ADDRSTRLEN];
+
+ switch (qual) {
+ case NET_QUAL_LOCAL_ADDR: {
+ zret = getIP(TSHttpTxnIncomingAddrGet(res.txnp), text);
+ } break;
+ case NET_QUAL_LOCAL_PORT: {
+ uint16_t port = getPort(TSHttpTxnIncomingAddrGet(res.txnp));
+ snprintf(text, sizeof(text), "%d", port);
+ zret = text;
+ } break;
+ case NET_QUAL_REMOTE_ADDR: {
+ zret = getIP(TSHttpTxnClientAddrGet(res.txnp), text);
+ } break;
+ case NET_QUAL_REMOTE_PORT: {
+ uint16_t port = getPort(TSHttpTxnClientAddrGet(res.txnp));
+ snprintf(text, sizeof(text), "%d", port);
+ zret = text;
+ } break;
+ case NET_QUAL_TLS:
+ zret = TSHttpTxnClientProtocolStackContains(res.txnp, "tls/");
+ break;
+ case NET_QUAL_H2:
+ zret = TSHttpTxnClientProtocolStackContains(res.txnp, "h2");
+ break;
+ case NET_QUAL_IPV4:
+ zret = TSHttpTxnClientProtocolStackContains(res.txnp, "ipv4");
+ break;
+ case NET_QUAL_IPV6:
+ zret = TSHttpTxnClientProtocolStackContains(res.txnp, "ipv6");
+ break;
+ case NET_QUAL_IP_FAMILY:
+ zret = TSHttpTxnClientProtocolStackContains(res.txnp, "ip");
+ break;
+ case NET_QUAL_STACK: {
+ std::array<char const *, 8> tags;
+ int count = 0;
+ size_t len = 0;
+ TSHttpTxnClientProtocolStackGet(res.txnp, tags.size(), tags.data(), &count);
+ for (int i = 0; i < count; ++i) {
+ len += 1 + strlen(tags[i]);
+ }
+ s.reserve(len);
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ s += ',';
+ s += tags[i];
+ }
+ } break;
+ }
+
+ if (zret) {
+ s += zret;
+ }
+}
diff --git a/plugins/header_rewrite/conditions.h b/plugins/header_rewrite/conditions.h
index 640f1a5..2119b4b 100644
--- a/plugins/header_rewrite/conditions.h
+++ b/plugins/header_rewrite/conditions.h
@@ -498,4 +498,29 @@ private:
IdQualifiers _id_qual;
};
+/// Information about the inbound (client) session.
+class ConditionInbound : public Condition
+{
+ using MatcherType = Matchers<std::string>;
+ using self = ConditionInbound;
+
+public:
+ explicit ConditionInbound() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionInbound"); };
+ ConditionInbound(self &) = delete;
+ self &operator=(self &) = delete;
+
+ void initialize(Parser &p);
+ void set_qualifier(const std::string &q);
+ void append_value(std::string &s, const Resources &res);
+ static void append_value(std::string &s, const Resources &res, NetworkSessionQualifiers qual);
+
+ static constexpr const char *TAG = "INBOUND";
+
+protected:
+ bool eval(const Resources &res);
+
+private:
+ NetworkSessionQualifiers _net_qual = NET_QUAL_STACK;
+};
+
#endif // __CONDITIONS_H
diff --git a/plugins/header_rewrite/expander.cc b/plugins/header_rewrite/expander.cc
index ceb46b7..dd3d1ab 100644
--- a/plugins/header_rewrite/expander.cc
+++ b/plugins/header_rewrite/expander.cc
@@ -28,6 +28,7 @@
#include "statement.h"
#include "parser.h"
#include "expander.h"
+#include "conditions.h"
// Main expander method
std::string
@@ -122,6 +123,26 @@ VariableExpander::expand(const Resources &res)
}
free(url);
url = nullptr;
+ } else if (variable == "%<INBOUND:REMOTE-ADDR>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_REMOTE_ADDR);
+ } else if (variable == "%<INBOUND:REMOTE-PORT>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_REMOTE_PORT);
+ } else if (variable == "%<INBOUND:LOCAL-ADDR>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_LOCAL_ADDR);
+ } else if (variable == "%<INBOUND:LOCAL-PORT>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_LOCAL_PORT);
+ } else if (variable == "%<INBOUND:TLS>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_TLS);
+ } else if (variable == "%<INBOUND:H2>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_H2);
+ } else if (variable == "%<INBOUND:IPV4>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_IPV4);
+ } else if (variable == "%<INBOUND:IPV6>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_IPV6);
+ } else if (variable == "%<INBOUND:IP-FAMILY>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_IP_FAMILY);
+ } else if (variable == "%<INBOUND:STACK>") {
+ ConditionInbound::append_value(resolved_variable, res, NET_QUAL_STACK);
}
// TODO(SaveTheRbtz): Can be optimized
diff --git a/plugins/header_rewrite/factory.cc b/plugins/header_rewrite/factory.cc
index 3b70c7a..28defb7 100644
--- a/plugins/header_rewrite/factory.cc
+++ b/plugins/header_rewrite/factory.cc
@@ -141,6 +141,8 @@ condition_factory(const std::string &cond)
c = new ConditionGeo();
} else if (c_name == "ID") {
c = new ConditionId();
+ } else if (c_name == "INBOUND") {
+ c = new ConditionInbound();
} else {
TSError("[%s] Unknown condition: %s", PLUGIN_NAME, c_name.c_str());
return nullptr;
diff --git a/plugins/header_rewrite/statement.h b/plugins/header_rewrite/statement.h
index 69e2df5..8e538ba 100644
--- a/plugins/header_rewrite/statement.h
+++ b/plugins/header_rewrite/statement.h
@@ -81,6 +81,19 @@ enum IpQualifiers {
IP_QUAL_OUTBOUND,
};
+enum NetworkSessionQualifiers {
+ NET_QUAL_LOCAL_ADDR, ///< Local address.
+ NET_QUAL_LOCAL_PORT, ///< Local port.
+ NET_QUAL_REMOTE_ADDR, ///< Remote address.
+ NET_QUAL_REMOTE_PORT, ///< Remote port.
+ NET_QUAL_TLS, ///< TLS protocol
+ NET_QUAL_H2, ///< 'h2' or not.
+ NET_QUAL_IPV4, ///< 'ipv4' or not.
+ NET_QUAL_IPV6, ///< 'ipv6' or not.
+ NET_QUAL_IP_FAMILY, ///< IP protocol family.
+ NET_QUAL_STACK, ///< Full protocol stack.
+};
+
class Statement
{
public:
--
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].