1ed9d09b3SDmitry Safonov // SPDX-License-Identifier: GPL-2.0
2ed9d09b3SDmitry Safonov /* Author: Dmitry Safonov <dima@arista.com> */
3ed9d09b3SDmitry Safonov #include <inttypes.h>
4ed9d09b3SDmitry Safonov #include "aolib.h"
5ed9d09b3SDmitry Safonov
6ed9d09b3SDmitry Safonov #define fault(type) (inj == FAULT_ ## type)
7ed9d09b3SDmitry Safonov
test_add_key_maclen(int sk,const char * key,uint8_t maclen,union tcp_addr in_addr,uint8_t prefix,uint8_t sndid,uint8_t rcvid)8ed9d09b3SDmitry Safonov static inline int test_add_key_maclen(int sk, const char *key, uint8_t maclen,
9ed9d09b3SDmitry Safonov union tcp_addr in_addr, uint8_t prefix,
10ed9d09b3SDmitry Safonov uint8_t sndid, uint8_t rcvid)
11ed9d09b3SDmitry Safonov {
12ed9d09b3SDmitry Safonov struct tcp_ao_add tmp = {};
13ed9d09b3SDmitry Safonov int err;
14ed9d09b3SDmitry Safonov
15ed9d09b3SDmitry Safonov if (prefix > DEFAULT_TEST_PREFIX)
16ed9d09b3SDmitry Safonov prefix = DEFAULT_TEST_PREFIX;
17ed9d09b3SDmitry Safonov
18ed9d09b3SDmitry Safonov err = test_prepare_key(&tmp, DEFAULT_TEST_ALGO, in_addr, false, false,
19ed9d09b3SDmitry Safonov prefix, 0, sndid, rcvid, maclen,
20ed9d09b3SDmitry Safonov 0, strlen(key), key);
21ed9d09b3SDmitry Safonov if (err)
22ed9d09b3SDmitry Safonov return err;
23ed9d09b3SDmitry Safonov
24ed9d09b3SDmitry Safonov err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp));
25ed9d09b3SDmitry Safonov if (err < 0)
26ed9d09b3SDmitry Safonov return -errno;
27ed9d09b3SDmitry Safonov
28ed9d09b3SDmitry Safonov return test_verify_socket_key(sk, &tmp);
29ed9d09b3SDmitry Safonov }
30ed9d09b3SDmitry Safonov
try_accept(const char * tst_name,unsigned int port,const char * pwd,union tcp_addr addr,uint8_t prefix,uint8_t sndid,uint8_t rcvid,uint8_t maclen,const char * cnt_name,test_cnt cnt_expected,fault_t inj)31ed9d09b3SDmitry Safonov static void try_accept(const char *tst_name, unsigned int port, const char *pwd,
32ed9d09b3SDmitry Safonov union tcp_addr addr, uint8_t prefix,
33ed9d09b3SDmitry Safonov uint8_t sndid, uint8_t rcvid, uint8_t maclen,
34ed9d09b3SDmitry Safonov const char *cnt_name, test_cnt cnt_expected,
35ed9d09b3SDmitry Safonov fault_t inj)
36ed9d09b3SDmitry Safonov {
37ed9d09b3SDmitry Safonov struct tcp_ao_counters ao_cnt1, ao_cnt2;
38ed9d09b3SDmitry Safonov uint64_t before_cnt = 0, after_cnt = 0; /* silence GCC */
39ed9d09b3SDmitry Safonov int lsk, err, sk = 0;
40ed9d09b3SDmitry Safonov time_t timeout;
41ed9d09b3SDmitry Safonov
42ed9d09b3SDmitry Safonov lsk = test_listen_socket(this_ip_addr, port, 1);
43ed9d09b3SDmitry Safonov
44ed9d09b3SDmitry Safonov if (pwd && test_add_key_maclen(lsk, pwd, maclen, addr, prefix, sndid, rcvid))
45ed9d09b3SDmitry Safonov test_error("setsockopt(TCP_AO_ADD_KEY)");
46ed9d09b3SDmitry Safonov
47ed9d09b3SDmitry Safonov if (cnt_name)
48ed9d09b3SDmitry Safonov before_cnt = netstat_get_one(cnt_name, NULL);
49ed9d09b3SDmitry Safonov if (pwd && test_get_tcp_ao_counters(lsk, &ao_cnt1))
50ed9d09b3SDmitry Safonov test_error("test_get_tcp_ao_counters()");
51ed9d09b3SDmitry Safonov
52ed9d09b3SDmitry Safonov synchronize_threads(); /* preparations done */
53ed9d09b3SDmitry Safonov
54ed9d09b3SDmitry Safonov timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
55ed9d09b3SDmitry Safonov err = test_wait_fd(lsk, timeout, 0);
56ed9d09b3SDmitry Safonov if (err == -ETIMEDOUT) {
57ed9d09b3SDmitry Safonov if (!fault(TIMEOUT))
58*67f440c0SColin Ian King test_fail("timed out for accept()");
59ed9d09b3SDmitry Safonov } else if (err < 0) {
60ed9d09b3SDmitry Safonov test_error("test_wait_fd()");
61ed9d09b3SDmitry Safonov } else {
62ed9d09b3SDmitry Safonov if (fault(TIMEOUT))
63ed9d09b3SDmitry Safonov test_fail("ready to accept");
64ed9d09b3SDmitry Safonov
65ed9d09b3SDmitry Safonov sk = accept(lsk, NULL, NULL);
66ed9d09b3SDmitry Safonov if (sk < 0) {
67ed9d09b3SDmitry Safonov test_error("accept()");
68ed9d09b3SDmitry Safonov } else {
69ed9d09b3SDmitry Safonov if (fault(TIMEOUT))
70ed9d09b3SDmitry Safonov test_fail("%s: accepted", tst_name);
71ed9d09b3SDmitry Safonov }
72ed9d09b3SDmitry Safonov }
73ed9d09b3SDmitry Safonov
74ed9d09b3SDmitry Safonov if (pwd && test_get_tcp_ao_counters(lsk, &ao_cnt2))
75ed9d09b3SDmitry Safonov test_error("test_get_tcp_ao_counters()");
76ed9d09b3SDmitry Safonov
77ed9d09b3SDmitry Safonov close(lsk);
78ed9d09b3SDmitry Safonov if (pwd)
79ed9d09b3SDmitry Safonov test_tcp_ao_counters_cmp(tst_name, &ao_cnt1, &ao_cnt2, cnt_expected);
80ed9d09b3SDmitry Safonov
81ed9d09b3SDmitry Safonov if (!cnt_name)
82ed9d09b3SDmitry Safonov goto out;
83ed9d09b3SDmitry Safonov
84ed9d09b3SDmitry Safonov after_cnt = netstat_get_one(cnt_name, NULL);
85ed9d09b3SDmitry Safonov
86ed9d09b3SDmitry Safonov if (after_cnt <= before_cnt) {
87ed9d09b3SDmitry Safonov test_fail("%s: %s counter did not increase: %zu <= %zu",
88ed9d09b3SDmitry Safonov tst_name, cnt_name, after_cnt, before_cnt);
89ed9d09b3SDmitry Safonov } else {
90ed9d09b3SDmitry Safonov test_ok("%s: counter %s increased %zu => %zu",
91ed9d09b3SDmitry Safonov tst_name, cnt_name, before_cnt, after_cnt);
92ed9d09b3SDmitry Safonov }
93ed9d09b3SDmitry Safonov
94ed9d09b3SDmitry Safonov out:
95ed9d09b3SDmitry Safonov synchronize_threads(); /* close() */
96ed9d09b3SDmitry Safonov if (sk > 0)
97ed9d09b3SDmitry Safonov close(sk);
98ed9d09b3SDmitry Safonov }
99ed9d09b3SDmitry Safonov
server_fn(void * arg)100ed9d09b3SDmitry Safonov static void *server_fn(void *arg)
101ed9d09b3SDmitry Safonov {
102ed9d09b3SDmitry Safonov union tcp_addr wrong_addr, network_addr;
103ed9d09b3SDmitry Safonov unsigned int port = test_server_port;
104ed9d09b3SDmitry Safonov
105ed9d09b3SDmitry Safonov if (inet_pton(TEST_FAMILY, TEST_WRONG_IP, &wrong_addr) != 1)
106ed9d09b3SDmitry Safonov test_error("Can't convert ip address %s", TEST_WRONG_IP);
107ed9d09b3SDmitry Safonov
108ed9d09b3SDmitry Safonov try_accept("Non-AO server + AO client", port++, NULL,
109ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0,
110ed9d09b3SDmitry Safonov "TCPAOKeyNotFound", 0, FAULT_TIMEOUT);
111ed9d09b3SDmitry Safonov
112ed9d09b3SDmitry Safonov try_accept("AO server + Non-AO client", port++, DEFAULT_TEST_PASSWORD,
113ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0,
114ed9d09b3SDmitry Safonov "TCPAORequired", TEST_CNT_AO_REQUIRED, FAULT_TIMEOUT);
115ed9d09b3SDmitry Safonov
116ed9d09b3SDmitry Safonov try_accept("Wrong password", port++, "something that is not DEFAULT_TEST_PASSWORD",
117ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0,
118ed9d09b3SDmitry Safonov "TCPAOBad", TEST_CNT_BAD, FAULT_TIMEOUT);
119ed9d09b3SDmitry Safonov
120ed9d09b3SDmitry Safonov try_accept("Wrong rcv id", port++, DEFAULT_TEST_PASSWORD,
121ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 101, 0,
122ed9d09b3SDmitry Safonov "TCPAOKeyNotFound", TEST_CNT_AO_KEY_NOT_FOUND, FAULT_TIMEOUT);
123ed9d09b3SDmitry Safonov
124ed9d09b3SDmitry Safonov try_accept("Wrong snd id", port++, DEFAULT_TEST_PASSWORD,
125ed9d09b3SDmitry Safonov this_ip_dest, -1, 101, 100, 0,
126ed9d09b3SDmitry Safonov "TCPAOGood", TEST_CNT_GOOD, FAULT_TIMEOUT);
127ed9d09b3SDmitry Safonov
128ed9d09b3SDmitry Safonov try_accept("Different maclen", port++, DEFAULT_TEST_PASSWORD,
129ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 8,
130ed9d09b3SDmitry Safonov "TCPAOBad", TEST_CNT_BAD, FAULT_TIMEOUT);
131ed9d09b3SDmitry Safonov
132ed9d09b3SDmitry Safonov try_accept("Server: Wrong addr", port++, DEFAULT_TEST_PASSWORD,
133ed9d09b3SDmitry Safonov wrong_addr, -1, 100, 100, 0,
134ed9d09b3SDmitry Safonov "TCPAOKeyNotFound", TEST_CNT_AO_KEY_NOT_FOUND, FAULT_TIMEOUT);
135ed9d09b3SDmitry Safonov
136ed9d09b3SDmitry Safonov try_accept("Client: Wrong addr", port++, NULL,
137ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0, NULL, 0, FAULT_TIMEOUT);
138ed9d09b3SDmitry Safonov
139ed9d09b3SDmitry Safonov try_accept("rcv id != snd id", port++, DEFAULT_TEST_PASSWORD,
140ed9d09b3SDmitry Safonov this_ip_dest, -1, 200, 100, 0,
141ed9d09b3SDmitry Safonov "TCPAOGood", TEST_CNT_GOOD, 0);
142ed9d09b3SDmitry Safonov
143ed9d09b3SDmitry Safonov if (inet_pton(TEST_FAMILY, TEST_NETWORK, &network_addr) != 1)
144ed9d09b3SDmitry Safonov test_error("Can't convert ip address %s", TEST_NETWORK);
145ed9d09b3SDmitry Safonov
146ed9d09b3SDmitry Safonov try_accept("Server: prefix match", port++, DEFAULT_TEST_PASSWORD,
147ed9d09b3SDmitry Safonov network_addr, 16, 100, 100, 0,
148ed9d09b3SDmitry Safonov "TCPAOGood", TEST_CNT_GOOD, 0);
149ed9d09b3SDmitry Safonov
150ed9d09b3SDmitry Safonov try_accept("Client: prefix match", port++, DEFAULT_TEST_PASSWORD,
151ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0,
152ed9d09b3SDmitry Safonov "TCPAOGood", TEST_CNT_GOOD, 0);
153ed9d09b3SDmitry Safonov
154ed9d09b3SDmitry Safonov /* client exits */
155ed9d09b3SDmitry Safonov synchronize_threads();
156ed9d09b3SDmitry Safonov return NULL;
157ed9d09b3SDmitry Safonov }
158ed9d09b3SDmitry Safonov
try_connect(const char * tst_name,unsigned int port,const char * pwd,union tcp_addr addr,uint8_t prefix,uint8_t sndid,uint8_t rcvid,test_cnt cnt_expected,fault_t inj)159ed9d09b3SDmitry Safonov static void try_connect(const char *tst_name, unsigned int port,
160ed9d09b3SDmitry Safonov const char *pwd, union tcp_addr addr, uint8_t prefix,
161ed9d09b3SDmitry Safonov uint8_t sndid, uint8_t rcvid,
162ed9d09b3SDmitry Safonov test_cnt cnt_expected, fault_t inj)
163ed9d09b3SDmitry Safonov {
164ed9d09b3SDmitry Safonov struct tcp_ao_counters ao_cnt1, ao_cnt2;
165ed9d09b3SDmitry Safonov time_t timeout;
166ed9d09b3SDmitry Safonov int sk, ret;
167ed9d09b3SDmitry Safonov
168ed9d09b3SDmitry Safonov sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
169ed9d09b3SDmitry Safonov if (sk < 0)
170ed9d09b3SDmitry Safonov test_error("socket()");
171ed9d09b3SDmitry Safonov
172ed9d09b3SDmitry Safonov if (pwd && test_add_key(sk, pwd, addr, prefix, sndid, rcvid))
173ed9d09b3SDmitry Safonov test_error("setsockopt(TCP_AO_ADD_KEY)");
174ed9d09b3SDmitry Safonov
175ed9d09b3SDmitry Safonov if (pwd && test_get_tcp_ao_counters(sk, &ao_cnt1))
176ed9d09b3SDmitry Safonov test_error("test_get_tcp_ao_counters()");
177ed9d09b3SDmitry Safonov
178ed9d09b3SDmitry Safonov synchronize_threads(); /* preparations done */
179ed9d09b3SDmitry Safonov
180ed9d09b3SDmitry Safonov timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
181ed9d09b3SDmitry Safonov ret = _test_connect_socket(sk, this_ip_dest, port, timeout);
182ed9d09b3SDmitry Safonov
183ed9d09b3SDmitry Safonov if (ret < 0) {
184ed9d09b3SDmitry Safonov if (fault(KEYREJECT) && ret == -EKEYREJECTED) {
185ed9d09b3SDmitry Safonov test_ok("%s: connect() was prevented", tst_name);
186ed9d09b3SDmitry Safonov } else if (ret == -ETIMEDOUT && fault(TIMEOUT)) {
187ed9d09b3SDmitry Safonov test_ok("%s", tst_name);
188ed9d09b3SDmitry Safonov } else if (ret == -ECONNREFUSED &&
189ed9d09b3SDmitry Safonov (fault(TIMEOUT) || fault(KEYREJECT))) {
190ed9d09b3SDmitry Safonov test_ok("%s: refused to connect", tst_name);
191ed9d09b3SDmitry Safonov } else {
192ed9d09b3SDmitry Safonov test_error("%s: connect() returned %d", tst_name, ret);
193ed9d09b3SDmitry Safonov }
194ed9d09b3SDmitry Safonov goto out;
195ed9d09b3SDmitry Safonov }
196ed9d09b3SDmitry Safonov
197ed9d09b3SDmitry Safonov if (fault(TIMEOUT) || fault(KEYREJECT))
198ed9d09b3SDmitry Safonov test_fail("%s: connected", tst_name);
199ed9d09b3SDmitry Safonov else
200ed9d09b3SDmitry Safonov test_ok("%s: connected", tst_name);
201ed9d09b3SDmitry Safonov if (pwd && ret > 0) {
202ed9d09b3SDmitry Safonov if (test_get_tcp_ao_counters(sk, &ao_cnt2))
203ed9d09b3SDmitry Safonov test_error("test_get_tcp_ao_counters()");
204ed9d09b3SDmitry Safonov test_tcp_ao_counters_cmp(tst_name, &ao_cnt1, &ao_cnt2, cnt_expected);
205ed9d09b3SDmitry Safonov }
206ed9d09b3SDmitry Safonov out:
207ed9d09b3SDmitry Safonov synchronize_threads(); /* close() */
208ed9d09b3SDmitry Safonov
209ed9d09b3SDmitry Safonov if (ret > 0)
210ed9d09b3SDmitry Safonov close(sk);
211ed9d09b3SDmitry Safonov }
212ed9d09b3SDmitry Safonov
client_fn(void * arg)213ed9d09b3SDmitry Safonov static void *client_fn(void *arg)
214ed9d09b3SDmitry Safonov {
215ed9d09b3SDmitry Safonov union tcp_addr wrong_addr, network_addr;
216ed9d09b3SDmitry Safonov unsigned int port = test_server_port;
217ed9d09b3SDmitry Safonov
218ed9d09b3SDmitry Safonov if (inet_pton(TEST_FAMILY, TEST_WRONG_IP, &wrong_addr) != 1)
219ed9d09b3SDmitry Safonov test_error("Can't convert ip address %s", TEST_WRONG_IP);
220ed9d09b3SDmitry Safonov
221ed9d09b3SDmitry Safonov try_connect("Non-AO server + AO client", port++, DEFAULT_TEST_PASSWORD,
222ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
223ed9d09b3SDmitry Safonov
224ed9d09b3SDmitry Safonov try_connect("AO server + Non-AO client", port++, NULL,
225ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
226ed9d09b3SDmitry Safonov
227ed9d09b3SDmitry Safonov try_connect("Wrong password", port++, DEFAULT_TEST_PASSWORD,
228ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
229ed9d09b3SDmitry Safonov
230ed9d09b3SDmitry Safonov try_connect("Wrong rcv id", port++, DEFAULT_TEST_PASSWORD,
231ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
232ed9d09b3SDmitry Safonov
233ed9d09b3SDmitry Safonov try_connect("Wrong snd id", port++, DEFAULT_TEST_PASSWORD,
234ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
235ed9d09b3SDmitry Safonov
236ed9d09b3SDmitry Safonov try_connect("Different maclen", port++, DEFAULT_TEST_PASSWORD,
237ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
238ed9d09b3SDmitry Safonov
239ed9d09b3SDmitry Safonov try_connect("Server: Wrong addr", port++, DEFAULT_TEST_PASSWORD,
240ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
241ed9d09b3SDmitry Safonov
242ed9d09b3SDmitry Safonov try_connect("Client: Wrong addr", port++, DEFAULT_TEST_PASSWORD,
243ed9d09b3SDmitry Safonov wrong_addr, -1, 100, 100, 0, FAULT_KEYREJECT);
244ed9d09b3SDmitry Safonov
245ed9d09b3SDmitry Safonov try_connect("rcv id != snd id", port++, DEFAULT_TEST_PASSWORD,
246ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 200, TEST_CNT_GOOD, 0);
247ed9d09b3SDmitry Safonov
248ed9d09b3SDmitry Safonov if (inet_pton(TEST_FAMILY, TEST_NETWORK, &network_addr) != 1)
249ed9d09b3SDmitry Safonov test_error("Can't convert ip address %s", TEST_NETWORK);
250ed9d09b3SDmitry Safonov
251ed9d09b3SDmitry Safonov try_connect("Server: prefix match", port++, DEFAULT_TEST_PASSWORD,
252ed9d09b3SDmitry Safonov this_ip_dest, -1, 100, 100, TEST_CNT_GOOD, 0);
253ed9d09b3SDmitry Safonov
254ed9d09b3SDmitry Safonov try_connect("Client: prefix match", port++, DEFAULT_TEST_PASSWORD,
255ed9d09b3SDmitry Safonov network_addr, 16, 100, 100, TEST_CNT_GOOD, 0);
256ed9d09b3SDmitry Safonov
257ed9d09b3SDmitry Safonov return NULL;
258ed9d09b3SDmitry Safonov }
259ed9d09b3SDmitry Safonov
main(int argc,char * argv[])260ed9d09b3SDmitry Safonov int main(int argc, char *argv[])
261ed9d09b3SDmitry Safonov {
262ed9d09b3SDmitry Safonov test_init(21, server_fn, client_fn);
263ed9d09b3SDmitry Safonov return 0;
264ed9d09b3SDmitry Safonov }
265