1 // SPDX-License-Identifier: GPL-2.0 2 /* Author: Dmitry Safonov <dima@arista.com> */ 3 #include <inttypes.h> 4 #include "aolib.h" 5 6 static union tcp_addr local_addr; 7 8 static void __setup_lo_intf(const char *lo_intf, 9 const char *addr_str, uint8_t prefix) 10 { 11 if (inet_pton(TEST_FAMILY, addr_str, &local_addr) != 1) 12 test_error("Can't convert local ip address"); 13 14 if (ip_addr_add(lo_intf, TEST_FAMILY, local_addr, prefix)) 15 test_error("Failed to add %s ip address", lo_intf); 16 17 if (link_set_up(lo_intf)) 18 test_error("Failed to bring %s up", lo_intf); 19 } 20 21 static void setup_lo_intf(const char *lo_intf) 22 { 23 #ifdef IPV6_TEST 24 __setup_lo_intf(lo_intf, "::1", 128); 25 #else 26 __setup_lo_intf(lo_intf, "127.0.0.1", 8); 27 #endif 28 } 29 30 static void tcp_self_connect(const char *tst, unsigned int port, 31 bool different_keyids, bool check_restore) 32 { 33 struct tcp_ao_counters before_ao, after_ao; 34 uint64_t before_aogood, after_aogood; 35 struct netstat *ns_before, *ns_after; 36 const size_t nr_packets = 20; 37 struct tcp_ao_repair ao_img; 38 struct tcp_sock_state img; 39 sockaddr_af addr; 40 int sk; 41 42 tcp_addr_to_sockaddr_in(&addr, &local_addr, htons(port)); 43 44 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP); 45 if (sk < 0) 46 test_error("socket()"); 47 48 if (different_keyids) { 49 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, local_addr, -1, 5, 7)) 50 test_error("setsockopt(TCP_AO_ADD_KEY)"); 51 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, local_addr, -1, 7, 5)) 52 test_error("setsockopt(TCP_AO_ADD_KEY)"); 53 } else { 54 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, local_addr, -1, 100, 100)) 55 test_error("setsockopt(TCP_AO_ADD_KEY)"); 56 } 57 58 if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) 59 test_error("bind()"); 60 61 ns_before = netstat_read(); 62 before_aogood = netstat_get(ns_before, "TCPAOGood", NULL); 63 if (test_get_tcp_ao_counters(sk, &before_ao)) 64 test_error("test_get_tcp_ao_counters()"); 65 66 if (__test_connect_socket(sk, "lo", (struct sockaddr *)&addr, 67 sizeof(addr), TEST_TIMEOUT_SEC) < 0) { 68 ns_after = netstat_read(); 69 netstat_print_diff(ns_before, ns_after); 70 test_error("failed to connect()"); 71 } 72 73 if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) { 74 test_fail("%s: tcp connection verify failed", tst); 75 close(sk); 76 return; 77 } 78 79 ns_after = netstat_read(); 80 after_aogood = netstat_get(ns_after, "TCPAOGood", NULL); 81 if (test_get_tcp_ao_counters(sk, &after_ao)) 82 test_error("test_get_tcp_ao_counters()"); 83 if (!check_restore) { 84 /* to debug: netstat_print_diff(ns_before, ns_after); */ 85 netstat_free(ns_before); 86 } 87 netstat_free(ns_after); 88 89 if (after_aogood <= before_aogood) { 90 test_fail("%s: TCPAOGood counter mismatch: %" PRIu64 " <= %" PRIu64, 91 tst, after_aogood, before_aogood); 92 close(sk); 93 return; 94 } 95 96 if (test_tcp_ao_counters_cmp(tst, &before_ao, &after_ao, TEST_CNT_GOOD)) { 97 close(sk); 98 return; 99 } 100 101 if (!check_restore) { 102 test_ok("%s: connect TCPAOGood %" PRIu64 " => %" PRIu64, 103 tst, before_aogood, after_aogood); 104 close(sk); 105 return; 106 } 107 108 test_enable_repair(sk); 109 test_sock_checkpoint(sk, &img, &addr); 110 #ifdef IPV6_TEST 111 addr.sin6_port = htons(port + 1); 112 #else 113 addr.sin_port = htons(port + 1); 114 #endif 115 test_ao_checkpoint(sk, &ao_img); 116 test_kill_sk(sk); 117 118 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP); 119 if (sk < 0) 120 test_error("socket()"); 121 122 test_enable_repair(sk); 123 __test_sock_restore(sk, "lo", &img, &addr, &addr, sizeof(addr)); 124 if (different_keyids) { 125 if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, 126 local_addr, -1, 7, 5)) 127 test_error("setsockopt(TCP_AO_ADD_KEY)"); 128 if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, 129 local_addr, -1, 5, 7)) 130 test_error("setsockopt(TCP_AO_ADD_KEY)"); 131 } else { 132 if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, 133 local_addr, -1, 100, 100)) 134 test_error("setsockopt(TCP_AO_ADD_KEY)"); 135 } 136 test_ao_restore(sk, &ao_img); 137 test_disable_repair(sk); 138 test_sock_state_free(&img); 139 if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) { 140 test_fail("%s: tcp connection verify failed", tst); 141 close(sk); 142 return; 143 } 144 ns_after = netstat_read(); 145 after_aogood = netstat_get(ns_after, "TCPAOGood", NULL); 146 /* to debug: netstat_print_diff(ns_before, ns_after); */ 147 netstat_free(ns_before); 148 netstat_free(ns_after); 149 close(sk); 150 if (after_aogood <= before_aogood) { 151 test_fail("%s: TCPAOGood counter mismatch: %" PRIu64 " <= %" PRIu64, 152 tst, after_aogood, before_aogood); 153 return; 154 } 155 test_ok("%s: connect TCPAOGood %" PRIu64 " => %" PRIu64, 156 tst, before_aogood, after_aogood); 157 } 158 159 static void *client_fn(void *arg) 160 { 161 unsigned int port = test_server_port; 162 163 setup_lo_intf("lo"); 164 165 tcp_self_connect("self-connect(same keyids)", port++, false, false); 166 167 /* expecting rnext to change based on the first segment RNext != Current */ 168 trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, local_addr, local_addr, 169 port, port, 0, -1, -1, -1, -1, -1, 7, 5, -1); 170 tcp_self_connect("self-connect(different keyids)", port++, true, false); 171 tcp_self_connect("self-connect(restore)", port, false, true); 172 port += 2; /* restore test restores over different port */ 173 trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, local_addr, local_addr, 174 port, port, 0, -1, -1, -1, -1, -1, 7, 5, -1); 175 /* intentionally on restore they are added to the socket in different order */ 176 trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, local_addr, local_addr, 177 port + 1, port + 1, 0, -1, -1, -1, -1, -1, 5, 7, -1); 178 tcp_self_connect("self-connect(restore, different keyids)", port, true, true); 179 port += 2; /* restore test restores over different port */ 180 181 return NULL; 182 } 183 184 int main(int argc, char *argv[]) 185 { 186 test_init(5, client_fn, NULL); 187 return 0; 188 } 189