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 b156314  TLS Bridge: Fix error where connect failure lead to a silent 
timeout. The error reporting back to the original user agent was also improved. 
The documentation was updated with more details on configuring without 
disabling remap required.
b156314 is described below

commit b156314dd8d7c6f918a3154b33340a80bc0dcf95
Author: Alan M. Carroll <[email protected]>
AuthorDate: Wed Nov 28 13:19:38 2018 -0600

    TLS Bridge: Fix error where connect failure lead to a silent timeout.
    The error reporting back to the original user agent was also improved.
    The documentation was updated with more details on configuring without 
disabling remap required.
---
 .../plugins/example-plugins/tls_bridge.en.rst      | 84 ++++++++++++++--------
 plugins/experimental/tls_bridge/tls_bridge.cc      | 39 ++++------
 2 files changed, 67 insertions(+), 56 deletions(-)

diff --git a/doc/developer-guide/plugins/example-plugins/tls_bridge.en.rst 
b/doc/developer-guide/plugins/example-plugins/tls_bridge.en.rst
index 0530afa..85836c2 100644
--- a/doc/developer-guide/plugins/example-plugins/tls_bridge.en.rst
+++ b/doc/developer-guide/plugins/example-plugins/tls_bridge.en.rst
@@ -20,10 +20,10 @@
 |Name|
 **********
 
-This plugin is used to provide secured TLS tunnels for connections between a 
Client and a Service
-via two gateway |TS| instances. By configuring the |TS| instances the level of 
security in the
-tunnel can be easily controlled for all communications across the tunnels 
without having to update
-the client or service.
+This plugin is used to provide TLS tunnels for connections between a Client 
and a Service via two
+gateway |TS| instances using explicit proxying. By configuring the |TS| 
instances the level of
+security in the tunnel can be easily controlled for all communications across 
the tunnels without
+having to update the client or service.
 
 Description
 ===========
@@ -47,24 +47,26 @@ The tunnel is sustained by two instances of |TS|.
    [Ingress ATS] ..> [tls_bridge\nPlugin] : Uses
 
 
-The ingress |TS| accepts a connection from the Client. This connection gets 
intercepted by the
-|Name| plugin inside |TS|. The plugin then makes a TLS connection to the peer 
|TS| using the
-configured level of security. The original request from the Client to the 
ingress |TS| is then sent
-to the peer |TS| to create a connection from the peer |TS| to the Service. 
After this the
-Client has a virtual circut to the Service and can use any TCP based 
communication (including TLS).
-Effectively the plugin causes the connectivity to work as if the Client had 
done the ``CONNECT``
-directly to the peer |TS|. Note this means the DNS lookup for the Service is 
done by the peer |TS|,
-not the ingress |TS|.
+The ingress |TS| accepts an HTTP ``CONNECT`` request from the Client. This 
connection gets
+intercepted by the |Name| plugin inside |TS| if the destination matches one of 
the configured
+destinations. The plugin then makes a TLS connection to the peer |TS| using 
the configured level of
+security. The original ``CONNECT`` request from the Client to the ingress |TS| 
is then sent to the
+peer |TS| to create a connection from the peer |TS| to the Service. After this 
the Client has a
+virtual circut to the Service and can use any TCP based communication 
(including TLS). Effectively
+the plugin causes the explicit proxy to work as if the Client had done the 
``CONNECT`` directly to
+the peer |TS|. Note this means the DNS lookup for the Service is done by the 
peer |TS|, not the
+ingress |TS|.
 
-The plugin is configured with a mapping of Service names to peer |TS| 
instances. The Service
-names are URLs which will in the original HTTP request made by the Client 
after connecting to the
-ingress |TS|. This means the FQDN for the Service is not resolved in the 
environment of the peer
+The plugin is configured with a mapping of Service names to peer |TS| 
instances. The Service names
+are URLs which will be in the original HTTP request made by the Client after 
connecting to the
+ingress |TS|. This means the FQDN for the Service is resolved in the 
environment of the peer
 |TS| and not the ingress |TS|.
 
 Configuration
 =============
 
-|Name| requires at least two instances of |TS| (Ingress and Peer).
+|Name| requires at least two instances of |TS| (Ingress and Peer). The client 
connects to the
+ingress |TS|, and the peer |TS| connects to the service.
 
 #. Disable caching on |TS| in ``records.config``::
 
@@ -72,32 +74,46 @@ Configuration
 
 #. Configure the ports.
 
-   *  The Peer |TS| must be listening on an SSL enabled proxy port. For 
instance, if the proxy port for the Peer is 4443, then configuration in 
``records.config`` would have::
+   *  The Peer |TS| must be listening on an SSL enabled proxy port. For 
instance, if the proxy port
+      for the Peer is 4443, then configuration in ``records.config`` would 
have::
 
          CONFIG proxy.config.http.server_ports STRING 4443:ssl
 
-   *  The Ingress |TS| must allow ``CONNECT`` to the Peer proxy port. This 
would be set in ``records.config`` by::
+   *  The Ingress |TS| must allow ``CONNECT`` to the Peer proxy port. This 
would be set in
+      ``records.config`` by::
 
          CONFIG proxy.config.http.connect_ports STRING 4443
 
       The Ingress |TS| also needs ``proxy.config.http.server_ports`` 
configured to have proxy ports
       to which the Client can connect.
 
-#. Remap is not required, however, |TS| requires remap in order to accept the 
request. This can be done by disabling the remap requirement::
+#. Remap on the ingress is not required, however, |TS| requires remap in order 
to accept the
+   request. This can be done by disabling the remap requirement::
 
       CONFIG proxy.config.url_remap.remap_required INT 0
 
-   In this case |TS| will act as an open proxy which is unlikely to be a good 
idea. |TS| will need
-   to run in a restricted environment or use access control (via 
``ip_allow.config`` or
-   ``iptables``).
+   In this case |TS| will act as an open proxy which is unlikely to be a good 
idea, therefore if
+   this approach is used |TS| will need to run in a restricted environment or 
use access control
+   (via ``ip_allow.config`` or ``iptables``).
 
-   If this is unsuitable then an identity remap rule can be added for the peer 
|TS|. If the peer |TS|
-   was named "peer.ats" then the remap rule would be ::
+   If this is unsuitable then an identity remap rule can be added for the peer 
|TS|. If the peer
+   |TS| was named "peer.ats" and it listens on port 4443, then the remap rule 
would be ::
 
-      remap https://peer.ats https://peer.ats
+      remap https://peer.ats:4443 https://peer.ats:4443
 
    Remapping will be disabled for the user agent connection and so it will not 
need a rule.
 
+#. If remap is required on the peer to enable the outbound connection from the 
peer to the service
+   (it is not explicitly disabled) the destination port must be
+   explicitly stated [#]_. E.g. ::
+
+      map https://service:4443 https://service:4443
+
+   Note this remap rule cannot alter the actual HTTP transactions between the 
client and service
+   because those happen inside what is effectively a tunnel between the client 
and service, supported
+   by the two |TS| instances. This rule just allows the ``CONNECT`` sent from 
the ingress to cause a
+   tunnel connection from the peer to the service.
+
 #. Configure the Ingress |TS| to verify the Peer server certificate::
 
       CONFIG proxy.config.ssl.client.verify.server.policy STRING ENFORCED
@@ -119,16 +135,21 @@ Configuration
 #. Enable the |Name| plugin in ``plugin.config``. The plugin is configured by 
arguments in
    ``plugin.config``. These are arguments are in pairs of a *destination* and 
a *peer*. The
    destination is an anchored regular expression which is matched against the 
host name in the Client
-   ``CONNECT``. The destinations are checked in order and the first match is 
used to select the Peer
+   ``CONNECT``. The destinations are checked in order and the first match is 
used to select the peer
    |TS|. The peer should be an FQDN or IP address with an optional port. For 
the example above, if
-   the Peer |TS| was named "peer.example.com" on port 4443 and the Service at 
``*.service.com``, the
-   peer argument would be "peer.example.com:4443". In ``plugin.config`` this 
would be::
+   the Peer |TS| was named "peer.ats" on port 4443 and the Service at 
``*.service.com``, the
+   peer argument would be "peer.ats:4443". In ``plugin.config`` this would be::
 
-      tls_bridge.so .*[.]service[.]com peer.example.com:4443
+      tls_bridge.so .*[.]service[.]com peer.ats:4443
 
    Note the '.' characters are escaped with brackets so that, for instance, 
"someservice.com" does
    not match the rule.
 
+   If there was another service, "\*.altsvc.ats", via a different peer 
"altpeer.ats" on port 4443,
+   the configuration would be ::
+
+      tls_bridge.so .*[.]service[.]com peer.ats:4443 .*[.]altsvc.ats 
altpeer.ats:4443
+
 Notes
 =====
 
@@ -255,3 +276,8 @@ Debugging
 ---------
 
 Debugging messages for the plugin can be enabled with the "tls_bridge" debug 
tag.
+
+
+.. rubric:: Footnotes
+
+.. [#] This is likely due to a bug in |TS|, currently under investigation.
diff --git a/plugins/experimental/tls_bridge/tls_bridge.cc 
b/plugins/experimental/tls_bridge/tls_bridge.cc
index 94657ac..7cfe1e5 100644
--- a/plugins/experimental/tls_bridge/tls_bridge.cc
+++ b/plugins/experimental/tls_bridge/tls_bridge.cc
@@ -186,8 +186,6 @@ struct Bridge {
   TSHttpStatus _out_response_code = TS_HTTP_STATUS_NONE;
   /// Response reason, if not TS_HTTP_STATUS_OK
   std::string _out_response_reason;
-  /// Is the response to the user agent suspended?
-  bool _ua_response_suspended = false;
 
   /// Bridge requires a continuation for scheduling and the transaction.
   Bridge(TSCont cont, TSHttpTxn txn, TextView peer);
@@ -231,7 +229,7 @@ Bridge::net_accept(TSVConn vc)
   char buff[1024];
   int64_t n = snprintf(buff, sizeof(buff), CONNECT_FORMAT, 
static_cast<int>(_peer.size()), _peer.data());
 
-  TSDebug(PLUGIN_TAG, "Received UA VConn");
+  TSDebug(PLUGIN_TAG, "Received UA VConn, connecting to peer %.*s", 
int(_peer.size()), _peer.data());
   // UA side intercepted.
   _ua.init(vc);
   _ua.do_read(_self_cont, INT64_MAX);
@@ -315,12 +313,6 @@ Bridge::check_outbound_OK()
         }
         // 519 is POOMA, useful for debugging, but may want to change this 
later.
         _out_response_code = c ? c : static_cast<TSHttpStatus>(519);
-        if (_ua_response_suspended) {
-          this->update_ua_response();
-          TSHttpTxnReenable(_ua_txn, TS_EVENT_HTTP_CONTINUE);
-          _ua_response_suspended = false;
-          TSDebug(PLUGIN_TAG, "TXN resumed");
-        }
         _out.consume(block.data() - raw.data());
         zret = true;
         TSDebug(PLUGIN_TAG, "Outbound status %d", c);
@@ -415,24 +407,19 @@ Bridge::eos(TSVIO vio)
   }
   _out.do_close();
   _ua.do_close();
-  _out_resp_state = EOS;
-  if (_ua_response_suspended) {
-    TSHttpTxnReenable(_ua_txn, TS_EVENT_HTTP_CONTINUE);
+  if (_out_resp_state != ERROR) {
+    _out_resp_state = EOS;
   }
 }
 
 void
 Bridge::send_response_cb()
 {
-  // If the upstream response hasn't been parsed yet, make the UA response 
wait for that.
-  // Set a flag so the upstream response parser knows to update response and 
reenable.
-  if (_out_resp_state < OK) {
-    _ua_response_suspended = true;
-    TSDebug(PLUGIN_TAG, "TXN suspended");
-  } else { // Already have all the data needed to do the update, so do it and 
move on.
-    this->update_ua_response();
-    TSHttpTxnReenable(_ua_txn, TS_EVENT_HTTP_CONTINUE);
-  }
+  // This happens either after the upstream connection and the writing the 
response there,
+  // or because the upstream connection was blocked. In either case the 
upstream work is
+  // done and the original transaction can proceed.
+  this->update_ua_response();
+  TSHttpTxnReenable(_ua_txn, TS_EVENT_HTTP_CONTINUE);
 }
 
 void
@@ -441,12 +428,10 @@ Bridge::update_ua_response()
   TSMBuffer mbuf;
   TSMLoc hdr_loc;
   if (TS_SUCCESS == TSHttpTxnClientRespGet(_ua_txn, &mbuf, &hdr_loc)) {
-    // A 200 for @a out_response_code only means there wasn't an internal 
failure on the upstream
-    // CONNECT. Network and other failures get reported in this response. This 
response code will
-    // be more accurate, so use it unless it's 200, in which case use the 
stored response code if
-    // that's not 200.
-    TSHttpStatus status = TSHttpHdrStatusGet(mbuf, hdr_loc);
-    if (TS_HTTP_STATUS_OK == status && TS_HTTP_STATUS_OK != 
_out_response_code) {
+    // If there is a non-200 upstream code then that's the most accurate 
because it was from
+    // an actual upstream connection. Otherwise, let the original connection 
response code
+    // ride.
+    if (_out_response_code != TS_HTTP_STATUS_OK && _out_response_code != 
TS_HTTP_STATUS_NONE) {
       TSHttpHdrStatusSet(mbuf, hdr_loc, _out_response_code);
       if (!_out_response_reason.empty()) {
         TSHttpHdrReasonSet(mbuf, hdr_loc, _out_response_reason.data(), 
_out_response_reason.size());

Reply via email to