staticvoid check_listen_socket(void)
{ int sk, err;
sk = prepare_lsk(&this_ip_dest, 200, 200);
try_delete_key("listen socket, delete a key", sk, 200, 200, 0, -1, -1, 0);
try_delete_key("listen socket, delete all keys", sk, 100, 100, 0, -1, -1, 0);
close(sk);
sk = prepare_lsk(&this_ip_dest, 200, 200);
err = test_set_key(sk, 100, -1); if (err == -EINVAL)
test_ok("listen socket, setting current key not allowed"); else
test_fail("listen socket, set current key");
err = test_set_key(sk, -1, 200); if (err == -EINVAL)
test_ok("listen socket, setting rnext key not allowed"); else
test_fail("listen socket, set rnext key");
close(sk);
sk = prepare_sk(&this_ip_dest, 200, 200); if (test_set_key(sk, 100, 200))
test_error("failed to set current/rnext keys"); if (listen(sk, 10))
test_error("listen()");
assert_no_current_rnext("listen() after current/rnext keys set", sk);
try_delete_key("listen socket, delete current key from before listen()", sk, 100, 100, 0, -1, -1, FAULT_FIXME);
try_delete_key("listen socket, delete rnext key from before listen()", sk, 200, 200, 0, -1, -1, FAULT_FIXME);
close(sk);
assert_no_tcp_repair();
sk = prepare_lsk(&this_ip_dest, 200, 200); if (test_add_key(sk, "Glory to heros!", this_ip_dest,
DEFAULT_TEST_PREFIX, 10, 11))
test_error("test_add_key()"); if (test_add_key(sk, "Glory to Ukraine!", this_ip_dest,
DEFAULT_TEST_PREFIX, 12, 13))
test_error("test_add_key()");
try_delete_key("listen socket, delete a key + set current/rnext", sk,
100, 100, 0, 10, 13, FAULT_CURRNEXT);
try_delete_key("listen socket, force-delete current key", sk,
10, 11, 0, 200, -1, FAULT_CURRNEXT);
try_delete_key("listen socket, force-delete rnext key", sk,
12, 13, 0, -1, 200, FAULT_CURRNEXT);
try_delete_key("listen socket, delete a key", sk,
200, 200, 0, -1, -1, 0);
close(sk);
/* Same for randomized and non-randomized test flows */
key->client_keyid = index;
key->server_keyid = 127 + index;
key->matches_client = 1;
key->matches_server = 1;
key->matches_vrf = 1; /* not really even random, but good enough for a test */
key->len = rand() % (TCP_AO_MAXKEYLEN - TEST_TCP_AO_MINKEYLEN);
key->len += TEST_TCP_AO_MINKEYLEN;
randomize_buffer(key->password, key->len);
if (!nr_keys) {
free(collection.keys);
collection.keys = NULL; return 0;
}
/* * All keys have uniq sndid/rcvid and sndid != rcvid in order to * check for any bugs/issues for different keyids, visible to both * peers. Keyid == 254 is unused.
*/ if (nr_keys > 127)
test_error("Test requires too many keys, correct the source");
collection.keys = reallocarray(collection.keys, nr_keys, key_sz); if (!collection.keys) return -ENOMEM;
staticvoid verify_current_rnext(constchar *tst, int sk, int current_keyid, int rnext_keyid)
{ struct tcp_ao_info_opt ao_info = {};
if (test_get_ao_info(sk, &ao_info))
test_error("getsockopt(TCP_AO_INFO) failed");
errno = 0; if (current_keyid >= 0) { if (!ao_info.set_current)
test_fail("%s: the socket doesn't have current key", tst); elseif (ao_info.current_key != current_keyid)
test_fail("%s: current key is not the expected one %d != %u",
tst, current_keyid, ao_info.current_key); else
test_ok("%s: current key %u as expected",
tst, ao_info.current_key);
} if (rnext_keyid >= 0) { if (!ao_info.set_rnext)
test_fail("%s: the socket doesn't have rnext key", tst); elseif (ao_info.rnext != rnext_keyid)
test_fail("%s: rnext key is not the expected one %d != %u",
tst, rnext_keyid, ao_info.rnext); else
test_ok("%s: rnext key %u as expected", tst, ao_info.rnext);
}
}
staticint key_collection_socket(bool server, unsignedint port)
{ unsignedint i; int sk;
if (server)
sk = test_listen_socket(this_ip_addr, port, 1); else
sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP); if (sk < 0)
test_error("socket()");
for (i = 0; i < collection.nr_keys; i++) { struct test_key *key = &collection.keys[i]; union tcp_addr *addr = &wrong_addr;
uint8_t sndid, rcvid, vrf; bool set_current = false, set_rnext = false;
if (server) { if (key->matches_client)
matches = true;
sndid = key->server_keyid;
rcvid = key->client_keyid;
} else { if (key->matches_server)
matches = true;
sndid = key->client_keyid;
rcvid = key->server_keyid;
} if (!key->matches_vrf)
matches = false; /* no keys get removed on the original listener socket */ if (is_listen_sk)
matches = true;
if (current_index >= 0 || rnext_index >= 0) { int sndid = -1, rcvid = -1;
if (current_index >= 0)
sndid = collection.keys[current_index].client_keyid; if (rnext_index >= 0)
rcvid = collection.keys[rnext_index].server_keyid; if (test_set_key(sk, sndid, rcvid))
test_error("failed to set current/rnext keys");
} if (before && test_get_tcp_counters(sk, before))
test_error("test_get_tcp_counters()");
staticvoid end_client(constchar *tst_name, int sk, unsignedint nr_keys, int current_index, int rnext_index, struct tcp_counters *start)
{ struct tcp_counters end;
/* Some application may become dependent on this kernel choice */ if (current_index < 0)
current_index = nr_keys - 1; if (rnext_index < 0)
rnext_index = nr_keys - 1;
verify_current_rnext(tst_name, sk,
collection.keys[current_index].client_keyid,
collection.keys[rnext_index].server_keyid); if (start && test_get_tcp_counters(sk, &end))
test_error("test_get_tcp_counters()");
verify_keys(tst_name, sk, false, false);
synchronize_threads(); /* 4: verify => closed */
close(sk); if (start)
verify_counters(tst_name, false, false, start, &end);
synchronize_threads(); /* 5: counters */
}
staticvoid try_unmatched_keys(int sk, int *rnext_index, unsignedint port)
{ struct test_key *key; unsignedint i = 0; int err;
do {
key = &collection.keys[i]; if (!key->matches_server) break;
} while (++i < collection.nr_keys); if (key->matches_server)
test_error("all keys on client match the server");
err = test_add_key_cr(sk, key->password, key->len, wrong_addr,
0, key->client_keyid, key->server_keyid,
key->maclen, key->alg, 0, 0); if (!err) {
test_fail("Added a key with non-matching ip-address for established sk"); return;
} if (err == -EINVAL)
test_ok("Can't add a key with non-matching ip-address for established sk"); else
test_error("Failed to add a key");
err = test_add_key_cr(sk, key->password, key->len, this_ip_dest,
test_vrf_ifindex,
key->client_keyid, key->server_keyid,
key->maclen, key->alg, 0, 0); if (!err) {
test_fail("Added a key with non-matching VRF for established sk"); return;
} if (err == -EINVAL)
test_ok("Can't add a key with non-matching VRF for established sk"); else
test_error("Failed to add a key");
for (i = 0; i < collection.nr_keys; i++) {
key = &collection.keys[i]; if (!key->matches_client) break;
} if (key->matches_client)
test_error("all keys on server match the client"); if (test_set_key(sk, -1, key->server_keyid))
test_error("Can't change the current key");
trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, this_ip_addr, this_ip_dest,
-1, port, 0, -1, -1, -1, -1, -1,
-1, key->server_keyid, -1); if (test_client_verify(sk, msg_len, nr_packets))
test_fail("verify failed");
*rnext_index = i;
}
staticint client_non_matching(constchar *tst_name, unsignedint port, unsignedint nr_keys, int current_index, int rnext_index, const size_t msg_sz, const size_t msg_nr)
{ unsignedint i;
if (init_default_key_collection(nr_keys, true))
test_error("Failed to init the key collection");
for (i = 0; i < nr_keys; i++) { /* key (0, 0) matches */
collection.keys[i].matches_client = !!((i + 3) % 4);
collection.keys[i].matches_server = !!((i + 2) % 4); if (kernel_config_has(KCONFIG_NET_VRF))
collection.keys[i].matches_vrf = !!((i + 1) % 4);
}
sk = start_client(tst_name, port, nr_keys, current_index, rnext_index,
&tmp, msg_len, nr_packets); if (sk < 0) return; if (test_set_key(sk, collection.keys[rotate_to_index].client_keyid, -1))
test_error("Can't change the current key");
trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, this_ip_dest, this_ip_addr,
port, -1, 0, -1, -1, -1, -1, -1,
collection.keys[rotate_to_index].client_keyid,
collection.keys[current_index].client_keyid, -1); if (test_client_verify(sk, msg_len, nr_packets))
test_fail("verify failed"); /* There is a race here: between setting the current_key with * setsockopt(TCP_AO_INFO) and starting to send some data - there * might have been a segment received with the desired * RNext_key set. In turn that would mean that the first outgoing * segment will have the desired current_key (flipped back). * Which is what the user/test wants. As it's racy, skip checking * the counters, yet check what are the resulting current/rnext * keys on both sides.
*/
collection.keys[rotate_to_index].skip_counters_checks = 1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.