diff --git a/tests/gold_tests/autest-site/verifier_client.test.ext b/tests/gold_tests/autest-site/verifier_client.test.ext index 9ff5c0311a6..cbe4c020cfc 100755 --- a/tests/gold_tests/autest-site/verifier_client.test.ext +++ b/tests/gold_tests/autest-site/verifier_client.test.ext @@ -23,8 +23,8 @@ from verifier_common import create_address_argument def _configure_client(obj, process, name, replay_path, http_ports=None, - https_ports=None, keys=None, ssl_cert='', ca_cert='', - verbose=True, other_args=''): + https_ports=None, http3_ports=None, keys=None, + ssl_cert='', ca_cert='', verbose=True, other_args=''): """ Configure the process for running the verifier-client. @@ -72,6 +72,19 @@ def _configure_client(obj, process, name, replay_path, http_ports=None, command += create_address_argument(https_ports) command += " " + if not http3_ports: + http3_ports = [4443] + if http3_ports: + command += "--connect-http3 " + command += create_address_argument(http3_ports) + command += " " + + qlog_basename = "qlog_directory" + qlog_dir = os.path.join(client_dir, qlog_basename) + command += f"--qlog-dir {qlog_dir} " + obj.Variables['qlog_dir'] = qlog_dir + + if https_ports or http3_ports: if ssl_cert == '': ssl_cert = os.path.join(obj.Variables["AtsTestToolsDir"], "proxy-verifier", "ssl", "client.pem") @@ -84,6 +97,11 @@ def _configure_client(obj, process, name, replay_path, http_ports=None, process.Setup.Copy(ssl_cert, run_ssl_cert, CopyLogic.SoftFiles) command += ' --client-cert "{}" '.format(run_ssl_cert) + tls_secrets_log_filename = "tls_secrets.txt" + tls_secrets_log_path = os.path.join(client_dir, tls_secrets_log_filename) + command += f"--tls-secrets-log-file {tls_secrets_log_path} " + obj.Variables['tls_secrets_log_path'] = tls_secrets_log_path + if ca_cert == '': ca_cert = os.path.join(obj.Variables["AtsTestToolsDir"], "proxy-verifier", "ssl", "ca.pem") @@ -114,8 +132,8 @@ def _configure_client(obj, process, name, replay_path, http_ports=None, def AddVerifierClientProcess(run, name, replay_path, http_ports=None, - https_ports=None, keys=None, ssl_cert='', ca_cert='', - verbose=True, other_args=''): + https_ports=None, http3_ports=None, keys=None, + ssl_cert='', ca_cert='', verbose=True, other_args=''): """ Set the Default process of the test run to a verifier-client Process. @@ -133,6 +151,8 @@ def AddVerifierClientProcess(run, name, replay_path, http_ports=None, https_ports: (list of ints) The set of HTTPS ports to connect on. + http3_ports: (list of ints) The set of HTTP3 ports to connect on. + ssl_cert: (path) The location of the cert for HTTPS encryption. If this is not provided and stock ssl_cert will be used. @@ -150,7 +170,8 @@ def AddVerifierClientProcess(run, name, replay_path, http_ports=None, p = run.Processes.Default _configure_client(run, p, name, replay_path, http_ports, https_ports, - keys, ssl_cert, ca_cert, verbose, other_args) + http3_ports, keys, ssl_cert, ca_cert, verbose, + other_args) return p diff --git a/tests/gold_tests/autest-site/verifier_server.test.ext b/tests/gold_tests/autest-site/verifier_server.test.ext index eab23ab4ec8..1ad922d6f43 100755 --- a/tests/gold_tests/autest-site/verifier_server.test.ext +++ b/tests/gold_tests/autest-site/verifier_server.test.ext @@ -23,7 +23,8 @@ from verifier_common import create_address_argument def _configure_server(obj, process, name, replay_path, http_ports=None, https_ports=None, - ssl_cert='', ca_cert='', verbose=True, other_args=''): + http3_ports=None, ssl_cert='', ca_cert='', verbose=True, + other_args=''): """ Configure the provided process to run a verifier-server command. @@ -70,6 +71,24 @@ def _configure_server(obj, process, name, replay_path, http_ports=None, https_po command += create_address_argument(https_ports) command += " " + if http3_ports is None: + get_port(process, "http3_port") + http3_ports = [process.Variables.http3_port] + else: + process.Variables['http3_port'] = http3_ports[0] + + # Add in the following when Proxy Verifier server-side HTTP/3 is supported. + # if len(http3_ports) > 0: + # command += '--listen-http3 ' + # command += create_address_argument(http3_ports) + # command += " " + # + # qlog_basename = "qlog_directory" + # qlog_dir = os.path.join(server_dir, qlog_basename) + # command += f"--qlog-dir {qlog_dir} " + # obj.Variables['qlog_dir'] = qlog_dir + + if https_ports or http3_ports: if ssl_cert == '': ssl_cert = os.path.join(obj.Variables["AtsTestToolsDir"], "proxy-verifier", "ssl", "server.pem") @@ -82,6 +101,11 @@ def _configure_server(obj, process, name, replay_path, http_ports=None, https_po process.Setup.Copy(ssl_cert, run_ssl_cert, CopyLogic.SoftFiles) command += ' --server-cert "{}" '.format(run_ssl_cert) + tls_secrets_log_filename = "tls_secrets.txt" + tls_secrets_log_path = os.path.join(server_dir, tls_secrets_log_filename) + command += f"--tls-secrets-log-file {tls_secrets_log_path} " + obj.Variables['tls_secrets_log_path'] = tls_secrets_log_path + if ca_cert == '': ca_cert = os.path.join(obj.Variables["AtsTestToolsDir"], "proxy-verifier", "ssl", "ca.pem") @@ -116,8 +140,8 @@ def _configure_server(obj, process, name, replay_path, http_ports=None, https_po def MakeVerifierServerProcess(test, name, replay_path, http_ports=None, - https_ports=None, ssl_cert='', ca_cert='', - verbose=True, other_args=''): + https_ports=None, http3_ports=None, ssl_cert='', + ca_cert='', verbose=True, other_args=''): """ Create a verifier-server process for the Test. @@ -137,6 +161,9 @@ def MakeVerifierServerProcess(test, name, replay_path, http_ports=None, https_ports: (list of ints) The set of HTTPS ports to listen on. If not passed in, a single open port will be selected. + http3_ports: (list of ints) The set of HTTP3 ports to listen on. If not + passed in, a single open port will be selected. + ssl_cert: (path) The location of the cert for HTTPS encryption. If this is not provided and stock ssl_cert will be used. @@ -153,13 +180,13 @@ def MakeVerifierServerProcess(test, name, replay_path, http_ports=None, """ server = test.Processes.Process(name) _configure_server(test, server, name, replay_path, http_ports, https_ports, - ssl_cert, ca_cert, verbose, other_args) + http3_ports, ssl_cert, ca_cert, verbose, other_args) return server def AddVerifierServerProcess(run, name, replay_path, http_ports=None, - https_ports=None, ssl_cert='', ca_cert='', - verbose=True, other_args=''): + https_ports=None, http3_ports=None, ssl_cert='', + ca_cert='', verbose=True, other_args=''): """ Create a verifier-server process and configure it for the given TestRun. @@ -174,7 +201,7 @@ def AddVerifierServerProcess(run, name, replay_path, http_ports=None, server = run.Processes.Process(name) _configure_server(run, server, name, replay_path, http_ports, https_ports, - ssl_cert, ca_cert, verbose, other_args) + http3_ports, ssl_cert, ca_cert, verbose, other_args) client = run.Processes.Default client.StartBefore(server) diff --git a/tests/gold_tests/pluginTest/traffic_dump/replay/http3.yaml b/tests/gold_tests/pluginTest/traffic_dump/replay/http3.yaml new file mode 100644 index 00000000000..e4eb5dd84c5 --- /dev/null +++ b/tests/gold_tests/pluginTest/traffic_dump/replay/http3.yaml @@ -0,0 +1,64 @@ +# 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. + +meta: + version: "1.0" + + blocks: + - 200_ok_response: &200_ok_response + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 16 ] + - [ Connection, close ] + +sessions: +- protocol: [ {name: http, version: 3}, + {name: tls, sni: www.tls.com}, + {name: udp}, + {name: ip} ] + + transactions: + - client-request: + headers: + fields: + - [ :method, GET ] + - [ :scheme, https ] + - [ :authority, www.client_only_tls.com ] + - [ :path, /h3_first ] + - [ uuid, 13 ] + + <<: *200_ok_response + + proxy-response: + status: 200 + + - client-request: + headers: + fields: + - [ :method, GET ] + - [ :scheme, https ] + - [ :authority, www.client_only_tls.com ] + - [ :path, /h3_second ] + - [ uuid, 14 ] + + <<: *200_ok_response + + proxy-response: + status: 200 + diff --git a/tests/gold_tests/pluginTest/traffic_dump/traffic_dump_http3.test.py b/tests/gold_tests/pluginTest/traffic_dump/traffic_dump_http3.test.py new file mode 100644 index 00000000000..b3c31b09206 --- /dev/null +++ b/tests/gold_tests/pluginTest/traffic_dump/traffic_dump_http3.test.py @@ -0,0 +1,153 @@ +""" +Verify traffic_dump HTTP/3 functionality. +""" +# 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 = ''' +Verify traffic_dump HTTP/3 functionality. +''' + +Test.SkipUnless( + Condition.PluginExists('traffic_dump.so'), + Condition.HasATSFeature('TS_USE_QUIC'), +) +Test.SkipIf( + Condition.true("Skip this test until the TS_EVENT_HTTP_SSN are supported for QUIC connections."), +) + +# Configure the origin server. +replay_file = "replay/http3.yaml" +server = Test.MakeVerifierServerProcess( + "server", replay_file, + ssl_cert="ssl/server_combined.pem", ca_cert="ssl/signer.pem") + + +# Define ATS and configure it. +ts = Test.MakeATSProcess("ts", enable_tls=True, enable_quic=True) +ts_log_dir = os.path.join(ts.RunDirectory, "ts", "log") +qlog_dir = os.path.join(ts_log_dir, "qlog_dir") + +ts.addSSLfile("ssl/server.pem") +ts.addSSLfile("ssl/server.key") +ts.addSSLfile("ssl/signer.pem") + +ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'traffic_dump|quic', + 'proxy.config.http.insert_age_in_response': 0, + + 'proxy.config.quic.qlog_dir': qlog_dir, + + 'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir), + 'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir), + 'proxy.config.url_remap.pristine_host_hdr': 1, + 'proxy.config.ssl.CA.cert.filename': '{0}/signer.pem'.format(ts.Variables.SSLDir), + 'proxy.config.exec_thread.autoconfig.scale': 1.0, + 'proxy.config.http.host_sni_policy': 2, + 'proxy.config.ssl.client.verify.server.policy': 'PERMISSIVE', +}) + +ts.Disk.ssl_multicert_config.AddLine( + 'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key' +) + +ts.Disk.remap_config.AddLine( + 'map https://www.client_only_tls.com/ http://127.0.0.1:{0}'.format(server.Variables.http_port) +) +ts.Disk.remap_config.AddLine( + 'map https://www.tls.com/ https://127.0.0.1:{0}'.format(server.Variables.https_port) +) +ts.Disk.remap_config.AddLine( + 'map / http://127.0.0.1:{0}'.format(server.Variables.http_port) +) + +# Configure traffic_dump. +ts.Disk.plugin_config.AddLine( + f'traffic_dump.so --logdir {ts_log_dir} --sample 1 --limit 1000000000 ' + '--sensitive-fields "cookie,set-cookie,x-request-1,x-request-2"' +) +# Configure logging of transactions. This is helpful for the cache test below. +ts.Disk.logging_yaml.AddLines( + ''' +logging: + formats: + - name: basic + format: "%: Read result: %:%:%, Write result: %" + logs: + - filename: transactions + format: basic +'''.split('\n')) + +# Set up trafficserver expectations. +ts.Disk.diags_log.Content = Testers.ContainsExpression( + "loading plugin.*traffic_dump.so", + "Verify the traffic_dump plugin got loaded.") +ts.Streams.stderr = Testers.ContainsExpression( + f"Initialized with log directory: {ts_log_dir}", + "Verify traffic_dump initialized with the configured directory.") +ts.Streams.stderr += Testers.ContainsExpression( + "Initialized with sample pool size 1 bytes and disk limit 1000000000 bytes", + "Verify traffic_dump initialized with the configured disk limit.") +ts.Streams.stderr += Testers.ContainsExpression( + "Finish a session with log file of.*bytes", + "Verify traffic_dump sees the end of sessions and accounts for it.") + +# Set up the json replay file expectations. +replay_file_session_1 = os.path.join(ts_log_dir, "127", "0000000000000000") +ts.Disk.File(replay_file_session_1, exists=True) + +# Execute the first transaction. We limit the threads to 1 so that the sessions +# are run in serial. +tr = Test.AddTestRun("Run the test traffic.") +tr.AddVerifierClientProcess( + "client", replay_file, http_ports=[ts.Variables.port], + https_ports=[ts.Variables.ssl_port], + http3_ports=[ts.Variables.ssl_port], + ssl_cert="ssl/server_combined.pem", ca_cert="ssl/signer.pem", + other_args='--thread-limit 1') + +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(ts) +tr.StillRunningAfter = server +tr.StillRunningAfter = ts + +# +# Test 1: Verify the correct behavior of two transactions across two sessions. +# + +# Verify the properties of the replay file for the first transaction. +tr = Test.AddTestRun("Verify the json content of the first session") +http_protocols = "tcp,ip" +verify_replay = "verify_replay.py" +sensitive_fields_arg = ( + "--sensitive-fields cookie " + "--sensitive-fields set-cookie " + "--sensitive-fields x-request-1 " + "--sensitive-fields x-request-2 ") +tr.Setup.CopyAs(verify_replay, Test.RunDirectory) +tr.Processes.Default.Command = \ + ('python3 {0} {1} {2} {3} --client-http-version "3" ' + '--client-protocols "{4}"'.format( + verify_replay, + os.path.join(Test.Variables.AtsTestToolsDir, 'lib', 'replay_schema.json'), + replay_file_session_1, + sensitive_fields_arg, + http_protocols)) +tr.Processes.Default.ReturnCode = 0 +tr.StillRunningAfter = server +tr.StillRunningAfter = ts