1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "tscore/ink_config.h"
20 #include "ts/ts.h"
21 #include "ts/remap.h"
22 #include "utilities.h"
23 
24 // Needs special OpenSSL APIs as a global plugin for early CLIENT_HELLO inspection
25 #if TS_USE_HELLO_CB
26 
27 std::string_view
getSNI(SSL * ssl)28 getSNI(SSL *ssl)
29 {
30   const char *servername = nullptr;
31   const unsigned char *p;
32   size_t remaining, len = 0;
33 
34   // Parse the server name if the get extension call succeeds and there are more than 2 bytes to parse
35   if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &p, &remaining) && remaining > 2) {
36     // Parse to get to the name, originally from test/handshake_helper.c in openssl tree
37     /* Extract the length of the supplied list of names. */
38     len = *(p++) << 8;
39     len += *(p++);
40     if (len + 2 == remaining) {
41       remaining = len;
42       /*
43        * The list in practice only has a single element, so we only consider
44        * the first one.
45        */
46       if (*p++ == TLSEXT_NAMETYPE_host_name) {
47         remaining--;
48         /* Now we can finally pull out the byte array with the actual hostname. */
49         if (remaining > 2) {
50           len = *(p++) << 8;
51           len += *(p++);
52           if (len + 2 <= remaining) {
53             servername = reinterpret_cast<const char *>(p);
54           }
55         }
56       }
57     }
58   }
59 
60   return std::string_view(servername, servername ? len : 0);
61 }
62 
63 #endif
64 
65 ///////////////////////////////////////////////////////////////////////////////
66 // Add a header with the delay imposed on this transaction. This can be used
67 // for logging, and other types of metrics.
68 //
69 void
delayHeader(TSHttpTxn txnp,std::string & header,std::chrono::milliseconds delay)70 delayHeader(TSHttpTxn txnp, std::string &header, std::chrono::milliseconds delay)
71 {
72   if (header.size() > 0) {
73     TSMLoc hdr_loc   = nullptr;
74     TSMBuffer bufp   = nullptr;
75     TSMLoc field_loc = nullptr;
76 
77     if (TS_SUCCESS == TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc)) {
78       if (TS_SUCCESS == TSMimeHdrFieldCreateNamed(bufp, hdr_loc, header.c_str(), header.size(), &field_loc)) {
79         if (TS_SUCCESS == TSMimeHdrFieldValueIntSet(bufp, hdr_loc, field_loc, -1, static_cast<int>(delay.count()))) {
80           TSDebug(PLUGIN_NAME, "Added client request header; %s: %d", header.c_str(), static_cast<int>(delay.count()));
81           TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc);
82         }
83         TSHandleMLocRelease(bufp, hdr_loc, field_loc);
84       }
85       TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
86     }
87   }
88 }
89 
90 ///////////////////////////////////////////////////////////////////////////////
91 // Add a header with the delay imposed on this transaction. This can be used
92 // for logging, and other types of metrics.
93 //
94 void
retryAfter(TSHttpTxn txnp,unsigned retry)95 retryAfter(TSHttpTxn txnp, unsigned retry)
96 {
97   if (retry > 0) {
98     TSMLoc hdr_loc   = nullptr;
99     TSMBuffer bufp   = nullptr;
100     TSMLoc field_loc = nullptr;
101 
102     if (TS_SUCCESS == TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc)) {
103       if (TS_SUCCESS == TSMimeHdrFieldCreateNamed(bufp, hdr_loc, "Retry-After", 11, &field_loc)) {
104         if (TS_SUCCESS == TSMimeHdrFieldValueIntSet(bufp, hdr_loc, field_loc, -1, retry)) {
105           TSDebug(PLUGIN_NAME, "Added a Retry-After: %u", retry);
106           TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc);
107         }
108         TSHandleMLocRelease(bufp, hdr_loc, field_loc);
109       }
110       TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
111     }
112   }
113 }
114