1 // SPDX-License-Identifier: GPL-2.0 2 /* Check that after SEQ number wrap-around: 3 * 1. SEQ-extension has upper bytes set 4 * 2. TCP conneciton is alive and no TCPAOBad segments 5 * In order to test (2), the test doesn't just adjust seq number for a queue 6 * on a connected socket, but migrates it to another sk+port number, so 7 * that there won't be any delayed packets that will fail to verify 8 * with the new SEQ numbers. 9 */ 10 #include <inttypes.h> 11 #include "aolib.h" 12 13 const unsigned int nr_packets = 1000; 14 const unsigned int msg_len = 1000; 15 const unsigned int quota = nr_packets * msg_len; 16 unsigned int client_new_port; 17 18 /* Move them closer to roll-over */ 19 static void test_adjust_seqs(struct tcp_sock_state *img, 20 struct tcp_ao_repair *ao_img, 21 bool server) 22 { 23 uint32_t new_seq1, new_seq2; 24 25 /* make them roll-over during quota, but on different segments */ 26 if (server) { 27 new_seq1 = ((uint32_t)-1) - msg_len; 28 new_seq2 = ((uint32_t)-1) - (quota - 2 * msg_len); 29 } else { 30 new_seq1 = ((uint32_t)-1) - (quota - 2 * msg_len); 31 new_seq2 = ((uint32_t)-1) - msg_len; 32 } 33 34 img->in.seq = new_seq1; 35 img->trw.snd_wl1 = img->in.seq - msg_len; 36 img->out.seq = new_seq2; 37 img->trw.rcv_wup = img->in.seq; 38 } 39 40 static int test_sk_restore(struct tcp_sock_state *img, 41 struct tcp_ao_repair *ao_img, sockaddr_af *saddr, 42 const union tcp_addr daddr, unsigned int dport, 43 struct tcp_ao_counters *cnt) 44 { 45 int sk; 46 47 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP); 48 if (sk < 0) 49 test_error("socket()"); 50 51 test_enable_repair(sk); 52 test_sock_restore(sk, img, saddr, daddr, dport); 53 if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, daddr, -1, 100, 100)) 54 test_error("setsockopt(TCP_AO_ADD_KEY)"); 55 test_ao_restore(sk, ao_img); 56 57 if (test_get_tcp_ao_counters(sk, cnt)) 58 test_error("test_get_tcp_ao_counters()"); 59 60 test_disable_repair(sk); 61 test_sock_state_free(img); 62 return sk; 63 } 64 65 static void *server_fn(void *arg) 66 { 67 uint64_t before_good, after_good, after_bad; 68 struct tcp_ao_counters ao1, ao2; 69 struct tcp_sock_state img; 70 struct tcp_ao_repair ao_img; 71 sockaddr_af saddr; 72 ssize_t bytes; 73 int sk, lsk; 74 75 lsk = test_listen_socket(this_ip_addr, test_server_port, 1); 76 77 if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100)) 78 test_error("setsockopt(TCP_AO_ADD_KEY)"); 79 80 synchronize_threads(); /* 1: MKT added => connect() */ 81 82 if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0)) 83 test_error("test_wait_fd()"); 84 85 sk = accept(lsk, NULL, NULL); 86 if (sk < 0) 87 test_error("accept()"); 88 89 synchronize_threads(); /* 2: accepted => send data */ 90 close(lsk); 91 92 bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC); 93 if (bytes != quota) { 94 if (bytes > 0) 95 test_fail("server served: %zd", bytes); 96 else 97 test_fail("server returned: %zd", bytes); 98 goto out; 99 } 100 101 before_good = netstat_get_one("TCPAOGood", NULL); 102 103 synchronize_threads(); /* 3: restore the connection on another port */ 104 105 test_enable_repair(sk); 106 test_sock_checkpoint(sk, &img, &saddr); 107 test_ao_checkpoint(sk, &ao_img); 108 test_kill_sk(sk); 109 #ifdef IPV6_TEST 110 saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1); 111 #else 112 saddr.sin_port = htons(ntohs(saddr.sin_port) + 1); 113 #endif 114 test_adjust_seqs(&img, &ao_img, true); 115 synchronize_threads(); /* 4: dump finished */ 116 sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest, 117 client_new_port, &ao1); 118 119 trace_ao_event_sne_expect(TCP_AO_SND_SNE_UPDATE, this_ip_addr, 120 this_ip_dest, test_server_port + 1, client_new_port, 1); 121 trace_ao_event_sne_expect(TCP_AO_SND_SNE_UPDATE, this_ip_dest, 122 this_ip_addr, client_new_port, test_server_port + 1, 1); 123 trace_ao_event_sne_expect(TCP_AO_RCV_SNE_UPDATE, this_ip_addr, 124 this_ip_dest, test_server_port + 1, client_new_port, 1); 125 trace_ao_event_sne_expect(TCP_AO_RCV_SNE_UPDATE, this_ip_dest, 126 this_ip_addr, client_new_port, test_server_port + 1, 1); 127 synchronize_threads(); /* 5: verify the connection during SEQ-number rollover */ 128 bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC); 129 if (bytes != quota) { 130 if (bytes > 0) 131 test_fail("server served: %zd", bytes); 132 else 133 test_fail("server returned: %zd", bytes); 134 } else { 135 test_ok("server alive"); 136 } 137 138 synchronize_threads(); /* 6: verify counters after SEQ-number rollover */ 139 if (test_get_tcp_ao_counters(sk, &ao2)) 140 test_error("test_get_tcp_ao_counters()"); 141 after_good = netstat_get_one("TCPAOGood", NULL); 142 143 test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD); 144 145 if (after_good <= before_good) { 146 test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64, 147 after_good, before_good); 148 } else { 149 test_ok("TCPAOGood counter increased %" PRIu64 " => %" PRIu64, 150 before_good, after_good); 151 } 152 after_bad = netstat_get_one("TCPAOBad", NULL); 153 if (after_bad) 154 test_fail("TCPAOBad counter is non-zero: %" PRIu64, after_bad); 155 else 156 test_ok("TCPAOBad counter didn't increase"); 157 test_enable_repair(sk); 158 test_ao_checkpoint(sk, &ao_img); 159 if (ao_img.snd_sne && ao_img.rcv_sne) { 160 test_ok("SEQ extension incremented: %u/%u", 161 ao_img.snd_sne, ao_img.rcv_sne); 162 } else { 163 test_fail("SEQ extension was not incremented: %u/%u", 164 ao_img.snd_sne, ao_img.rcv_sne); 165 } 166 167 synchronize_threads(); /* 6: verified => closed */ 168 out: 169 close(sk); 170 return NULL; 171 } 172 173 static void *client_fn(void *arg) 174 { 175 uint64_t before_good, after_good, after_bad; 176 struct tcp_ao_counters ao1, ao2; 177 struct tcp_sock_state img; 178 struct tcp_ao_repair ao_img; 179 sockaddr_af saddr; 180 int sk; 181 182 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP); 183 if (sk < 0) 184 test_error("socket()"); 185 186 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100)) 187 test_error("setsockopt(TCP_AO_ADD_KEY)"); 188 189 synchronize_threads(); /* 1: MKT added => connect() */ 190 if (test_connect_socket(sk, this_ip_dest, test_server_port) <= 0) 191 test_error("failed to connect()"); 192 193 synchronize_threads(); /* 2: accepted => send data */ 194 if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) { 195 test_fail("pre-migrate verify failed"); 196 return NULL; 197 } 198 199 before_good = netstat_get_one("TCPAOGood", NULL); 200 201 synchronize_threads(); /* 3: restore the connection on another port */ 202 test_enable_repair(sk); 203 test_sock_checkpoint(sk, &img, &saddr); 204 test_ao_checkpoint(sk, &ao_img); 205 test_kill_sk(sk); 206 #ifdef IPV6_TEST 207 client_new_port = ntohs(saddr.sin6_port) + 1; 208 saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1); 209 #else 210 client_new_port = ntohs(saddr.sin_port) + 1; 211 saddr.sin_port = htons(ntohs(saddr.sin_port) + 1); 212 #endif 213 test_adjust_seqs(&img, &ao_img, false); 214 synchronize_threads(); /* 4: dump finished */ 215 sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest, 216 test_server_port + 1, &ao1); 217 218 synchronize_threads(); /* 5: verify the connection during SEQ-number rollover */ 219 if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) 220 test_fail("post-migrate verify failed"); 221 else 222 test_ok("post-migrate connection alive"); 223 224 synchronize_threads(); /* 5: verify counters after SEQ-number rollover */ 225 if (test_get_tcp_ao_counters(sk, &ao2)) 226 test_error("test_get_tcp_ao_counters()"); 227 after_good = netstat_get_one("TCPAOGood", NULL); 228 229 test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD); 230 231 if (after_good <= before_good) { 232 test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64, 233 after_good, before_good); 234 } else { 235 test_ok("TCPAOGood counter increased %" PRIu64 " => %" PRIu64, 236 before_good, after_good); 237 } 238 after_bad = netstat_get_one("TCPAOBad", NULL); 239 if (after_bad) 240 test_fail("TCPAOBad counter is non-zero: %" PRIu64, after_bad); 241 else 242 test_ok("TCPAOBad counter didn't increase"); 243 244 synchronize_threads(); /* 6: verified => closed */ 245 close(sk); 246 247 synchronize_threads(); /* don't race to exit: let server exit() */ 248 return NULL; 249 } 250 251 int main(int argc, char *argv[]) 252 { 253 test_init(8, server_fn, client_fn); 254 return 0; 255 } 256