]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libcharon/tests/utils/exchange_test_asserts.c
unit-tests: Ensure listeners can track SAs via ike/child_updown/rekey()
[thirdparty/strongswan.git] / src / libcharon / tests / utils / exchange_test_asserts.c
1 /*
2 * Copyright (C) 2016-2017 Tobias Brunner
3 *
4 * Copyright (C) secunet Security Networks AG
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <inttypes.h>
18
19 #include <test_suite.h>
20
21 #include "exchange_test_asserts.h"
22 #include "mock_ipsec.h"
23
24 /*
25 * Described in header
26 */
27 bool exchange_test_asserts_hook(listener_t *listener)
28 {
29 listener_hook_assert_t *this = (listener_hook_assert_t*)listener;
30
31 this->count++;
32 return TRUE;
33 }
34
35 /*
36 * Described in header
37 */
38 bool exchange_test_asserts_ike_updown(listener_t *listener, ike_sa_t *ike_sa,
39 bool up)
40 {
41 listener_hook_assert_t *this = (listener_hook_assert_t*)listener;
42
43 this->count++;
44 assert_listener_msg(this->up == up, this, "IKE_SA not '%s'",
45 this->up ? "up" : "down");
46 return TRUE;
47 }
48
49 /*
50 * Described in header
51 */
52 bool exchange_test_asserts_child_updown(listener_t *listener, ike_sa_t *ike_sa,
53 child_sa_t *child_sa, bool up)
54 {
55 listener_hook_assert_t *this = (listener_hook_assert_t*)listener;
56
57 this->count++;
58 assert_listener_msg(this->up == up, this, "CHILD_SA not '%s'",
59 this->up ? "up" : "down");
60 return TRUE;
61 }
62
63 /*
64 * Described in header
65 */
66 bool exchange_test_asserts_ike_rekey(listener_t *listener, ike_sa_t *old,
67 ike_sa_t *new)
68 {
69 listener_hook_assert_t *this = (listener_hook_assert_t*)listener;
70 ike_sa_id_t *id;
71 uint64_t spi;
72
73 this->count++;
74 id = old->get_id(old);
75 spi = id->get_initiator_spi(id);
76 assert_listener_msg(this->spi_old == spi, this, "unexpected old IKE_SA "
77 "%.16"PRIx64"_i instead of %.16"PRIx64"_i",
78 be64toh(spi), be64toh(this->spi_old));
79 id = new->get_id(new);
80 spi = id->get_initiator_spi(id);
81 assert_listener_msg(this->spi_new == spi, this, "unexpected new IKE_SA "
82 "%.16"PRIx64"_i instead of %.16"PRIx64"_i",
83 be64toh(spi), be64toh(this->spi_new));
84 return TRUE;
85 }
86
87 /*
88 * Described in header
89 */
90 bool exchange_test_asserts_child_rekey(listener_t *listener, ike_sa_t *ike_sa,
91 child_sa_t *old, child_sa_t *new)
92 {
93 listener_hook_assert_t *this = (listener_hook_assert_t*)listener;
94 uint32_t spi, expected;
95
96 this->count++;
97 spi = old->get_spi(old, TRUE);
98 expected = this->spi_old;
99 assert_listener_msg(expected == spi, this, "unexpected old CHILD_SA %.8x "
100 "instead of %.8x", spi, expected);
101 spi = new->get_spi(new, TRUE);
102 expected = this->spi_new;
103 assert_listener_msg(expected == spi, this, "unexpected new CHILD_SA %.8x "
104 "instead of %.8x", spi, expected);
105 return TRUE;
106 }
107
108 /**
109 * Track SAs via updown event.
110 */
111 static void track_sa_updown(listener_track_sas_assert_t *this, char *event,
112 array_t *sas, uint32_t id, bool up)
113 {
114 uint32_t existing;
115 bool found = FALSE;
116 int i;
117
118 if (up)
119 {
120 for (i = 0; i < array_count(sas); i++)
121 {
122 array_get(sas, i, &existing);
123 assert_listener_msg(id != existing, this, "duplicate %s(up) event "
124 "for SA %u", event, id);
125 }
126 array_insert(sas, ARRAY_TAIL, &id);
127 }
128 else
129 {
130 for (i = 0; i < array_count(sas); i++)
131 {
132 array_get(sas, i, &existing);
133 if (id == existing)
134 {
135 array_remove(sas, i, NULL);
136 found = TRUE;
137 break;
138 }
139 }
140 assert_listener_msg(found, this, "%s(down) event for unknown SA %u",
141 event, id);
142 }
143 }
144
145 /**
146 * Track SAs via a rekey event.
147 */
148 static void track_sa_rekey(listener_track_sas_assert_t *this, char *event,
149 array_t *sas, uint32_t old_id, uint32_t new_id)
150 {
151 uint32_t existing;
152 bool found = FALSE;
153 int i;
154
155 for (i = 0; i < array_count(sas); i++)
156 {
157 array_get(sas, i, &existing);
158 if (old_id == existing)
159 {
160 array_remove(sas, i, NULL);
161 found = TRUE;
162 break;
163 }
164 }
165 assert_listener_msg(found, this, "%s() event for unknown old SA %u", event,
166 old_id);
167
168 for (i = 0; i < array_count(sas); i++)
169 {
170 array_get(sas, i, &existing);
171 assert_listener_msg(new_id != existing, this, "%s() event for "
172 "already up new SA %u", event, new_id);
173 }
174 array_insert(sas, ARRAY_TAIL, &new_id);
175 }
176
177 /*
178 * Described in header
179 */
180 bool exchange_test_asserts_track_ike_updown(listener_t *listener,
181 ike_sa_t *ike_sa, bool up)
182 {
183 listener_track_sas_assert_t *this = (listener_track_sas_assert_t*)listener;
184
185 track_sa_updown(this, "ike_updown", this->ike_sas,
186 ike_sa->get_unique_id(ike_sa), up);
187 return TRUE;
188 }
189
190 /*
191 * Described in header
192 */
193 bool exchange_test_asserts_track_child_updown(listener_t *listener,
194 ike_sa_t *ike_sa,
195 child_sa_t *child_sa, bool up)
196 {
197 listener_track_sas_assert_t *this = (listener_track_sas_assert_t*)listener;
198
199 track_sa_updown(this, "child_updown", this->child_sas,
200 child_sa->get_unique_id(child_sa), up);
201 return TRUE;
202 }
203
204 /*
205 * Described in header
206 */
207 bool exchange_test_asserts_track_ike_rekey(listener_t *listener, ike_sa_t *old,
208 ike_sa_t *new)
209 {
210 listener_track_sas_assert_t *this = (listener_track_sas_assert_t*)listener;
211
212 track_sa_rekey(this, "ike_rekey", this->ike_sas, old->get_unique_id(old),
213 new->get_unique_id(new));
214 return TRUE;
215 }
216
217 /*
218 * Described in header
219 */
220 bool exchange_test_asserts_track_child_rekey(listener_t *listener,
221 ike_sa_t *ike_sa, child_sa_t *old,
222 child_sa_t *new)
223 {
224 listener_track_sas_assert_t *this = (listener_track_sas_assert_t*)listener;
225
226 track_sa_rekey(this, "child_rekey", this->child_sas, old->get_unique_id(old),
227 new->get_unique_id(new));
228 return TRUE;
229 }
230
231 /**
232 * Assert a given message rule
233 */
234 static void assert_message_rule(listener_message_assert_t *this, message_t *msg,
235 listener_message_rule_t *rule)
236 {
237 if (rule->expected)
238 {
239 if (rule->payload)
240 {
241 assert_listener_msg(msg->get_payload(msg, rule->payload),
242 this, "expected payload (%N) not found",
243 payload_type_names, rule->payload);
244
245 }
246 if (rule->notify)
247 {
248 assert_listener_msg(msg->get_notify(msg, rule->notify),
249 this, "expected notify payload (%N) not found",
250 notify_type_names, rule->notify);
251 }
252 }
253 else
254 {
255 if (rule->payload)
256 {
257 assert_listener_msg(!msg->get_payload(msg, rule->payload),
258 this, "unexpected payload (%N) found",
259 payload_type_names, rule->payload);
260
261 }
262 if (rule->notify)
263 {
264 assert_listener_msg(!msg->get_notify(msg, rule->notify),
265 this, "unexpected notify payload (%N) found",
266 notify_type_names, rule->notify);
267 }
268 }
269 }
270
271 /*
272 * Described in header
273 */
274 bool exchange_test_asserts_message(listener_t *listener, ike_sa_t *ike_sa,
275 message_t *message, bool incoming, bool plain)
276 {
277 listener_message_assert_t *this = (listener_message_assert_t*)listener;
278
279 if (plain && this->incoming == incoming)
280 {
281 if (this->count >= 0)
282 {
283 enumerator_t *enumerator;
284 int count = 0;
285 enumerator = message->create_payload_enumerator(message);
286 while (enumerator->enumerate(enumerator, NULL))
287 {
288 count++;
289 }
290 enumerator->destroy(enumerator);
291 assert_listener_msg(this->count == count, this, "unexpected payload "
292 "count in message (%d != %d)", this->count,
293 count);
294 }
295 if (this->num_rules)
296 {
297 int i;
298
299 for (i = 0; i < this->num_rules; i++)
300 {
301 assert_message_rule(this, message, &this->rules[i]);
302 }
303 }
304 free(this->rules);
305 free(this);
306 return FALSE;
307 }
308 return TRUE;
309 }
310
311 /**
312 * Compare two SPIs
313 */
314 static int spis_cmp(const void *a, const void *b)
315 {
316 return *(const uint32_t*)a - *(const uint32_t*)b;
317 }
318
319 /**
320 * Compare two SPIs to sort them
321 */
322 static int spis_sort(const void *a, const void *b, void *data)
323 {
324 return spis_cmp(a, b);
325 }
326
327
328 /*
329 * Described in header
330 */
331 void exchange_test_asserts_ipsec_sas(ipsec_sas_assert_t *sas)
332 {
333 enumerator_t *enumerator;
334 array_t *spis;
335 ike_sa_t *ike_sa;
336 uint32_t spi;
337 int i;
338
339 spis = array_create(sizeof(uint32_t), 0);
340 for (i = 0; i < sas->count; i++)
341 {
342 array_insert(spis, ARRAY_TAIL, &sas->spis[i]);
343 }
344 array_sort(spis, spis_sort, NULL);
345
346 enumerator = mock_ipsec_create_sa_enumerator();
347 while (enumerator->enumerate(enumerator, &ike_sa, &spi))
348 {
349 if (ike_sa == sas->ike_sa)
350 {
351 i = array_bsearch(spis, &spi, spis_cmp, NULL);
352 assert_listener_msg(i != -1, sas, "unexpected IPsec SA %.8x", spi);
353 array_remove(spis, i, NULL);
354 }
355 }
356 enumerator->destroy(enumerator);
357 for (i = 0; i < array_count(spis); i++)
358 {
359 array_get(spis, i, &spi);
360 assert_listener_msg(!spi, sas, "expected IPsec SA %.8x not found", spi);
361 }
362 array_destroy(spis);
363 }