MXS-1628: Add bad handshake test case
The test checks that a bad handshake error is returned when a malformed packet is sent.
This commit is contained in:
@ -50,8 +50,8 @@ add_library(testcore SHARED testconnections.cpp mariadb_nodes.cpp
|
||||
mariadb_func.cpp get_com_select_insert.cpp maxadmin_operations.cpp big_transaction.cpp
|
||||
sql_t1.cpp test_binlog_fnc.cpp get_my_ip.cpp big_load.cpp get_com_select_insert.cpp
|
||||
different_size.cpp fw_copy_rules maxinfo_func.cpp config_operations.cpp rds_vpc.cpp execute_cmd.cpp
|
||||
blob_test.cpp cdc_connector.cpp)
|
||||
target_link_libraries(testcore ${MYSQL_CLIENT} z crypt nsl m pthread ssl crypto dl rt jansson)
|
||||
blob_test.cpp cdc_connector.cpp tcp_connection.cpp)
|
||||
target_link_libraries(testcore ${MYSQL_CLIENT} z crypt m pthread ssl crypto dl rt jansson)
|
||||
install(TARGETS testcore DESTINATION system-test)
|
||||
add_dependencies(testcore connector-c)
|
||||
|
||||
@ -768,6 +768,10 @@ add_test_executable_notest(long_sysbench.cpp long_sysbench replication LABELS re
|
||||
# test effect of local_address in configuration file
|
||||
add_test_executable(local_address.cpp local_address local_address LABELS REPL_BACKEND)
|
||||
|
||||
# MXS-1628: Security scanner says MaxScale is vulnerable to ancient MySQL vulnerability
|
||||
# https://jira.mariadb.org/browse/MXS-1628
|
||||
add_test_executable(mxs1628_bad_handshake.cpp mxs1628_bad_handshake replication LABELS REPL_BACKEND)
|
||||
|
||||
configure_file(templates.h.in templates.h @ONLY)
|
||||
|
||||
include(CTest)
|
||||
|
71
maxscale-system-test/mxs1628_bad_handshake.cpp
Normal file
71
maxscale-system-test/mxs1628_bad_handshake.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "testconnections.h"
|
||||
#include "tcp_connection.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
TestConnections test(argc, argv);
|
||||
test.set_timeout(30);
|
||||
|
||||
uint32_t caps = 1 | 8 | 512;
|
||||
uint32_t max_packet = 65535;
|
||||
uint8_t charset = 8;
|
||||
std::string username = "username";
|
||||
uint8_t token_len = 20; // SHA1 hash size
|
||||
std::string database = "database";
|
||||
|
||||
// Capabilities, max packet size and client charset
|
||||
std::vector<uint8_t> wbuf;
|
||||
auto it = std::back_inserter(wbuf);
|
||||
|
||||
for (auto a: {(uint8_t)(caps), (uint8_t)(caps >> 8), (uint8_t)(caps >> 16), (uint8_t)(caps >> 24),
|
||||
(uint8_t)(max_packet), (uint8_t)(max_packet >> 8), (uint8_t)(max_packet >> 16), (uint8_t)(max_packet >> 24),
|
||||
charset})
|
||||
{
|
||||
*it++ = a;
|
||||
}
|
||||
|
||||
// Reserved filler space
|
||||
std::fill_n(it, 23, 0);
|
||||
|
||||
// Username without terminating null character
|
||||
for (auto a: username)
|
||||
{
|
||||
*it++ = (uint8_t)a;
|
||||
}
|
||||
|
||||
// Auth token length and the token itself
|
||||
*it++ = token_len;
|
||||
std::fill_n(it, token_len, 123);
|
||||
|
||||
// Database without terminating null character
|
||||
for (auto a: database)
|
||||
{
|
||||
*it++ = (uint8_t)a;
|
||||
}
|
||||
|
||||
// Payload length and sequence number
|
||||
uint8_t bufsize = wbuf.size();
|
||||
wbuf.insert(wbuf.begin(), {(uint8_t)(bufsize), (uint8_t)(bufsize >> 8), (uint8_t)(bufsize >> 16), 2});
|
||||
|
||||
|
||||
tcp::Connection conn;
|
||||
conn.connect(test.maxscale_ip(), test.rwsplit_port);
|
||||
|
||||
// Read the handshake
|
||||
uint8_t buf[512] = {};
|
||||
conn.read(buf, sizeof(buf));
|
||||
|
||||
// Send the handshake response
|
||||
conn.write(&wbuf[0], wbuf.size());
|
||||
|
||||
// Read MaxScale's response
|
||||
conn.read(buf, sizeof(buf));
|
||||
|
||||
const char response[] = "Bad handshake";
|
||||
test.add_result(memmem(buf, sizeof(buf), response, sizeof(response) - 1) == NULL,
|
||||
"MaxScale should respond with 'Bad handshake'");
|
||||
|
||||
return test.global_result;
|
||||
}
|
89
maxscale-system-test/tcp_connection.cpp
Normal file
89
maxscale-system-test/tcp_connection.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include "tcp_connection.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static void set_port(struct sockaddr_storage *addr, uint16_t port)
|
||||
{
|
||||
if (addr->ss_family == AF_INET)
|
||||
{
|
||||
struct sockaddr_in *ip = (struct sockaddr_in*)addr;
|
||||
ip->sin_port = htons(port);
|
||||
}
|
||||
else if (addr->ss_family == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 *ip = (struct sockaddr_in6*)addr;
|
||||
ip->sin6_port = htons(port);
|
||||
}
|
||||
}
|
||||
|
||||
int open_network_socket(struct sockaddr_storage *addr, const char *host, uint16_t port)
|
||||
{
|
||||
struct addrinfo *ai = NULL, hint = {};
|
||||
int so = -1, rc = 0;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
hint.ai_family = AF_UNSPEC;
|
||||
hint.ai_flags = AI_ALL;
|
||||
|
||||
/* Take the first one */
|
||||
if (getaddrinfo(host, NULL, &hint, &ai) == 0 && ai)
|
||||
{
|
||||
if ((so = socket(ai->ai_family, SOCK_STREAM, 0)) != -1)
|
||||
{
|
||||
memcpy(addr, ai->ai_addr, ai->ai_addrlen);
|
||||
set_port(addr, port);
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
}
|
||||
|
||||
return so;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace tcp
|
||||
{
|
||||
|
||||
Connection::~Connection()
|
||||
{
|
||||
if (m_so != -1)
|
||||
{
|
||||
close(m_so);
|
||||
}
|
||||
}
|
||||
|
||||
bool Connection::connect(const char* host, uint16_t port)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
if ((m_so = open_network_socket(&addr, host, port)) != -1)
|
||||
{
|
||||
if (::connect(m_so, (struct sockaddr*)&addr, sizeof(addr)) != 0)
|
||||
{
|
||||
close(m_so);
|
||||
m_so = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return m_so != -1;
|
||||
}
|
||||
|
||||
int Connection::write(void* buf, size_t size)
|
||||
{
|
||||
return ::write(m_so, buf, size);
|
||||
}
|
||||
|
||||
int Connection::read(void* buf, size_t size)
|
||||
{
|
||||
return ::read(m_so, buf, size);
|
||||
}
|
||||
|
||||
}
|
49
maxscale-system-test/tcp_connection.h
Normal file
49
maxscale-system-test/tcp_connection.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace tcp
|
||||
{
|
||||
|
||||
// A raw TCP connection
|
||||
class Connection
|
||||
{
|
||||
public:
|
||||
~Connection();
|
||||
|
||||
/**
|
||||
* Connect to the target server
|
||||
*
|
||||
* @param host Server hostname
|
||||
* @param port Server port
|
||||
*
|
||||
* @return True if connection was successfully created
|
||||
*/
|
||||
bool connect(const char* host, uint16_t port);
|
||||
|
||||
/**
|
||||
* Write to socket
|
||||
*
|
||||
* @param buf Buffer to read from
|
||||
* @param size Number of bytes to read from @c buf
|
||||
*
|
||||
* @return Number of written bytes or -1 on error
|
||||
*/
|
||||
int write(void* buf, size_t size);
|
||||
|
||||
/**
|
||||
* Read from socket
|
||||
*
|
||||
* @param buf Buffer to write to
|
||||
* @param size Size of @c buf
|
||||
*
|
||||
* @return Number of read bytes or -1 on error
|
||||
*/
|
||||
int read(void* buf, size_t size);
|
||||
|
||||
private:
|
||||
int m_so = -1;
|
||||
};
|
||||
|
||||
}
|
Reference in New Issue
Block a user