This is an automated email from the ASF dual-hosted git repository.
cmcfarlen pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new 9573b6e6d1 Add TSVConnPPInfoGet (#12032)
9573b6e6d1 is described below
commit 9573b6e6d12161d8c1c6dcdd92306b542d5a4108
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Wed May 14 16:53:13 2025 -0600
Add TSVConnPPInfoGet (#12032)
* Add TSVConnPPInfoGet
* Set socket type in PPv1 parser as well
* Fix nullptr dereference
* Change tye type of key parameter to uint16_t
(cherry picked from commit c4c31de48bfcfb4a7ce58e7a16804a2dc37ab57d)
---
include/ts/apidefs.h.in | 10 ++
include/ts/ts.h | 25 +++++
src/api/InkAPI.cc | 70 ++++++++++++
src/iocore/net/ProxyProtocol.cc | 2 +
tests/gold_tests/pluginTest/tsapi/CMakeLists.txt | 1 +
.../pluginTest/tsapi/test_TSVConnPPInfo.cc | 118 +++++++++++++++++++++
.../pluginTest/tsapi/test_TSVConnPPInfo.test.py | 98 +++++++++++++++++
.../pluginTest/tsapi/test_TSVConnPPInfo_curl0.gold | 1 +
.../pluginTest/tsapi/test_TSVConnPPInfo_curl1.gold | 1 +
.../tsapi/test_TSVConnPPInfo_plugin_log.gold | 2 +
10 files changed, 328 insertions(+)
diff --git a/include/ts/apidefs.h.in b/include/ts/apidefs.h.in
index 58a2f55bb8..bd37127970 100644
--- a/include/ts/apidefs.h.in
+++ b/include/ts/apidefs.h.in
@@ -649,6 +649,16 @@ enum TSHttpSsnInfoKey {
TS_SSN_INFO_RECEIVED_FRAME_COUNT,
};
+enum TSVConnPPInfoKey {
+ TS_PP_INFO_VERSION = 0x100,
+ TS_PP_INFO_SRC_ADDR,
+ TS_PP_INFO_SRC_PORT,
+ TS_PP_INFO_DST_ADDR,
+ TS_PP_INFO_DST_PORT,
+ TS_PP_INFO_PROTOCOL,
+ TS_PP_INFO_SOCK_TYPE,
+};
+
#define TS_SSN_INFO_RECEIVED_FRAME_COUNT_H2_UNKNOWN 999
#define TS_SSN_INFO_RECEIVED_FRAME_COUNT_H3_UNKNOWN 0x21
diff --git a/include/ts/ts.h b/include/ts/ts.h
index 76030df541..42998a756f 100644
--- a/include/ts/ts.h
+++ b/include/ts/ts.h
@@ -3077,3 +3077,28 @@ TSRalloc(size_t count = 1 /**< Number of instances of T
to allocate storage for.
{
return static_cast<std::remove_cv_t<T> *>(TSmalloc(count * sizeof(T)));
}
+
+/**
+ Return the particular PROXY protocol info requested.
+
+ @param vconn the vconection pointer
+ @param key the requested PROXY protocol info. One of TSVConnPPInfoKey or
TLV type ID
+ @param value a pointer to a const char pointer where the return value is
stored
+ @param length a pointer to a integer where the length of return value is
stored
+
+ @return @c TS_SUCCESS if the requested info is supported, TS_ERROR otherwise
+
+*/
+TSReturnCode TSVConnPPInfoGet(TSVConn vconn, uint16_t key, const char **value,
int *length);
+
+/**
+ Return the particular PROXY protocol info requested.
+
+ @param vconn the vconection pointer
+ @param key the requested PROXY protocol info. One of TSVConnPPInfoKey or
TLV type ID
+ @param value a pointer to a integer where the return value is stored
+
+ @return @c TS_SUCCESS if the requested info is supported, TS_ERROR otherwise
+
+*/
+TSReturnCode TSVConnPPInfoIntGet(TSVConn vconn, uint16_t key, TSMgmtInt
*value);
diff --git a/src/api/InkAPI.cc b/src/api/InkAPI.cc
index dbd68d6fc9..234d77c06a 100644
--- a/src/api/InkAPI.cc
+++ b/src/api/InkAPI.cc
@@ -8417,6 +8417,76 @@ TSVConnReenableEx(TSVConn vconn, TSEvent event)
}
}
+TSReturnCode
+TSVConnPPInfoGet(TSVConn vconn, uint16_t key, const char **value, int *length)
+{
+ NetVConnection *vc = reinterpret_cast<NetVConnection *>(vconn);
+
+ if (key < 0x100) {
+ auto &tlv = vc->get_proxy_protocol_info().tlv;
+ if (auto ite = tlv.find(key); ite != tlv.end()) {
+ *value = ite->second.data();
+ *length = ite->second.length();
+ } else {
+ return TS_ERROR;
+ }
+ } else {
+ switch (key) {
+ case TS_PP_INFO_SRC_ADDR:
+ *value = reinterpret_cast<const char
*>(vc->get_proxy_protocol_src_addr());
+ if (*value == nullptr) {
+ return TS_ERROR;
+ }
+ *length = ats_ip_size(reinterpret_cast<const sockaddr *>(*value));
+ break;
+ case TS_PP_INFO_DST_ADDR:
+ *value = reinterpret_cast<const char
*>(vc->get_proxy_protocol_dst_addr());
+ if (*value == nullptr) {
+ return TS_ERROR;
+ }
+ *length = ats_ip_size(reinterpret_cast<const sockaddr *>(*value));
+ break;
+ default:
+ return TS_ERROR;
+ }
+ }
+
+ return TS_SUCCESS;
+}
+
+TSReturnCode
+TSVConnPPInfoIntGet(TSVConn vconn, uint16_t key, TSMgmtInt *value)
+{
+ NetVConnection *vc = reinterpret_cast<NetVConnection *>(vconn);
+
+ if (key < 0x100) {
+ // Unknown type value cannot be returned as an integer
+ return TS_ERROR;
+ } else {
+ switch (key) {
+ case TS_PP_INFO_VERSION:
+ *value = static_cast<TSMgmtInt>(vc->get_proxy_protocol_version());
+ break;
+ case TS_PP_INFO_SRC_PORT:
+ *value = static_cast<TSMgmtInt>(vc->get_proxy_protocol_src_port());
+ break;
+ case TS_PP_INFO_DST_PORT:
+ *value = static_cast<TSMgmtInt>(vc->get_proxy_protocol_dst_port());
+ break;
+ case TS_PP_INFO_PROTOCOL:
+ *value = static_cast<TSMgmtInt>(vc->get_proxy_protocol_info().ip_family);
+ break;
+ case TS_PP_INFO_SOCK_TYPE:
+ *value = static_cast<TSMgmtInt>(vc->get_proxy_protocol_info().type);
+ break;
+ default:
+ return TS_ERROR;
+ }
+ }
+
+ return TS_SUCCESS;
+}
+
TSSslSession
TSSslSessionGet(const TSSslSessionID *session_id)
{
diff --git a/src/iocore/net/ProxyProtocol.cc b/src/iocore/net/ProxyProtocol.cc
index e775c99357..27b1c84301 100644
--- a/src/iocore/net/ProxyProtocol.cc
+++ b/src/iocore/net/ProxyProtocol.cc
@@ -145,6 +145,7 @@ proxy_protocol_v1_parse(ProxyProtocol *pp_info,
swoc::TextView hdr)
}
pp_info->ip_family = AF_INET;
+ pp_info->type = SOCK_STREAM;
} else if (hdr.starts_with(PPv1_PROTO_TCP6)) {
token = hdr.split_prefix_at(' ');
if (0 == token.size()) {
@@ -152,6 +153,7 @@ proxy_protocol_v1_parse(ProxyProtocol *pp_info,
swoc::TextView hdr)
}
pp_info->ip_family = AF_INET6;
+ pp_info->type = SOCK_STREAM;
} else {
return 0;
}
diff --git a/tests/gold_tests/pluginTest/tsapi/CMakeLists.txt
b/tests/gold_tests/pluginTest/tsapi/CMakeLists.txt
index a03fa94037..d5e3a088fa 100644
--- a/tests/gold_tests/pluginTest/tsapi/CMakeLists.txt
+++ b/tests/gold_tests/pluginTest/tsapi/CMakeLists.txt
@@ -18,3 +18,4 @@
add_autest_plugin(test_tsapi test_tsapi.cc)
add_autest_plugin(test_TSHttpTxnServerAddrSet test_TSHttpTxnServerAddrSet.cc)
add_autest_plugin(test_TSHttpSsnInfo test_TSHttpSsnInfo.cc)
+add_autest_plugin(test_TSVConnPPInfo test_TSVConnPPInfo.cc)
diff --git a/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo.cc
b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo.cc
new file mode 100644
index 0000000000..6aa78118ac
--- /dev/null
+++ b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo.cc
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fstream>
+#include <cstdlib>
+#include <arpa/inet.h>
+
+#include <ts/ts.h>
+
+namespace
+{
+#define PINAME "test_TSVConnPPInfo"
+char PIName[] = PINAME;
+
+DbgCtl dbg_ctl{PIName};
+
+// NOTE: It's important to flush this after writing so that a gold test using
this plugin can examine the log before TS
+// terminates.
+//
+std::fstream logFile;
+
+void
+handle_ssn_start(TSHttpSsn ssn)
+{
+ TSVConn vconn = TSHttpSsnClientVConnGet(ssn);
+ TSMgmtInt pp_ver;
+ auto ret = TSVConnPPInfoIntGet(vconn, TS_PP_INFO_VERSION, &pp_ver);
+ if (ret == TS_SUCCESS && pp_ver != 0) {
+ TSMgmtInt info[2];
+ const struct sockaddr_in *addr[2];
+ int addr_len[2];
+ TSVConnPPInfoIntGet(vconn, TS_PP_INFO_PROTOCOL, &info[0]);
+ TSVConnPPInfoIntGet(vconn, TS_PP_INFO_SOCK_TYPE, &info[1]);
+ TSVConnPPInfoGet(vconn, TS_PP_INFO_SRC_ADDR, reinterpret_cast<const char
**>(&addr[0]), &addr_len[0]);
+ TSVConnPPInfoGet(vconn, TS_PP_INFO_DST_ADDR, reinterpret_cast<const char
**>(&addr[1]), &addr_len[1]);
+
+ logFile << "PP Info Received:" << "V" << pp_ver << "," << "P" << info[0]
<< "," << "T" << info[1] << "," << "SRC"
+ << inet_ntoa(addr[0]->sin_addr) << "," << "DST" <<
inet_ntoa(addr[1]->sin_addr) << std::endl;
+ }
+
+ TSHttpSsnReenable(ssn, TS_EVENT_HTTP_CONTINUE);
+}
+
+int
+globalContFunc(TSCont, TSEvent event, void *eventData)
+{
+ logFile << "Global: event=" << TSHttpEventNameLookup(event) << std::endl;
+
+ Dbg(dbg_ctl, "Global: event=%s(%d) eventData=%p",
TSHttpEventNameLookup(event), event, eventData);
+
+ switch (event) {
+ case TS_EVENT_HTTP_SSN_START:
+ handle_ssn_start(static_cast<TSHttpSsn>(eventData));
+ break;
+ default:
+ break;
+ } // end switch
+
+ return 0;
+}
+
+TSCont gCont;
+
+} // end anonymous namespace
+
+void
+TSPluginInit(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */)
+{
+ TSPluginRegistrationInfo info;
+
+ info.plugin_name = PIName;
+ info.vendor_name = "Apache Software Foundation";
+ info.support_email = "[email protected]";
+
+ if (TSPluginRegister(&info) != TS_SUCCESS) {
+ TSError(PINAME ": Plugin registration failed");
+
+ return;
+ }
+
+ const char *fileSpec = std::getenv("OUTPUT_FILE");
+
+ if (nullptr == fileSpec) {
+ TSError(PINAME ": Environment variable OUTPUT_FILE not found.");
+
+ return;
+ }
+
+ // Disable output buffering for logFile, so that explicit flushing is not
necessary.
+ logFile.rdbuf()->pubsetbuf(nullptr, 0);
+
+ logFile.open(fileSpec, std::ios::out);
+ if (!logFile.is_open()) {
+ TSError(PINAME ": could not open log file \"%s\"", fileSpec);
+
+ return;
+ }
+
+ // Mutex to protect the logFile object.
+ TSMutex mtx = TSMutexCreate();
+ gCont = TSContCreate(globalContFunc, mtx);
+ TSHttpHookAdd(TS_HTTP_SSN_START_HOOK, gCont);
+}
diff --git a/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo.test.py
b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo.test.py
new file mode 100644
index 0000000000..2564d28814
--- /dev/null
+++ b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo.test.py
@@ -0,0 +1,98 @@
+'''
+'''
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+Test.Summary = '''
+Test TS API to get PROXY protocol info
+'''
+
+Test.SkipUnless(Condition.HasProgram("nghttp", "Nghttp need to be installed on
system for this test to work"),)
+Test.ContinueOnFail = True
+
+# ----
+# Setup Origin Server
+# ----
+httpbin = Test.MakeHttpBinServer("httpbin")
+
+# 128ytes
+post_body = "0123456789abcdef" * 8
+post_body_file = open(os.path.join(Test.RunDirectory, "post_body"), "w")
+post_body_file.write(post_body)
+post_body_file.close()
+
+# ----
+# Setup ATS
+# ----
+ts = Test.MakeATSProcess("ts", enable_tls=True, enable_proxy_protocol=True)
+
+# add ssl materials like key, certificates for the server
+ts.addDefaultSSLFiles()
+
+ts.Disk.remap_config.AddLines(['map /httpbin/
http://127.0.0.1:{0}/'.format(httpbin.Variables.Port)])
+
+ts.Disk.ssl_multicert_config.AddLine('dest_ip=* ssl_cert_name=server.pem
ssl_key_name=server.key')
+
+Test.PrepareTestPlugin(
+ os.path.join(Test.Variables.AtsBuildGoldTestsDir, 'pluginTest', 'tsapi',
'.libs', 'test_TSVConnPPInfo.so'), ts)
+
+ts.Disk.records_config.update(
+ {
+ 'proxy.config.diags.debug.enabled': 1,
+ 'proxy.config.diags.debug.tags':
'http|proxyprotocol|test_TSVConnPPInfo',
+ 'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
+ 'proxy.config.ssl.server.private_key.path':
'{0}'.format(ts.Variables.SSLDir)
+ })
+
+# http2_info.so will output test logging to this file.
+log_path = os.path.join(ts.Variables.LOGDIR,
"test_TSVConnPPInfo_plugin_log.txt")
+Test.Env["OUTPUT_FILE"] = log_path
+
+# ----
+# Test Cases
+# ----
+
+# plaintext HTTP
+tr = Test.AddTestRun()
+tr.TimeOut = 10
+tr.Processes.Default.Command = f"curl --haproxy-protocol --haproxy-clientip
1.2.3.4 'http://127.0.0.1:{ts.Variables.proxy_protocol_port}/httpbin/get'"
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.StartBefore(httpbin,
ready=When.PortOpen(httpbin.Variables.Port))
+tr.Processes.Default.StartBefore(Test.Processes.ts)
+tr.Processes.Default.Streams.stdout = "test_TSVConnPPInfo_curl0.gold"
+tr.StillRunningAfter = httpbin
+tr.StillRunningAfter = ts
+
+# HTTPS
+tr = Test.AddTestRun()
+tr.TimeOut = 10
+tr.Processes.Default.Command = f"curl --haproxy-protocol --haproxy-clientip
5.6.7.8 -k
'https://127.0.0.1:{ts.Variables.proxy_protocol_ssl_port}/httpbin/get'"
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Streams.stdout = "test_TSVConnPPInfo_curl1.gold"
+tr.StillRunningAfter = httpbin
+tr.StillRunningAfter = ts
+
+tr = Test.AddTestRun()
+tr.Processes.Default.Command = "echo check log"
+tr.Processes.Default.ReturnCode = 0
+f = tr.Disk.File(log_path)
+f.Content = "test_TSVConnPPInfo_plugin_log.gold"
+f.Content += Testers.ContainsExpression(
+ "PP Info Received:V1,P2,T1,SRC1.2.3.4,DST127.0.0.1", "Expected information
should be received")
+f.Content += Testers.ContainsExpression(
+ "PP Info Received:V1,P2,T1,SRC5.6.7.8,DST127.0.0.1", "Expected information
should be received")
diff --git a/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo_curl0.gold
b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo_curl0.gold
new file mode 100644
index 0000000000..cf637de588
--- /dev/null
+++ b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo_curl0.gold
@@ -0,0 +1 @@
+``
diff --git a/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo_curl1.gold
b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo_curl1.gold
new file mode 100644
index 0000000000..cf637de588
--- /dev/null
+++ b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo_curl1.gold
@@ -0,0 +1 @@
+``
diff --git
a/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo_plugin_log.gold
b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo_plugin_log.gold
new file mode 100644
index 0000000000..fd14052482
--- /dev/null
+++ b/tests/gold_tests/pluginTest/tsapi/test_TSVConnPPInfo_plugin_log.gold
@@ -0,0 +1,2 @@
+Global: event=TS_EVENT_HTTP_SSN_START
+``