This is an automated email from the ASF dual-hosted git repository. maskit 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 2c9534603e Fixed h3 crash in accept() triggered by ip_allow rejection (#10167) 2c9534603e is described below commit 2c9534603e3917929127583d8450dfe4561dc92e Author: Zhengxi Li <lzx404...@hotmail.com> AuthorDate: Wed Aug 9 18:23:27 2023 -0400 Fixed h3 crash in accept() triggered by ip_allow rejection (#10167) * Added an Autest to trigger a quic crash * Fixed the crash --- iocore/net/QUICNetVConnection_quiche.cc | 4 + tests/gold_tests/ip_allow/ip_allow.test.py | 124 +++++++++++++++++++++++ tests/gold_tests/ip_allow/replays/h3.replay.yaml | 46 +++++++++ 3 files changed, 174 insertions(+) diff --git a/iocore/net/QUICNetVConnection_quiche.cc b/iocore/net/QUICNetVConnection_quiche.cc index 143a4cbf24..f84e60e918 100644 --- a/iocore/net/QUICNetVConnection_quiche.cc +++ b/iocore/net/QUICNetVConnection_quiche.cc @@ -184,6 +184,10 @@ QUICNetVConnection::state_handshake(int event, Event *data) int QUICNetVConnection::state_established(int event, Event *data) { + if (!this->_quiche_con) { + // Connection has been closed. + return EVENT_DONE; + } switch (event) { case QUIC_EVENT_PACKET_READ_READY: this->_handle_read_ready(); diff --git a/tests/gold_tests/ip_allow/ip_allow.test.py b/tests/gold_tests/ip_allow/ip_allow.test.py index ce21a36162..1be084d87a 100644 --- a/tests/gold_tests/ip_allow/ip_allow.test.py +++ b/tests/gold_tests/ip_allow/ip_allow.test.py @@ -185,3 +185,127 @@ tr.Processes.Default.Command = ( os.path.join(Test.TestDirectory, 'gold/log.gold')) ) tr.Processes.Default.ReturnCode = 0 + +IP_ALLOW_CONFIG_ALLOW_ALL = '''ip_allow: + - apply: in + ip_addrs: 0/0 + action: allow + methods: ALL +''' + +IP_ALLOW_CONFIG_DENY_ALL = '''ip_allow: + - apply: in + ip_addrs: 0/0 + action: deny + methods: ALL +''' + + +class Test_ip_allow_h3: + """Configure a test to verify ip_allow behavior for h3 connections.""" + + replay_file = "replays/h3.replay.yaml" + client_counter: int = 0 + ts_counter: int = 0 + server_counter: int = 0 + + def __init__(self, name: str, ip_allow_config: str, gold_file="", replay_keys="", expect_request_rejected=False): + """Initialize the test. + + :param name: The name of the test. + :param ip_allow_config: The ip_allow configuration to be used. + :param gold_file: (Optional) Gold file to be checked. + :param replay_keys: (Optional) Keys to be used by pv. + :param expect_request_rejected: (Optional) Whether or not the client request is expected to be rejected. + """ + self.name = name + self.gold_file = gold_file + self.replay_keys = replay_keys + self.ip_allow_config = ip_allow_config + self.expect_request_rejected = expect_request_rejected + + def _configure_server(self, tr: 'TestRun'): + """Configure the server. + + :param tr: The TestRun object to associate the server process with. + """ + server = tr.AddVerifierServerProcess( + f"server_{Test_ip_allow_h3.server_counter}", + self.replay_file) + Test_ip_allow_h3.server_counter += 1 + self._server = server + + def _configure_traffic_server(self, tr: 'TestRun'): + """Configure Traffic Server. + + :param tr: The TestRun object to associate the ts process with. + """ + ts = tr.MakeATSProcess(f"ts-{Test_ip_allow_h3.ts_counter}", enable_quic=True, enable_tls=True) + + Test_ip_allow_h3.ts_counter += 1 + self._ts = ts + # Configure TLS for Traffic Server. + self._ts.addDefaultSSLFiles() + self._ts.Disk.ssl_multicert_config.AddLine( + 'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key' + ) + self._ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'v_quic|quic|http|ip_allow', + 'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir), + 'proxy.config.quic.no_activity_timeout_in': 0, + 'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir), + 'proxy.config.ssl.client.verify.server.policy': 'PERMISSIVE', + }) + + self._ts.Disk.remap_config.AddLine(f'map / http://127.0.0.1:{self._server.Variables.http_port}') + + # Set ip_allow policy based on the input configuration. + self._ts.Disk.ip_allow_yaml.AddLines( + self.ip_allow_config.split("\n") + ) + + def run(self): + """Run the test.""" + tr = Test.AddTestRun(self.name) + self._configure_server(tr) + self._configure_traffic_server(tr) + + tr.Processes.Default.StartBefore(self._server) + tr.Processes.Default.StartBefore(self._ts) + + tr.AddVerifierClientProcess( + f'client-{Test_ip_allow_h3.client_counter}', + self.replay_file, + http3_ports=[self._ts.Variables.ssl_port], + keys=self.replay_keys) + Test_ip_allow_h3.client_counter += 1 + + if self.expect_request_rejected: + # The client request should time out because ATS rejects it and does + # not send a response. + tr.Processes.Default.ReturnCode = 1 + self._ts.Disk.diags_log.Content += Testers.ContainsExpression( + "client.*prohibited by ip-allow policy", "Request should be rejected by ip_allow") + else: + # Verify the client request is successful. + tr.Processes.Default.ReturnCode = 0 + self._ts.Disk.diags_log.Content += Testers.ExcludesExpression( + "client.*allowed by ip-allow policy", "Request should be allowed by ip_allow") + + if self.gold_file: + tr.Processes.Default.Streams.all = self.gold_file + + +# ip_allow tests for h3. +if Condition.HasATSFeature('TS_USE_QUIC') and Condition.HasCurlFeature('http3'): + + # TEST 4: Perform a request in h3 with ip_allow configured to allow all IPs. + test0 = Test_ip_allow_h3( + "", ip_allow_config=IP_ALLOW_CONFIG_ALLOW_ALL, expect_request_rejected=False) + test0.run() + + # TEST 5: Perform a request in h3 with ip_allow configured to deny all IPs. + test1 = Test_ip_allow_h3( + "", ip_allow_config=IP_ALLOW_CONFIG_DENY_ALL, expect_request_rejected=True) + test1.run() diff --git a/tests/gold_tests/ip_allow/replays/h3.replay.yaml b/tests/gold_tests/ip_allow/replays/h3.replay.yaml new file mode 100644 index 0000000000..187d046f9a --- /dev/null +++ b/tests/gold_tests/ip_allow/replays/h3.replay.yaml @@ -0,0 +1,46 @@ +# 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" + +sessions: +- protocol: + - name: http + version: 3 + - name: tls + sni: test_sni + transactions: + + - client-request: + version: "3" + headers: + fields: + - [ Content-Length, 0 ] + - [:method, GET] + - [:scheme, https] + - [:authority, example.com] + - [:path, /path/test1] + - [ uuid, 1 ] + server-response: + status: 200 + reason: "OK" + headers: + fields: + - [ Content-Length, 20 ] + + proxy-response: + status: 200