mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-08-22 00:42:01 +02:00

Setup trace points, add a new ftrace instance in order to not interfere with the rest of the system, filtering by net namespace cookies. Raise a new background thread that parses trace_pipe, matches them with the list of expected events. Wiring up trace events to selftests provides another insight if there is anything unexpected happining in the tcp-ao code (i.e. key rotation when it's not expected). Note: in real programs libtraceevent should be used instead of this manual labor of setting ftrace up and parsing. I'm not using it here as I don't want to have an .so library dependency that one would have to bring into VM or DUT (Device Under Test). Please, don't copy it over into any real world programs, that aren't tests. Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> Link: https://patch.msgid.link/20240823-tcp-ao-selftests-upd-6-12-v4-8-05623636fe8c@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
189 lines
5.5 KiB
C
189 lines
5.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Author: Dmitry Safonov <dima@arista.com> */
|
|
#include <inttypes.h>
|
|
#include "aolib.h"
|
|
|
|
static union tcp_addr local_addr;
|
|
|
|
static void __setup_lo_intf(const char *lo_intf,
|
|
const char *addr_str, uint8_t prefix)
|
|
{
|
|
if (inet_pton(TEST_FAMILY, addr_str, &local_addr) != 1)
|
|
test_error("Can't convert local ip address");
|
|
|
|
if (ip_addr_add(lo_intf, TEST_FAMILY, local_addr, prefix))
|
|
test_error("Failed to add %s ip address", lo_intf);
|
|
|
|
if (link_set_up(lo_intf))
|
|
test_error("Failed to bring %s up", lo_intf);
|
|
}
|
|
|
|
static void setup_lo_intf(const char *lo_intf)
|
|
{
|
|
#ifdef IPV6_TEST
|
|
__setup_lo_intf(lo_intf, "::1", 128);
|
|
#else
|
|
__setup_lo_intf(lo_intf, "127.0.0.1", 8);
|
|
#endif
|
|
}
|
|
|
|
static void tcp_self_connect(const char *tst, unsigned int port,
|
|
bool different_keyids, bool check_restore)
|
|
{
|
|
struct tcp_ao_counters before_ao, after_ao;
|
|
uint64_t before_aogood, after_aogood;
|
|
struct netstat *ns_before, *ns_after;
|
|
const size_t nr_packets = 20;
|
|
struct tcp_ao_repair ao_img;
|
|
struct tcp_sock_state img;
|
|
sockaddr_af addr;
|
|
int sk;
|
|
|
|
tcp_addr_to_sockaddr_in(&addr, &local_addr, htons(port));
|
|
|
|
sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
|
|
if (sk < 0)
|
|
test_error("socket()");
|
|
|
|
if (different_keyids) {
|
|
if (test_add_key(sk, DEFAULT_TEST_PASSWORD, local_addr, -1, 5, 7))
|
|
test_error("setsockopt(TCP_AO_ADD_KEY)");
|
|
if (test_add_key(sk, DEFAULT_TEST_PASSWORD, local_addr, -1, 7, 5))
|
|
test_error("setsockopt(TCP_AO_ADD_KEY)");
|
|
} else {
|
|
if (test_add_key(sk, DEFAULT_TEST_PASSWORD, local_addr, -1, 100, 100))
|
|
test_error("setsockopt(TCP_AO_ADD_KEY)");
|
|
}
|
|
|
|
if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
|
test_error("bind()");
|
|
|
|
ns_before = netstat_read();
|
|
before_aogood = netstat_get(ns_before, "TCPAOGood", NULL);
|
|
if (test_get_tcp_ao_counters(sk, &before_ao))
|
|
test_error("test_get_tcp_ao_counters()");
|
|
|
|
if (__test_connect_socket(sk, "lo", (struct sockaddr *)&addr,
|
|
sizeof(addr), TEST_TIMEOUT_SEC) < 0) {
|
|
ns_after = netstat_read();
|
|
netstat_print_diff(ns_before, ns_after);
|
|
test_error("failed to connect()");
|
|
}
|
|
|
|
if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) {
|
|
test_fail("%s: tcp connection verify failed", tst);
|
|
close(sk);
|
|
return;
|
|
}
|
|
|
|
ns_after = netstat_read();
|
|
after_aogood = netstat_get(ns_after, "TCPAOGood", NULL);
|
|
if (test_get_tcp_ao_counters(sk, &after_ao))
|
|
test_error("test_get_tcp_ao_counters()");
|
|
if (!check_restore) {
|
|
/* to debug: netstat_print_diff(ns_before, ns_after); */
|
|
netstat_free(ns_before);
|
|
}
|
|
netstat_free(ns_after);
|
|
|
|
if (after_aogood <= before_aogood) {
|
|
test_fail("%s: TCPAOGood counter mismatch: %" PRIu64 " <= %" PRIu64,
|
|
tst, after_aogood, before_aogood);
|
|
close(sk);
|
|
return;
|
|
}
|
|
|
|
if (test_tcp_ao_counters_cmp(tst, &before_ao, &after_ao, TEST_CNT_GOOD)) {
|
|
close(sk);
|
|
return;
|
|
}
|
|
|
|
if (!check_restore) {
|
|
test_ok("%s: connect TCPAOGood %" PRIu64 " => %" PRIu64,
|
|
tst, before_aogood, after_aogood);
|
|
close(sk);
|
|
return;
|
|
}
|
|
|
|
test_enable_repair(sk);
|
|
test_sock_checkpoint(sk, &img, &addr);
|
|
#ifdef IPV6_TEST
|
|
addr.sin6_port = htons(port + 1);
|
|
#else
|
|
addr.sin_port = htons(port + 1);
|
|
#endif
|
|
test_ao_checkpoint(sk, &ao_img);
|
|
test_kill_sk(sk);
|
|
|
|
sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
|
|
if (sk < 0)
|
|
test_error("socket()");
|
|
|
|
test_enable_repair(sk);
|
|
__test_sock_restore(sk, "lo", &img, &addr, &addr, sizeof(addr));
|
|
if (different_keyids) {
|
|
if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0,
|
|
local_addr, -1, 7, 5))
|
|
test_error("setsockopt(TCP_AO_ADD_KEY)");
|
|
if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0,
|
|
local_addr, -1, 5, 7))
|
|
test_error("setsockopt(TCP_AO_ADD_KEY)");
|
|
} else {
|
|
if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0,
|
|
local_addr, -1, 100, 100))
|
|
test_error("setsockopt(TCP_AO_ADD_KEY)");
|
|
}
|
|
test_ao_restore(sk, &ao_img);
|
|
test_disable_repair(sk);
|
|
test_sock_state_free(&img);
|
|
if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) {
|
|
test_fail("%s: tcp connection verify failed", tst);
|
|
close(sk);
|
|
return;
|
|
}
|
|
ns_after = netstat_read();
|
|
after_aogood = netstat_get(ns_after, "TCPAOGood", NULL);
|
|
/* to debug: netstat_print_diff(ns_before, ns_after); */
|
|
netstat_free(ns_before);
|
|
netstat_free(ns_after);
|
|
close(sk);
|
|
if (after_aogood <= before_aogood) {
|
|
test_fail("%s: TCPAOGood counter mismatch: %" PRIu64 " <= %" PRIu64,
|
|
tst, after_aogood, before_aogood);
|
|
return;
|
|
}
|
|
test_ok("%s: connect TCPAOGood %" PRIu64 " => %" PRIu64,
|
|
tst, before_aogood, after_aogood);
|
|
}
|
|
|
|
static void *client_fn(void *arg)
|
|
{
|
|
unsigned int port = test_server_port;
|
|
|
|
setup_lo_intf("lo");
|
|
|
|
tcp_self_connect("self-connect(same keyids)", port++, false, false);
|
|
|
|
/* expecting rnext to change based on the first segment RNext != Current */
|
|
trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, local_addr, local_addr,
|
|
port, port, 0, -1, -1, -1, -1, -1, 7, 5, -1);
|
|
tcp_self_connect("self-connect(different keyids)", port++, true, false);
|
|
tcp_self_connect("self-connect(restore)", port, false, true);
|
|
port += 2; /* restore test restores over different port */
|
|
trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, local_addr, local_addr,
|
|
port, port, 0, -1, -1, -1, -1, -1, 7, 5, -1);
|
|
/* intentionally on restore they are added to the socket in different order */
|
|
trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, local_addr, local_addr,
|
|
port + 1, port + 1, 0, -1, -1, -1, -1, -1, 5, 7, -1);
|
|
tcp_self_connect("self-connect(restore, different keyids)", port, true, true);
|
|
port += 2; /* restore test restores over different port */
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
test_init(5, client_fn, NULL);
|
|
return 0;
|
|
}
|