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