@@ -154,6 +154,23 @@ static xcl::XError make_x_connection(
154154 password.c_str (), " " );
155155}
156156
157+ static xcl::XError make_x_raw_connection (
158+ XProtocolSession &session, const std::string &host, const uint16_t port,
159+ int64_t connect_timeout = 10000 /* 10s*/ ) {
160+ session = xcl::create_session ();
161+ xcl::XError err = setup_x_session (session, connect_timeout, " PREFERRED" );
162+ if (err) return err;
163+
164+ return session->get_protocol ().get_connection ().connect (
165+ host, port, xcl::Internet_protocol::Any);
166+ }
167+
168+ static std::string format_xerror (const xcl::XError &e) {
169+ if (!e) return " no-error" ;
170+
171+ return " (code:" + std::to_string (e.error ()) + " , message:" + e.what () + " )" ;
172+ }
173+
157174#ifndef _WIN32
158175static xcl::XError make_x_connection (XProtocolSession &session,
159176 const std::string &socket,
@@ -1941,6 +1958,78 @@ static size_t xproto_frame_encode(const T &msg, uint8_t msg_type,
19411958 return msg.SerializeToCodedStream (&codecouts);
19421959}
19431960
1961+ /* *
1962+ * @test Verify that repeated TLS activation requests are properly rejected
1963+ * and do not crash the Router.
1964+ */
1965+ TEST_F (RouterRoutingTest, XProtocolRepeatedTlsUpgrade) {
1966+ const auto server_classic_port = port_pool_.get_next_available ();
1967+ const auto server_x_port = port_pool_.get_next_available ();
1968+ const auto router_x_rw_port = port_pool_.get_next_available ();
1969+
1970+ const std::string json_stmts = get_data_dir ().join (" bootstrap_gr.js" ).str ();
1971+
1972+ launch_mysql_server_mock (json_stmts, server_classic_port, EXIT_SUCCESS , false ,
1973+ /* http_port*/ 0 , server_x_port, /* module_prefix*/ " " ,
1974+ /* bind_address*/ " 127.0.0.1" ,
1975+ /* wait_for_notify_ready*/ std::chrono::seconds (30 ),
1976+ /* enable_ssl*/ true );
1977+
1978+ const std::string routing_x_section = get_static_routing_section (
1979+ " x" , router_x_rw_port, " " , {server_x_port}, " x" );
1980+
1981+ TempDirectory conf_dir (" conf" );
1982+ const std::string ssl_conf =
1983+ " client_ssl_mode=PREFERRED\n "
1984+ " server_ssl_mode=AS_CLIENT\n "
1985+ " client_ssl_key=" SSL_TEST_DATA_DIR
1986+ " /server-key-sha512.pem\n "
1987+ " client_ssl_cert=" SSL_TEST_DATA_DIR " /server-cert-sha512.pem" ;
1988+ std::string conf_file =
1989+ create_config_file (conf_dir.name (), routing_x_section, nullptr ,
1990+ " mysqlrouter.conf" , ssl_conf, true );
1991+
1992+ launch_router ({" -c" , conf_file});
1993+
1994+ Mysqlx::Connection::CapabilitiesSet switch_tls_msg;
1995+ auto *cap = switch_tls_msg.mutable_capabilities ()->add_capabilities ();
1996+ cap->set_name (" tls" );
1997+ auto *cap_value = cap->mutable_value ();
1998+ cap_value->set_type (Mysqlx::Datatypes::Any_Type::Any_Type_SCALAR);
1999+ auto *cap_scalar = cap_value->mutable_scalar ();
2000+ cap_scalar->set_type (Mysqlx::Datatypes::Scalar_Type::Scalar_Type_V_BOOL);
2001+ cap_scalar->set_v_bool (true );
2002+
2003+ XProtocolSession x_session;
2004+ const auto x_connect_error =
2005+ make_x_raw_connection (x_session, " 127.0.0.1" , router_x_rw_port);
2006+ ASSERT_FALSE (x_connect_error) << format_xerror (x_connect_error);
2007+
2008+ const auto x_cap_set_error =
2009+ x_session.get ()->get_protocol ().execute_set_capability (switch_tls_msg);
2010+ ASSERT_FALSE (x_cap_set_error) << format_xerror (x_cap_set_error);
2011+
2012+ const auto x_tls_error =
2013+ x_session.get ()->get_protocol ().get_connection ().activate_tls ();
2014+
2015+ ASSERT_FALSE (x_tls_error) << format_xerror (x_tls_error);
2016+
2017+ const auto x_cap_set2_error =
2018+ x_session.get ()->get_protocol ().execute_set_capability (switch_tls_msg);
2019+ ASSERT_EQ (x_cap_set2_error.error (), 5001 ) << format_xerror (x_cap_set2_error);
2020+
2021+ const auto x_login_error =
2022+ x_session.get ()->get_protocol ().execute_authenticate (" root" , " fake-pass" ,
2023+ " " , " SHA256_MEMORY" );
2024+ ASSERT_FALSE (x_login_error) << format_xerror (x_login_error);
2025+
2026+ // Router should still accept a fresh X Protocol connection after the loop.
2027+ XProtocolSession x_session2;
2028+ const auto res = make_x_connection (x_session2, " 127.0.0.1" , router_x_rw_port,
2029+ " root" , " fake-pass" );
2030+ EXPECT_THAT (res.error (), ::testing::AnyOf (0 , 3159 ));
2031+ }
2032+
19442033/* *
19452034 * @test Check that if the x protocol client sends CONCLOSE message the Router
19462035 * replies with OK{bye!} message.
0 commit comments