1 /*
2 * Copyright (C) 2012-2016 Sean Buckheister
3 * Copyright (C) 2016 Nikos Mavrogiannopoulos
4 * Copyright (C) 2016 Red Hat, Inc.
5 *
6 * This file is part of GnuTLS.
7 *
8 * GnuTLS is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * GnuTLS is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GnuTLS; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 /*
24 * DTLS stress test utility
25 *
26 * **** Available parameters ****
27 *
28 * -nb enable nonblocking operations on sessions
29 * -batch read test identifiers from stdin and run them
30 * -d increase debug level by one
31 * -r replay messages (very crude replay mechanism)
32 * -d <n> set debug level to <n>
33 * -die don't start new tests after the first detected failure
34 * -timeout <n> set handshake timeout to <n> seconds. Tests that don't make progress
35 * within twice this time will be forcibly killed. (default: 120)
36 * -retransmit <n> set retransmit timeout to <n> milliseconds (default: 100)
37 * -j <n> run up to <n> tests in parallel
38 * -full use full handshake with mutual certificate authentication
39 * -resume use resumed handshake
40 * -shello <perm> run only one test, with the server hello flight permuted as <perm>
41 * -sfinished <perm> run only one test, with the server finished flight permuted as <perm>
42 * -cfinished <perm> run only one test, with the client finished flight permuted as <perm>
43 * <packet name> run only one test, drop <packet name> three times
44 * valid values for <packet name> are:
45 * SHello, SCertificate, SKeyExchange, SCertificateRequest, SHelloDone,
46 * CCertificate, CKeyExchange, CCertificateVerify, CChangeCipherSpec,
47 * CFinished, SChangeCipherSpec, SFinished
48 * using *Certificate* without -full will yield unexpected results
49 *
50 *
51 * **** Permutation handling ****
52 *
53 * Flight length for -sfinished is 2, for -shello and -cfinished they are 5 with -full, 3 otherwise.
54 * Permutations are given with base 0 and specify the order in which reordered packets are transmitted.
55 * For example, -full -shello 42130 will transmit server hello flight packets in the order
56 * SHelloDone, SKeyExchange, SCertificate, SCertificateRequest, SHello
57 *
58 * When -resume is specified the -sfinished flight length is 3 (same as shello), cfinished is 2.
59 * The -resume option has to be combined with sfinished or cfinished.
60 *
61 * **** Output format ****
62 *
63 * Every line printed for any given test is prefixed by a unique id for that test. See run_test_by_id for
64 * exact composition. Errors encountered during execution are printed, with one status line after test
65 * completen. The format for this line is as follows:
66 *
67 * <id> <status> SHello(<shperm>), SFinished(<sfinperm>), CFinished(<cfinperm>) :- <drops>
68 *
69 * The format for error lines is <id> <role>| <text>, with <role> being the role of the child process
70 * that encountered the error, and <text> being obvious.
71 *
72 * <id> is the unique id for the test, it can be used as input to -batch.
73 * <status> can be ++ for a successful test, -- for a failure, TT for a deadlock timeout killed test,
74 * or !! for a test has died due to some unforeseen circumstances like syscall failures.
75 * <shperm>, <sfinperm>, <cfinperm> show the permutation for the respective flights used.
76 * They can be used as input to -shello, -sfinished, and -cfinished, respectively.
77 * <drops> is a comma separated list of <packet name>, one for every packet dropped thrice
78 *
79 *
80 * **** Exit status ****
81 *
82 * 0 all tests have passed
83 * 1 some tests have failed
84 * 4 the master processed has encountered unexpected errors
85 * 8 error parsing command line
86 */
87
88 #include <config.h>
89 #include <gnutls/gnutls.h>
90 #include <gnutls/openpgp.h>
91 #include <gnutls/dtls.h>
92 #include <unistd.h>
93 #include "../utils.h"
94 #include <sys/socket.h>
95 #include <sys/types.h>
96 #include <netinet/in.h>
97 #include <fcntl.h>
98 #include <stdio.h>
99 #include <stdlib.h>
100 #include <string.h>
101 #include <errno.h>
102 #include <poll.h>
103 #include <time.h>
104 #include <assert.h>
105 #include <sys/wait.h>
106
107 #if _POSIX_TIMERS && (_POSIX_TIMERS - 200112L) >= 0
108
109 // {{{ types
110
111 #define log(fmt, ...) \
112 if (debug) fprintf(stdout, "%i %s| "fmt, run_id, role_name, ##__VA_ARGS__)
113
114 typedef struct {
115 int count;
116 } filter_packet_state_t;
117
118 typedef struct {
119 const char *name;
120 gnutls_datum_t packets[5];
121 int *order;
122 int count;
123 } filter_permute_state_t;
124
125 typedef void (*filter_fn) (gnutls_transport_ptr_t, const unsigned char *,
126 size_t);
127
128 typedef int (*match_fn) (const unsigned char *, size_t);
129
130 enum role { SERVER, CLIENT };
131
132 // }}}
133
134 // {{{ static data
135
136 static int permutations2[2][2]
137 = { {0, 1}, {1, 0} };
138
139 static const char *permutation_names2[]
140 = { "01", "10", 0 };
141
142 static int permutations3[6][3]
143 = { {0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0} };
144
145 static const char *permutation_names3[]
146 = { "012", "021", "102", "120", "201", "210", 0 };
147
148 static int permutations5[120][5] = {
149 {0, 1, 2, 3, 4}, {0, 2, 1, 3, 4}, {1, 0, 2, 3, 4}, {1, 2, 0, 3, 4},
150 {2, 0, 1, 3, 4}, {2, 1, 0, 3, 4}, {0, 1, 3, 2, 4}, {0, 2, 3, 1, 4},
151 {1, 0, 3, 2, 4}, {1, 2, 3, 0, 4}, {2, 0, 3, 1, 4}, {2, 1, 3, 0, 4},
152 {0, 3, 1, 2, 4}, {0, 3, 2, 1, 4}, {1, 3, 0, 2, 4}, {1, 3, 2, 0, 4},
153 {2, 3, 0, 1, 4}, {2, 3, 1, 0, 4}, {3, 0, 1, 2, 4}, {3, 0, 2, 1, 4},
154 {3, 1, 0, 2, 4}, {3, 1, 2, 0, 4}, {3, 2, 0, 1, 4}, {3, 2, 1, 0, 4},
155 {0, 1, 2, 4, 3}, {0, 2, 1, 4, 3}, {1, 0, 2, 4, 3}, {1, 2, 0, 4, 3},
156 {2, 0, 1, 4, 3}, {2, 1, 0, 4, 3}, {0, 1, 3, 4, 2}, {0, 2, 3, 4, 1},
157 {1, 0, 3, 4, 2}, {1, 2, 3, 4, 0}, {2, 0, 3, 4, 1}, {2, 1, 3, 4, 0},
158 {0, 3, 1, 4, 2}, {0, 3, 2, 4, 1}, {1, 3, 0, 4, 2}, {1, 3, 2, 4, 0},
159 {2, 3, 0, 4, 1}, {2, 3, 1, 4, 0}, {3, 0, 1, 4, 2}, {3, 0, 2, 4, 1},
160 {3, 1, 0, 4, 2}, {3, 1, 2, 4, 0}, {3, 2, 0, 4, 1}, {3, 2, 1, 4, 0},
161 {0, 1, 4, 2, 3}, {0, 2, 4, 1, 3}, {1, 0, 4, 2, 3}, {1, 2, 4, 0, 3},
162 {2, 0, 4, 1, 3}, {2, 1, 4, 0, 3}, {0, 1, 4, 3, 2}, {0, 2, 4, 3, 1},
163 {1, 0, 4, 3, 2}, {1, 2, 4, 3, 0}, {2, 0, 4, 3, 1}, {2, 1, 4, 3, 0},
164 {0, 3, 4, 1, 2}, {0, 3, 4, 2, 1}, {1, 3, 4, 0, 2}, {1, 3, 4, 2, 0},
165 {2, 3, 4, 0, 1}, {2, 3, 4, 1, 0}, {3, 0, 4, 1, 2}, {3, 0, 4, 2, 1},
166 {3, 1, 4, 0, 2}, {3, 1, 4, 2, 0}, {3, 2, 4, 0, 1}, {3, 2, 4, 1, 0},
167 {0, 4, 1, 2, 3}, {0, 4, 2, 1, 3}, {1, 4, 0, 2, 3}, {1, 4, 2, 0, 3},
168 {2, 4, 0, 1, 3}, {2, 4, 1, 0, 3}, {0, 4, 1, 3, 2}, {0, 4, 2, 3, 1},
169 {1, 4, 0, 3, 2}, {1, 4, 2, 3, 0}, {2, 4, 0, 3, 1}, {2, 4, 1, 3, 0},
170 {0, 4, 3, 1, 2}, {0, 4, 3, 2, 1}, {1, 4, 3, 0, 2}, {1, 4, 3, 2, 0},
171 {2, 4, 3, 0, 1}, {2, 4, 3, 1, 0}, {3, 4, 0, 1, 2}, {3, 4, 0, 2, 1},
172 {3, 4, 1, 0, 2}, {3, 4, 1, 2, 0}, {3, 4, 2, 0, 1}, {3, 4, 2, 1, 0},
173 {4, 0, 1, 2, 3}, {4, 0, 2, 1, 3}, {4, 1, 0, 2, 3}, {4, 1, 2, 0, 3},
174 {4, 2, 0, 1, 3}, {4, 2, 1, 0, 3}, {4, 0, 1, 3, 2}, {4, 0, 2, 3, 1},
175 {4, 1, 0, 3, 2}, {4, 1, 2, 3, 0}, {4, 2, 0, 3, 1}, {4, 2, 1, 3, 0},
176 {4, 0, 3, 1, 2}, {4, 0, 3, 2, 1}, {4, 1, 3, 0, 2}, {4, 1, 3, 2, 0},
177 {4, 2, 3, 0, 1}, {4, 2, 3, 1, 0}, {4, 3, 0, 1, 2}, {4, 3, 0, 2, 1},
178 {4, 3, 1, 0, 2}, {4, 3, 1, 2, 0}, {4, 3, 2, 0, 1}, {4, 3, 2, 1, 0}
179 };
180
181 static const char *permutation_names5[]
182 = { "01234", "02134", "10234", "12034", "20134", "21034", "01324",
183 "02314", "10324", "12304", "20314", "21304", "03124", "03214",
184 "13024", "13204", "23014", "23104", "30124", "30214", "31024",
185 "31204", "32014", "32104", "01243", "02143", "10243", "12043",
186 "20143", "21043", "01342", "02341", "10342", "12340", "20341",
187 "21340", "03142", "03241", "13042", "13240", "23041", "23140",
188 "30142", "30241", "31042", "31240", "32041", "32140", "01423",
189 "02413", "10423", "12403", "20413", "21403", "01432", "02431",
190 "10432", "12430", "20431", "21430", "03412", "03421", "13402",
191 "13420", "23401", "23410", "30412", "30421", "31402", "31420",
192 "32401", "32410", "04123", "04213", "14023", "14203", "24013",
193 "24103", "04132", "04231", "14032", "14230", "24031", "24130",
194 "04312", "04321", "14302", "14320", "24301", "24310", "34012",
195 "34021", "34102", "34120", "34201", "34210", "40123", "40213",
196 "41023", "41203", "42013", "42103", "40132", "40231", "41032",
197 "41230", "42031", "42130", "40312", "40321", "41302", "41320",
198 "42301", "42310", "43012", "43021", "43102", "43120", "43201",
199 "43210", 0
200 };
201
202 static const char *filter_names[8]
203 = { "SHello",
204 "SKeyExchange",
205 "SHelloDone",
206 "CKeyExchange",
207 "CChangeCipherSpec",
208 "CFinished",
209 "SChangeCipherSpec",
210 "SFinished"
211 };
212
213 static const char *filter_names_resume[]
214 = { "SHello",
215 "SChangeCipherSpec",
216 "SFinished",
217 "CChangeCipherSpec",
218 "CFinished"
219 };
220
221 static const char *filter_names_full[12]
222 = { "SHello",
223 "SCertificate",
224 "SKeyExchange",
225 "SCertificateRequest",
226 "SHelloDone",
227 "CCertificate",
228 "CKeyExchange",
229 "CCertificateVerify",
230 "CChangeCipherSpec",
231 "CFinished",
232 "SChangeCipherSpec",
233 "SFinished"
234 };
235
236 #include "cert-common.h"
237
238 // }}}
239
240 // {{{ other global state
241
242 enum role role;
243
244 #define role_name (role == SERVER ? "server" : "client")
245
246 int debug;
247 int nonblock;
248 int replay;
249 int full;
250 int resume;
251 int timeout_seconds;
252 int retransmit_milliseconds;
253 int run_to_end;
254
255 int run_id;
256
257 // }}}
258
259 // {{{ logging and error handling
260
logfn(int level,const char * s)261 static void logfn(int level, const char *s)
262 {
263 if (debug) {
264 fprintf(stdout, "%i %s|<%i> %s", run_id, role_name, level, s);
265 }
266 }
267
auditfn(gnutls_session_t session,const char * s)268 static void auditfn(gnutls_session_t session, const char *s)
269 {
270 if (debug) {
271 fprintf(stdout, "%i %s| %s", run_id, role_name, s);
272 }
273 }
274
drop(const char * packet)275 static void drop(const char *packet)
276 {
277 if (debug) {
278 log("dropping %s\n", packet);
279 }
280 }
281
_process_error(int loc,int code,int die)282 static int _process_error(int loc, int code, int die)
283 {
284 if (code < 0 && (die || code != GNUTLS_E_AGAIN)) {
285 fprintf(stdout, "%i <%s tls> line %i: %s", run_id,
286 role_name, loc, gnutls_strerror(code));
287 if (gnutls_error_is_fatal(code) || die) {
288 fprintf(stdout, " (fatal)\n");
289 exit(1);
290 } else {
291 fprintf(stdout, "\n");
292 }
293 }
294 return code;
295 }
296
297 #define die_on_error(code) _process_error(__LINE__, code, 1)
298 #define process_error(code) _process_error(__LINE__, code, 0)
299
_process_error_or_timeout(int loc,int err,time_t tdiff)300 static void _process_error_or_timeout(int loc, int err, time_t tdiff)
301 {
302 if (err < 0) {
303 if (err != GNUTLS_E_TIMEDOUT || tdiff >= 60) {
304 _process_error(loc, err, 0);
305 } else {
306 log("line %i: {spurious timeout} (fatal)", loc);
307 exit(1);
308 }
309 }
310 }
311
312 #define process_error_or_timeout(code, tdiff) _process_error_or_timeout(__LINE__, code, tdiff)
313
rperror(const char * name)314 static void rperror(const char *name)
315 {
316 fprintf(stdout, "%i %s| %s\n", run_id, role_name, name);
317 }
318
319 // }}}
320
321 // {{{ init, shared, and teardown code and data for packet stream filters
322
323 filter_packet_state_t state_packet_ServerHello = { 0 };
324 filter_packet_state_t state_packet_ServerCertificate = { 0 };
325 filter_packet_state_t state_packet_ServerKeyExchange = { 0 };
326 filter_packet_state_t state_packet_ServerCertificateRequest = { 0 };
327 filter_packet_state_t state_packet_ServerHelloDone = { 0 };
328 filter_packet_state_t state_packet_ClientCertificate = { 0 };
329 filter_packet_state_t state_packet_ClientKeyExchange = { 0 };
330 filter_packet_state_t state_packet_ClientCertificateVerify = { 0 };
331 filter_packet_state_t state_packet_ClientChangeCipherSpec = { 0 };
332 filter_packet_state_t state_packet_ClientFinished = { 0 };
333 filter_packet_state_t state_packet_ClientFinishedResume = { 0 };
334 filter_packet_state_t state_packet_ServerChangeCipherSpec = { 0 };
335 filter_packet_state_t state_packet_ServerFinished = { 0 };
336 filter_packet_state_t state_packet_ServerFinishedResume = { 0 };
337
338 static filter_permute_state_t state_permute_ServerHello =
339 { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
340 static filter_permute_state_t state_permute_ServerHelloFull =
341 { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
342 static filter_permute_state_t state_permute_ServerFinished =
343 { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
344 static filter_permute_state_t state_permute_ServerFinishedResume =
345 { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
346 static filter_permute_state_t state_permute_ClientFinished =
347 { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
348 static filter_permute_state_t state_permute_ClientFinishedResume =
349 { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
350 static filter_permute_state_t state_permute_ClientFinishedFull =
351 { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
352
353 filter_fn filter_chain[32];
354 int filter_current_idx;
355
filter_permute_state_free_buffer(filter_permute_state_t * state)356 static void filter_permute_state_free_buffer(filter_permute_state_t * state)
357 {
358 unsigned int i;
359
360 for (i = 0; i < sizeof(state->packets) / sizeof(state->packets[0]); i++) {
361 free(state->packets[i].data);
362 state->packets[i].data = NULL;
363 }
364 }
365
filter_clear_state(void)366 static void filter_clear_state(void)
367 {
368 filter_current_idx = 0;
369
370 filter_permute_state_free_buffer(&state_permute_ServerHello);
371 filter_permute_state_free_buffer(&state_permute_ServerHelloFull);
372 filter_permute_state_free_buffer(&state_permute_ServerFinished);
373 filter_permute_state_free_buffer(&state_permute_ServerFinishedResume);
374 filter_permute_state_free_buffer(&state_permute_ClientFinished);
375 filter_permute_state_free_buffer(&state_permute_ClientFinishedResume);
376 filter_permute_state_free_buffer(&state_permute_ClientFinishedFull);
377
378 memset(&state_packet_ServerHello, 0, sizeof(state_packet_ServerHello));
379 memset(&state_packet_ServerCertificate, 0,
380 sizeof(state_packet_ServerCertificate));
381 memset(&state_packet_ServerKeyExchange, 0,
382 sizeof(state_packet_ServerKeyExchange));
383 memset(&state_packet_ServerCertificateRequest, 0,
384 sizeof(state_packet_ServerCertificateRequest));
385 memset(&state_packet_ServerHelloDone, 0,
386 sizeof(state_packet_ServerHelloDone));
387 memset(&state_packet_ClientCertificate, 0,
388 sizeof(state_packet_ClientCertificate));
389 memset(&state_packet_ClientKeyExchange, 0,
390 sizeof(state_packet_ClientKeyExchange));
391 memset(&state_packet_ClientCertificateVerify, 0,
392 sizeof(state_packet_ClientCertificateVerify));
393 memset(&state_packet_ClientChangeCipherSpec, 0,
394 sizeof(state_packet_ClientChangeCipherSpec));
395 memset(&state_packet_ClientFinished, 0,
396 sizeof(state_packet_ClientFinished));
397 memset(&state_packet_ClientFinishedResume, 0,
398 sizeof(state_packet_ClientFinishedResume));
399 memset(&state_packet_ServerChangeCipherSpec, 0,
400 sizeof(state_packet_ServerChangeCipherSpec));
401 memset(&state_packet_ServerFinished, 0,
402 sizeof(state_packet_ServerFinished));
403 memset(&state_packet_ServerFinishedResume, 0,
404 sizeof(state_packet_ServerFinishedResume));
405 memset(&state_permute_ServerHello, 0,
406 sizeof(state_permute_ServerHello));
407 memset(&state_permute_ServerHelloFull, 0,
408 sizeof(state_permute_ServerHelloFull));
409 memset(&state_permute_ServerFinished, 0,
410 sizeof(state_permute_ServerFinished));
411 memset(&state_permute_ClientFinished, 0,
412 sizeof(state_permute_ClientFinished));
413 memset(&state_permute_ClientFinishedResume, 0,
414 sizeof(state_permute_ClientFinishedResume));
415 memset(&state_permute_ClientFinishedFull, 0,
416 sizeof(state_permute_ClientFinishedFull));
417
418 state_permute_ServerHello.name = "ServerHello";
419 state_permute_ServerHelloFull.name = "ServerHelloFull";
420 state_permute_ServerFinished.name = "ServerFinished";
421 state_permute_ServerFinishedResume.name = "ServerFinishedResume";
422 state_permute_ClientFinished.name = "ClientFinished";
423 state_permute_ClientFinishedResume.name = "ClientFinishedResume";
424 state_permute_ClientFinishedFull.name = "ClientFinishedFull";
425 }
426
427 /* replay buffer */
428 static int rbuffer[5 * 1024];
429 unsigned rbuffer_size = 0;
430
filter_run_next(gnutls_transport_ptr_t fd,const unsigned char * buffer,size_t len)431 static void filter_run_next(gnutls_transport_ptr_t fd,
432 const unsigned char *buffer, size_t len)
433 {
434 int ret = 0;
435 filter_fn fn = filter_chain[filter_current_idx];
436 filter_current_idx++;
437 if (fn) {
438 fn(fd, buffer, len);
439 } else {
440 ret = send((int)(intptr_t) fd, buffer, len, 0);
441 }
442 filter_current_idx--;
443
444 if (ret > 0 && replay != 0) {
445 if (rbuffer_size == 0 && len < sizeof(rbuffer)) {
446 memcpy(rbuffer, buffer, len);
447 rbuffer_size = len;
448 } else if (rbuffer_size != 0) {
449 send((int)(intptr_t) fd, rbuffer, rbuffer_size, 0);
450 if (len < sizeof(rbuffer) && len > rbuffer_size) {
451 memcpy(rbuffer, buffer, len);
452 rbuffer_size = len;
453 }
454 }
455 }
456 }
457
458 // }}}
459
460 // {{{ packet match functions
461
match_ServerHello(const unsigned char * buffer,size_t len)462 static int match_ServerHello(const unsigned char *buffer, size_t len)
463 {
464 return role == SERVER && len >= 13 + 1 && buffer[0] == 22
465 && buffer[13] == 2;
466 }
467
match_ServerCertificate(const unsigned char * buffer,size_t len)468 static int match_ServerCertificate(const unsigned char *buffer, size_t len)
469 {
470 return role == SERVER && len >= 13 + 1 && buffer[0] == 22
471 && buffer[13] == 11;
472 }
473
match_ServerKeyExchange(const unsigned char * buffer,size_t len)474 static int match_ServerKeyExchange(const unsigned char *buffer, size_t len)
475 {
476 return role == SERVER && len >= 13 + 1 && buffer[0] == 22
477 && buffer[13] == 12;
478 }
479
match_ServerCertificateRequest(const unsigned char * buffer,size_t len)480 static int match_ServerCertificateRequest(const unsigned char *buffer,
481 size_t len)
482 {
483 return role == SERVER && len >= 13 + 1 && buffer[0] == 22
484 && buffer[13] == 13;
485 }
486
match_ServerHelloDone(const unsigned char * buffer,size_t len)487 static int match_ServerHelloDone(const unsigned char *buffer, size_t len)
488 {
489 return role == SERVER && len >= 13 + 1 && buffer[0] == 22
490 && buffer[13] == 14;
491 }
492
match_ClientCertificate(const unsigned char * buffer,size_t len)493 static int match_ClientCertificate(const unsigned char *buffer, size_t len)
494 {
495 return role == CLIENT && len >= 13 + 1 && buffer[0] == 22
496 && buffer[13] == 11;
497 }
498
match_ClientKeyExchange(const unsigned char * buffer,size_t len)499 static int match_ClientKeyExchange(const unsigned char *buffer, size_t len)
500 {
501 return role == CLIENT && len >= 13 + 1 && buffer[0] == 22
502 && buffer[13] == 16;
503 }
504
match_ClientCertificateVerify(const unsigned char * buffer,size_t len)505 static int match_ClientCertificateVerify(const unsigned char *buffer,
506 size_t len)
507 {
508 return role == CLIENT && len >= 13 + 1 && buffer[0] == 22
509 && buffer[13] == 15;
510 }
511
match_ClientChangeCipherSpec(const unsigned char * buffer,size_t len)512 static int match_ClientChangeCipherSpec(const unsigned char *buffer, size_t len)
513 {
514 return role == CLIENT && len >= 13 && buffer[0] == 20;
515 }
516
match_ClientFinished(const unsigned char * buffer,size_t len)517 static int match_ClientFinished(const unsigned char *buffer, size_t len)
518 {
519 return role == CLIENT && len >= 13 && buffer[0] == 22 && buffer[4] == 1;
520 }
521
match_ServerChangeCipherSpec(const unsigned char * buffer,size_t len)522 static int match_ServerChangeCipherSpec(const unsigned char *buffer, size_t len)
523 {
524 return role == SERVER && len >= 13 && buffer[0] == 20;
525 }
526
match_ServerFinished(const unsigned char * buffer,size_t len)527 static int match_ServerFinished(const unsigned char *buffer, size_t len)
528 {
529 return role == SERVER && len >= 13 && buffer[0] == 22 && buffer[4] == 1;
530 }
531
532 // }}}
533
534 // {{{ packet drop filters
535
536 #define FILTER_DROP_COUNT 3
537 #define DECLARE_FILTER(packet) \
538 static void filter_packet_##packet(gnutls_transport_ptr_t fd, \
539 const unsigned char* buffer, size_t len) \
540 { \
541 if (match_##packet(buffer, len) && (state_packet_##packet).count++ < FILTER_DROP_COUNT) { \
542 drop(#packet); \
543 } else { \
544 filter_run_next(fd, buffer, len); \
545 } \
546 }
547
548 DECLARE_FILTER(ServerHello)
DECLARE_FILTER(ServerCertificate)549 DECLARE_FILTER(ServerCertificate)
550 DECLARE_FILTER(ServerKeyExchange)
551 DECLARE_FILTER(ServerCertificateRequest)
552 DECLARE_FILTER(ServerHelloDone)
553 DECLARE_FILTER(ClientCertificate)
554 DECLARE_FILTER(ClientKeyExchange)
555 DECLARE_FILTER(ClientCertificateVerify)
556 DECLARE_FILTER(ClientChangeCipherSpec)
557 DECLARE_FILTER(ClientFinished)
558 DECLARE_FILTER(ServerChangeCipherSpec)
559 DECLARE_FILTER(ServerFinished)
560 // }}}
561 // {{{ flight permutation filters
562 static void filter_permute_state_run(filter_permute_state_t * state,
563 int packetCount,
564 gnutls_transport_ptr_t fd,
565 const unsigned char *buffer, size_t len)
566 {
567 unsigned char *data = malloc(len);
568 int packet = state->order[state->count];
569
570 if (debug > 2)
571 log("running permutation for %s/%d/%d\n", state->name, packetCount, state->count);
572
573 memcpy(data, buffer, len);
574 state->packets[packet].data = data;
575 state->packets[packet].size = len;
576 state->count++;
577
578 if (state->count == packetCount) {
579 for (packet = 0; packet < packetCount; packet++) {
580 filter_run_next(fd, state->packets[packet].data,
581 state->packets[packet].size);
582 }
583 filter_permute_state_free_buffer(state);
584 state->count = 0;
585 }
586 }
587
588 #define DECLARE_PERMUTE(flight) \
589 static void filter_permute_##flight(gnutls_transport_ptr_t fd, \
590 const unsigned char* buffer, size_t len) \
591 { \
592 int count = sizeof(permute_match_##flight) / sizeof(permute_match_##flight[0]); \
593 int i; \
594 for (i = 0; i < count; i++) { \
595 if (permute_match_##flight[i](buffer, len)) { \
596 filter_permute_state_run(&state_permute_##flight, count, fd, buffer, len); \
597 return; \
598 } \
599 } \
600 filter_run_next(fd, buffer, len); \
601 }
602
603 static match_fn permute_match_ServerHello[] =
604 { match_ServerHello, match_ServerKeyExchange, match_ServerHelloDone };
605
606 static match_fn permute_match_ServerHelloFull[] =
607 { match_ServerHello, match_ServerCertificate, match_ServerKeyExchange,
608 match_ServerCertificateRequest, match_ServerHelloDone
609 };
610
611 static match_fn permute_match_ServerFinished[] =
612 { match_ServerChangeCipherSpec, match_ServerFinished };
613
614 static match_fn permute_match_ServerFinishedResume[] =
615 { match_ServerHello, match_ServerChangeCipherSpec, match_ServerFinished };
616
617 static match_fn permute_match_ClientFinished[] =
618 { match_ClientKeyExchange, match_ClientChangeCipherSpec,
619 match_ClientFinished
620 };
621
622 static match_fn permute_match_ClientFinishedResume[] =
623 { match_ClientChangeCipherSpec, match_ClientFinished
624 };
625
626 static match_fn permute_match_ClientFinishedFull[] =
627 { match_ClientCertificate, match_ClientKeyExchange,
628 match_ClientCertificateVerify, match_ClientChangeCipherSpec,
629 match_ClientFinished
630 };
631
632 DECLARE_PERMUTE(ServerHello)
633 DECLARE_PERMUTE(ServerHelloFull)
634 DECLARE_PERMUTE(ServerFinishedResume)
635 DECLARE_PERMUTE(ServerFinished)
636 DECLARE_PERMUTE(ClientFinished)
637 DECLARE_PERMUTE(ClientFinishedResume)
638 DECLARE_PERMUTE(ClientFinishedFull)
639 // }}}
640 // {{{ emergency deadlock resolution time bomb
641 timer_t killtimer_tid = 0;
642
killtimer_set(void)643 static void killtimer_set(void)
644 {
645 struct sigevent sig;
646 struct itimerspec tout = { {0, 0}, {2 * timeout_seconds, 0} };
647
648 if (killtimer_tid != 0) {
649 timer_delete(killtimer_tid);
650 }
651
652 memset(&sig, 0, sizeof(sig));
653 sig.sigev_notify = SIGEV_SIGNAL;
654 sig.sigev_signo = 15;
655 if (timer_create(CLOCK_MONOTONIC, &sig, &killtimer_tid) < 0) {
656 rperror("timer_create");
657 exit(3);
658 }
659
660 timer_settime(killtimer_tid, 0, &tout, 0);
661 }
662
663 // }}}
664
665 // {{{ actual gnutls operations
666
667 gnutls_certificate_credentials_t cred;
668 gnutls_session_t session;
669
writefn(gnutls_transport_ptr_t fd,const void * buffer,size_t len)670 static ssize_t writefn(gnutls_transport_ptr_t fd, const void *buffer,
671 size_t len)
672 {
673 filter_run_next(fd, (const unsigned char *)buffer, len);
674 return len;
675 }
676
await(int fd,int timeout)677 static void await(int fd, int timeout)
678 {
679 if (nonblock) {
680 struct pollfd p = { fd, POLLIN, 0 };
681 if (poll(&p, 1, timeout) < 0 && errno != EAGAIN
682 && errno != EINTR) {
683 rperror("poll");
684 exit(3);
685 }
686 }
687 }
688
cred_init(void)689 static void cred_init(void)
690 {
691 assert(gnutls_certificate_allocate_credentials(&cred)>=0);
692
693 gnutls_certificate_set_x509_key_mem(cred, &cli_ca3_cert, &cli_ca3_key,
694 GNUTLS_X509_FMT_PEM);
695 }
696
session_init(int sock,int server)697 static void session_init(int sock, int server)
698 {
699 gnutls_init(&session,
700 GNUTLS_DATAGRAM | (server ? GNUTLS_SERVER : GNUTLS_CLIENT)
701 | GNUTLS_NONBLOCK * nonblock);
702 gnutls_priority_set_direct(session,
703 "NORMAL:+ECDHE-RSA:+ANON-ECDH",
704 0);
705 gnutls_transport_set_int(session, sock);
706
707 if (full) {
708 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
709 if (server) {
710 gnutls_certificate_server_set_request(session,
711 GNUTLS_CERT_REQUIRE);
712 }
713 } else if (server) {
714 gnutls_anon_server_credentials_t acred;
715 assert(gnutls_anon_allocate_server_credentials(&acred)>=0);
716 gnutls_credentials_set(session, GNUTLS_CRD_ANON, acred);
717 } else {
718 gnutls_anon_client_credentials_t acred;
719 assert(gnutls_anon_allocate_client_credentials(&acred)>=0);
720 gnutls_credentials_set(session, GNUTLS_CRD_ANON, acred);
721 }
722
723 gnutls_dtls_set_mtu(session, 1400);
724 gnutls_dtls_set_timeouts(session, retransmit_milliseconds,
725 timeout_seconds * 1000);
726 }
727
client(int sock)728 static void client(int sock)
729 {
730 int err = 0;
731 time_t started = time(0);
732 const char *line = "foobar!";
733 char buffer[8192];
734 int len, ret;
735 gnutls_datum_t data = {NULL, 0};
736
737 session_init(sock, 0);
738
739 killtimer_set();
740
741 if (resume) {
742 do {
743 err = process_error(gnutls_handshake(session));
744 if (err != 0) {
745 int t = gnutls_dtls_get_timeout(session);
746 await(sock, t ? t : 100);
747 }
748 } while (err != 0);
749 process_error_or_timeout(err, time(0) - started);
750
751 ret = gnutls_session_get_data2(session, &data);
752 if (ret < 0) {
753 exit(1);
754 }
755 gnutls_deinit(session);
756
757 session_init(sock, 0);
758 gnutls_session_set_data(session, data.data, data.size);
759 gnutls_free(data.data);
760 data.data = NULL;
761
762 if (debug) {
763 fprintf(stdout, "%i %s| initial handshake complete\n", run_id, role_name);
764 }
765 }
766
767 gnutls_transport_set_push_function(session, writefn);
768
769 killtimer_set();
770 do {
771 err = process_error(gnutls_handshake(session));
772 if (err != 0) {
773 int t = gnutls_dtls_get_timeout(session);
774 await(sock, t ? t : 100);
775 }
776 } while (err != 0);
777 process_error_or_timeout(err, time(0) - started);
778
779 if (debug) {
780 fprintf(stdout, "%i %s| handshake complete\n", run_id, role_name);
781 }
782
783 if (resume) {
784 killtimer_set();
785
786 do {
787 await(sock, -1);
788 len =
789 process_error(gnutls_record_recv
790 (session, buffer, sizeof(buffer)));
791 } while (len < 0);
792
793 log("received data\n");
794
795 die_on_error(gnutls_record_send(session, buffer, len));
796
797 log("sent data\n");
798 exit(0);
799
800 } else {
801 killtimer_set();
802 die_on_error(gnutls_record_send(session, line, strlen(line)));
803
804 log("sent data\n");
805
806 do {
807 await(sock, -1);
808 len =
809 process_error(gnutls_record_recv
810 (session, buffer, sizeof(buffer)));
811 } while (len < 0);
812
813 log("received data\n");
814
815 if (len > 0 && strncmp(line, buffer, len) == 0) {
816 exit(0);
817 } else {
818 exit(1);
819 }
820 }
821
822 }
823
824 static gnutls_datum_t saved_data = {NULL, 0};
825
db_fetch(void * dbf,gnutls_datum_t key)826 static gnutls_datum_t db_fetch(void *dbf, gnutls_datum_t key)
827 {
828 gnutls_datum_t t = {NULL, 0};
829 t.data = malloc(saved_data.size);
830 if (t.data == NULL)
831 return t;
832 memcpy(t.data, saved_data.data, saved_data.size);
833 t.size = saved_data.size;
834
835 return t;
836 }
837
db_delete(void * dbf,gnutls_datum_t key)838 static int db_delete(void *dbf, gnutls_datum_t key)
839 {
840 return 0;
841 }
842
db_store(void * dbf,gnutls_datum_t key,gnutls_datum_t data)843 static int db_store(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
844 {
845 saved_data.data = malloc(data.size);
846 if (saved_data.data == NULL)
847 return -1;
848 memcpy(saved_data.data, data.data, data.size);
849 saved_data.size = data.size;
850 return 0;
851 }
852
server(int sock)853 static void server(int sock)
854 {
855 int err;
856 const char *line = "server foobar!";
857 time_t started = time(0);
858 char buffer[8192];
859 int len;
860
861 session_init(sock, 1);
862
863 await(sock, -1);
864
865 killtimer_set();
866 if (resume) {
867 gnutls_db_set_retrieve_function(session, db_fetch);
868 gnutls_db_set_store_function(session, db_store);
869 gnutls_db_set_remove_function(session, db_delete);
870 gnutls_db_set_ptr(session, NULL);
871
872 do {
873 err = process_error(gnutls_handshake(session));
874 if (err != 0) {
875 int t = gnutls_dtls_get_timeout(session);
876 await(sock, t ? t : 100);
877 }
878 } while (err != 0);
879 process_error_or_timeout(err, time(0) - started);
880
881 gnutls_deinit(session);
882
883 session_init(sock, 1);
884 gnutls_db_set_retrieve_function(session, db_fetch);
885 gnutls_db_set_store_function(session, db_store);
886 gnutls_db_set_remove_function(session, db_delete);
887 gnutls_db_set_ptr(session, NULL);
888
889 if (debug) {
890 fprintf(stdout, "%i %s| initial handshake complete\n", run_id, role_name);
891 }
892 }
893
894 gnutls_transport_set_push_function(session, writefn);
895
896 await(sock, -1);
897
898 killtimer_set();
899 do {
900 err = process_error(gnutls_handshake(session));
901 if (err != 0) {
902 int t = gnutls_dtls_get_timeout(session);
903 await(sock, t ? t : 100);
904 }
905 } while (err != 0);
906 process_error_or_timeout(err, time(0) - started);
907
908 log("handshake complete\n");
909
910 if (resume) {
911 free(saved_data.data);
912 saved_data.data = NULL;
913 }
914
915 if (resume) {
916 killtimer_set();
917 die_on_error(gnutls_record_send(session, line, strlen(line)));
918
919 log("sent data\n");
920
921 do {
922 await(sock, -1);
923 len =
924 process_error(gnutls_record_recv
925 (session, buffer, sizeof(buffer)));
926 } while (len < 0);
927
928 log("received data\n");
929
930 if (len > 0 && strncmp(line, buffer, len) == 0) {
931 exit(0);
932 } else {
933 exit(1);
934 }
935 } else {
936 killtimer_set();
937
938 do {
939 await(sock, -1);
940 len =
941 process_error(gnutls_record_recv
942 (session, buffer, sizeof(buffer)));
943 } while (len < 0);
944
945 log("received data\n");
946
947 die_on_error(gnutls_record_send(session, buffer, len));
948
949 log("sent data\n");
950 }
951
952 exit(0);
953 }
954
955 // }}}
956
957 // {{{ test running/handling itself
958
959 #if 0
960 static void udp_sockpair(int *socks)
961 {
962 struct sockaddr_in6 sa =
963 { AF_INET6, htons(30000), 0, in6addr_loopback, 0 };
964 struct sockaddr_in6 sb =
965 { AF_INET6, htons(20000), 0, in6addr_loopback, 0 };
966
967 socks[0] = socket(AF_INET6, SOCK_DGRAM, 0);
968 socks[1] = socket(AF_INET6, SOCK_DGRAM, 0);
969
970 bind(socks[0], (struct sockaddr *)&sa, sizeof(sa));
971 bind(socks[1], (struct sockaddr *)&sb, sizeof(sb));
972
973 connect(socks[1], (struct sockaddr *)&sa, sizeof(sa));
974 connect(socks[0], (struct sockaddr *)&sb, sizeof(sb));
975 }
976 #endif
977
run_test(void)978 static int run_test(void)
979 {
980 int fds[2];
981 int pid1, pid2;
982 int status2;
983
984 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
985 rperror("socketpair");
986 exit(2);
987 }
988
989 if (nonblock) {
990 fcntl(fds[0], F_SETFL, (long)O_NONBLOCK);
991 fcntl(fds[1], F_SETFL, (long)O_NONBLOCK);
992 }
993
994 if (!(pid1 = fork())) {
995 role = SERVER;
996 server(fds[1]); // noreturn
997 } else if (pid1 < 0) {
998 rperror("fork server");
999 exit(2);
1000 }
1001 if (!(pid2 = fork())) {
1002 role = CLIENT;
1003 client(fds[0]); // noreturn
1004 } else if (pid2 < 0) {
1005 rperror("fork client");
1006 exit(2);
1007 }
1008 while (waitpid(pid2, &status2, 0) < 0 && errno == EINTR) ;
1009 kill(pid1, 15);
1010 while (waitpid(pid1, 0, 0) < 0 && errno == EINTR) ;
1011
1012 close(fds[0]);
1013 close(fds[1]);
1014
1015 if (!WIFSIGNALED(status2) && WEXITSTATUS(status2) != 3) {
1016 return ! !WEXITSTATUS(status2);
1017 } else {
1018 return 3;
1019 }
1020 }
1021
1022 static filter_fn filters[]
1023 = { filter_packet_ServerHello,
1024 filter_packet_ServerKeyExchange,
1025 filter_packet_ServerHelloDone,
1026 filter_packet_ClientKeyExchange,
1027 filter_packet_ClientChangeCipherSpec,
1028 filter_packet_ClientFinished,
1029 filter_packet_ServerChangeCipherSpec,
1030 filter_packet_ServerFinished
1031 };
1032
1033 static filter_fn filters_resume[]
1034 = { filter_packet_ServerHello,
1035 filter_packet_ServerChangeCipherSpec,
1036 filter_packet_ServerFinished,
1037 filter_packet_ClientChangeCipherSpec,
1038 filter_packet_ClientFinished
1039 };
1040
1041 static filter_fn filters_full[]
1042 = { filter_packet_ServerHello,
1043 filter_packet_ServerCertificate,
1044 filter_packet_ServerKeyExchange,
1045 filter_packet_ServerCertificateRequest,
1046 filter_packet_ServerHelloDone,
1047 filter_packet_ClientCertificate,
1048 filter_packet_ClientKeyExchange,
1049 filter_packet_ClientCertificateVerify,
1050 filter_packet_ClientChangeCipherSpec,
1051 filter_packet_ClientFinished,
1052 filter_packet_ServerChangeCipherSpec,
1053 filter_packet_ServerFinished
1054 };
1055
run_one_test(int dropMode,int serverFinishedPermute,int serverHelloPermute,int clientFinishedPermute)1056 static int run_one_test(int dropMode, int serverFinishedPermute,
1057 int serverHelloPermute, int clientFinishedPermute)
1058 {
1059 int fnIdx = 0;
1060 int res, filterIdx;
1061 filter_fn *local_filters;
1062 const char **local_filter_names;
1063 const char **client_finished_permutation_names;
1064 const char **server_finished_permutation_names;
1065 const char **server_hello_permutation_names;
1066 int filter_count;
1067
1068 if (full) {
1069 local_filters = filters_full;
1070 local_filter_names = filter_names_full;
1071 filter_count = sizeof(filters_full)/sizeof(filters_full[0]);
1072 client_finished_permutation_names = permutation_names5;
1073 server_finished_permutation_names = permutation_names2;
1074 server_hello_permutation_names = permutation_names5;
1075 } else if (resume) {
1076 local_filters = filters_resume;
1077 local_filter_names = filter_names_resume;
1078 filter_count = sizeof(filters_resume)/sizeof(filters_resume[0]);
1079 client_finished_permutation_names = permutation_names2;
1080 server_finished_permutation_names = permutation_names3;
1081 server_hello_permutation_names = NULL;
1082 } else {
1083 local_filters = filters;
1084 local_filter_names = filter_names;
1085 filter_count = sizeof(filters)/sizeof(filters[0]);
1086 client_finished_permutation_names = permutation_names3;
1087 server_finished_permutation_names = permutation_names2;
1088 server_hello_permutation_names = permutation_names3;
1089 }
1090
1091 run_id =
1092 ((dropMode * 2 + serverFinishedPermute) * (full ? 120 : 6) +
1093 serverHelloPermute) * (full ? 120 : 6) + clientFinishedPermute;
1094
1095 filter_clear_state();
1096
1097 if (full) {
1098 filter_chain[fnIdx++] = filter_permute_ServerHelloFull;
1099 state_permute_ServerHelloFull.order =
1100 permutations5[serverHelloPermute];
1101
1102 filter_chain[fnIdx++] = filter_permute_ClientFinishedFull;
1103 state_permute_ClientFinishedFull.order =
1104 permutations5[clientFinishedPermute];
1105
1106 filter_chain[fnIdx++] = filter_permute_ServerFinished;
1107 state_permute_ServerFinished.order =
1108 permutations2[serverFinishedPermute];
1109 } else if (resume) {
1110 filter_chain[fnIdx++] = filter_permute_ServerFinishedResume;
1111 state_permute_ServerFinishedResume.order =
1112 permutations3[serverFinishedPermute];
1113
1114 filter_chain[fnIdx++] = filter_permute_ClientFinishedResume;
1115 state_permute_ClientFinishedResume.order =
1116 permutations2[clientFinishedPermute];
1117 } else {
1118 filter_chain[fnIdx++] = filter_permute_ServerHello;
1119 state_permute_ServerHello.order =
1120 permutations3[serverHelloPermute];
1121
1122 filter_chain[fnIdx++] = filter_permute_ClientFinished;
1123 state_permute_ClientFinished.order =
1124 permutations3[clientFinishedPermute];
1125
1126 filter_chain[fnIdx++] = filter_permute_ServerFinished;
1127 state_permute_ServerFinished.order =
1128 permutations2[serverFinishedPermute];
1129 }
1130
1131 if (dropMode) {
1132 for (filterIdx = 0; filterIdx < filter_count; filterIdx++) {
1133 if (dropMode & (1 << filterIdx)) {
1134 filter_chain[fnIdx++] =
1135 local_filters[filterIdx];
1136 }
1137 }
1138 }
1139 filter_chain[fnIdx++] = NULL;
1140
1141 res = run_test();
1142
1143 switch (res) {
1144 case 0:
1145 fprintf(stdout, "%i ++ ", run_id);
1146 break;
1147 case 1:
1148 fprintf(stdout, "%i -- ", run_id);
1149 break;
1150 case 2:
1151 fprintf(stdout, "%i !! ", run_id);
1152 break;
1153 case 3:
1154 fprintf(stdout, "%i TT ", run_id);
1155 break;
1156 }
1157
1158 if (!resume)
1159 fprintf(stdout, "SHello(%s), ", server_hello_permutation_names[serverHelloPermute]);
1160 fprintf(stdout, "SFinished(%s), ",
1161 server_finished_permutation_names[serverFinishedPermute]);
1162 fprintf(stdout, "CFinished(%s) :- ",
1163 client_finished_permutation_names[clientFinishedPermute]);
1164 if (dropMode) {
1165 for (filterIdx = 0; filterIdx < filter_count; filterIdx++) {
1166 if (dropMode & (1 << filterIdx)) {
1167 if (dropMode & ((1 << filterIdx) - 1)) {
1168 fprintf(stdout, ", ");
1169 }
1170 fprintf(stdout, "%s",
1171 local_filter_names[filterIdx]);
1172 }
1173 }
1174 }
1175 fprintf(stdout, "\n");
1176
1177 return res;
1178 }
1179
run_test_by_id(int id)1180 static int run_test_by_id(int id)
1181 {
1182 int pscale = full ? 120 : 6;
1183 int dropMode, serverFinishedPermute, serverHelloPermute,
1184 clientFinishedPermute;
1185
1186 clientFinishedPermute = id % pscale;
1187 id /= pscale;
1188
1189 serverHelloPermute = id % pscale;
1190 id /= pscale;
1191
1192 serverFinishedPermute = id % 2;
1193 id /= 2;
1194
1195 dropMode = id;
1196
1197 return run_one_test(dropMode, serverFinishedPermute,
1198 serverHelloPermute, clientFinishedPermute);
1199 }
1200
1201 int *job_pids;
1202 int job_limit;
1203 int children = 0;
1204
register_child(int pid)1205 static void register_child(int pid)
1206 {
1207 int idx;
1208
1209 children++;
1210 for (idx = 0; idx < job_limit; idx++) {
1211 if (job_pids[idx] == 0) {
1212 job_pids[idx] = pid;
1213 return;
1214 }
1215 }
1216 }
1217
wait_children(int child_limit)1218 static int wait_children(int child_limit)
1219 {
1220 int fail = 0;
1221 int result = 1;
1222
1223 while (children > child_limit) {
1224 int status;
1225 int idx;
1226 int pid = waitpid(0, &status, 0);
1227 if (pid < 0 && errno == ECHILD) {
1228 break;
1229 }
1230 for (idx = 0; idx < job_limit; idx++) {
1231 if (job_pids[idx] == pid) {
1232 children--;
1233 if (WEXITSTATUS(status)) {
1234 result = 1;
1235 if (!run_to_end && !fail) {
1236 fprintf(stderr,
1237 "One test failed, waiting for remaining tests\n");
1238 fail = 1;
1239 child_limit = 0;
1240 }
1241 }
1242 job_pids[idx] = 0;
1243 break;
1244 }
1245 }
1246 }
1247
1248 if (fail) {
1249 exit(1);
1250 }
1251
1252 return result;
1253 }
1254
run_tests_from_id_list(int childcount)1255 static int run_tests_from_id_list(int childcount)
1256 {
1257 int test_id;
1258 int ret;
1259 int result = 0;
1260
1261 while ((ret = fscanf(stdin, "%i\n", &test_id)) > 0) {
1262 int pid;
1263 if (test_id < 0
1264 || test_id >
1265 2 * (full ? 120 * 120 * (1 << 12) : 6 * 6 * 256)) {
1266 fprintf(stderr, "Invalid test id %i\n", test_id);
1267 break;
1268 }
1269 if (!(pid = fork())) {
1270 exit(run_test_by_id(test_id));
1271 } else if (pid < 0) {
1272 rperror("fork");
1273 result = 4;
1274 break;
1275 } else {
1276 register_child(pid);
1277 result |= wait_children(childcount);
1278 }
1279 }
1280
1281 if (ret < 0 && ret != EOF) {
1282 fprintf(stderr, "Error reading test id list\n");
1283 }
1284
1285 result |= wait_children(0);
1286
1287 return result;
1288 }
1289
run_all_tests(int childcount)1290 static int run_all_tests(int childcount)
1291 {
1292 int dropMode, serverFinishedPermute, serverHelloPermute,
1293 clientFinishedPermute;
1294 int result = 0;
1295
1296 for (dropMode = 0; dropMode != 1 << (full ? 12 : 8); dropMode++)
1297 for (serverFinishedPermute = 0; serverFinishedPermute < 2;
1298 serverFinishedPermute++)
1299 for (serverHelloPermute = 0;
1300 serverHelloPermute < (full ? 120 : 6);
1301 serverHelloPermute++)
1302 for (clientFinishedPermute = 0;
1303 clientFinishedPermute <
1304 (full ? 120 : 6);
1305 clientFinishedPermute++) {
1306 int pid;
1307 if (!(pid = fork())) {
1308 exit(run_one_test
1309 (dropMode,
1310 serverFinishedPermute,
1311 serverHelloPermute,
1312 clientFinishedPermute));
1313 } else if (pid < 0) {
1314 rperror("fork");
1315 result = 4;
1316 break;
1317 } else {
1318 register_child(pid);
1319 result |=
1320 wait_children(childcount);
1321 }
1322 }
1323
1324 result |= wait_children(0);
1325
1326 return result;
1327 }
1328
1329 // }}}
1330
parse_permutation(const char * arg,const char * permutations[],int * val)1331 static int parse_permutation(const char *arg, const char *permutations[],
1332 int *val)
1333 {
1334 *val = 0;
1335 while (permutations[*val]) {
1336 if (strcmp(permutations[*val], arg) == 0) {
1337 return 1;
1338 } else {
1339 *val += 1;
1340 }
1341 }
1342 return 0;
1343 }
1344
main(int argc,const char * argv[])1345 int main(int argc, const char *argv[])
1346 {
1347 int dropMode = 0;
1348 int serverFinishedPermute = 0;
1349 int serverHelloPermute = 0;
1350 int clientFinishedPermute = 0;
1351 int batch = 0;
1352 unsigned single = 0;
1353 int arg;
1354
1355 nonblock = 0;
1356 replay = 0;
1357 debug = 0;
1358 timeout_seconds = 120;
1359 retransmit_milliseconds = 100;
1360 full = 0;
1361 run_to_end = 1;
1362 job_limit = 1;
1363
1364 #define NEXT_ARG(name) \
1365 do { \
1366 if (++arg >= argc) { \
1367 fprintf(stderr, "No argument for -" #name "\n"); \
1368 exit(8); \
1369 } \
1370 } while (0);
1371 #define FAIL_ARG(name) \
1372 do { \
1373 fprintf(stderr, "Invalid argument for -" #name "\n"); \
1374 exit(8); \
1375 } while (0);
1376
1377 for (arg = 1; arg < argc; arg++) {
1378 if (strcmp("-die", argv[arg]) == 0) {
1379 run_to_end = 0;
1380 } else if (strcmp("-batch", argv[arg]) == 0) {
1381 batch = 1;
1382 } else if (strcmp("-d", argv[arg]) == 0) {
1383 char *end;
1384 int level;
1385
1386 if (arg+1 < argc) {
1387 level = strtol(argv[arg + 1], &end, 10);
1388 if (*end == '\0') {
1389 debug = level;
1390 arg++;
1391 } else
1392 debug++;
1393 } else {
1394 debug++;
1395 }
1396 } else if (strcmp("-nb", argv[arg]) == 0) {
1397 nonblock = 1;
1398 } else if (strcmp("-r", argv[arg]) == 0) {
1399 replay = 1;
1400 } else if (strcmp("-timeout", argv[arg]) == 0) {
1401 char *end;
1402 int val;
1403
1404 NEXT_ARG(timeout);
1405 val = strtol(argv[arg], &end, 10);
1406 if (*end == '\0') {
1407 timeout_seconds = val;
1408 } else {
1409 FAIL_ARG(timeout);
1410 }
1411 } else if (strcmp("-retransmit", argv[arg]) == 0) {
1412 char *end;
1413 int val;
1414
1415 NEXT_ARG(retransmit);
1416 val = strtol(argv[arg], &end, 10);
1417 if (*end == '\0') {
1418 retransmit_milliseconds = val;
1419 } else {
1420 FAIL_ARG(retransmit);
1421 }
1422 } else if (strcmp("-j", argv[arg]) == 0) {
1423 char *end;
1424 int val;
1425
1426 NEXT_ARG(timeout);
1427 val = strtol(argv[arg], &end, 10);
1428 if (*end == '\0') {
1429 job_limit = val;
1430 } else {
1431 FAIL_ARG(j);
1432 }
1433 } else if (strcmp("-full", argv[arg]) == 0) {
1434 if (resume) {
1435 fprintf(stderr, "You cannot combine full with resume\n");
1436 exit(1);
1437 }
1438
1439 full = 1;
1440 } else if (strcmp("-resume", argv[arg]) == 0) {
1441 if (full) {
1442 fprintf(stderr, "You cannot combine full with resume\n");
1443 exit(1);
1444 }
1445
1446 resume = 1;
1447 } else if (strcmp("-shello", argv[arg]) == 0) {
1448 if (resume) {
1449 fprintf(stderr, "Please use -sfinished instead of -shello\n");
1450 exit(1);
1451 }
1452
1453 NEXT_ARG(shello);
1454 if (!parse_permutation
1455 (argv[arg],
1456 full ? permutation_names5 :
1457 permutation_names3, &serverHelloPermute)) {
1458 FAIL_ARG(shell);
1459 }
1460 single++;
1461 } else if (strcmp("-sfinished", argv[arg]) == 0) {
1462 const char **pname;
1463 NEXT_ARG(cfinished);
1464 if (resume) pname = permutation_names3;
1465 else pname = permutation_names2;
1466 if (!parse_permutation
1467 (argv[arg], pname,
1468 &serverFinishedPermute)) {
1469 FAIL_ARG(cfinished);
1470 }
1471 single++;
1472 } else if (strcmp("-cfinished", argv[arg]) == 0) {
1473 const char **pname;
1474 NEXT_ARG(cfinished);
1475 if (full) pname = permutation_names5;
1476 else if (resume) pname = permutation_names2;
1477 else pname = permutation_names3;
1478 if (!parse_permutation
1479 (argv[arg], pname,
1480 &clientFinishedPermute)) {
1481 FAIL_ARG(cfinished);
1482 }
1483 single++;
1484 } else {
1485 int drop;
1486 int filter_count;
1487 const char **local_filter_names;
1488
1489 if (full) {
1490 local_filter_names = filter_names_full;
1491 filter_count = sizeof(filters_full)/sizeof(filters_full[0]);
1492 } else if (resume) {
1493 local_filter_names = filter_names_resume;
1494 filter_count = sizeof(filters_resume)/sizeof(filters_resume[0]);
1495 } else {
1496 local_filter_names = filter_names;
1497 filter_count = sizeof(filters)/sizeof(filters[0]);
1498 }
1499
1500 for (drop = 0; drop < filter_count; drop++) {
1501 if (strcmp
1502 (local_filter_names[drop],
1503 argv[arg]) == 0) {
1504 dropMode |= (1 << drop);
1505 break;
1506 }
1507 }
1508 if (drop == filter_count) {
1509 fprintf(stderr, "Unknown packet %s\n",
1510 argv[arg]);
1511 exit(8);
1512 }
1513 single++;
1514 }
1515 }
1516
1517 setlinebuf(stdout);
1518 global_init();
1519 cred_init();
1520 gnutls_global_set_log_function(logfn);
1521 gnutls_global_set_audit_log_function(auditfn);
1522 gnutls_global_set_log_level(debug);
1523
1524 if (single) {
1525 if (debug)
1526 fprintf(stderr, "single test mode\n");
1527 return run_one_test(dropMode, serverFinishedPermute,
1528 serverHelloPermute, clientFinishedPermute);
1529 } else {
1530 if (debug)
1531 fprintf(stderr, "multi test mode\n");
1532
1533 if (resume) {
1534 fprintf(stderr, "full run not implemented yet for resumed runs\n");
1535 exit(5);
1536 }
1537
1538 job_pids = calloc(sizeof(int), job_limit);
1539 if (batch) {
1540 return run_tests_from_id_list(job_limit);
1541 } else {
1542 return run_all_tests(job_limit);
1543 }
1544 }
1545 }
1546
1547 // vim: foldmethod=marker
1548
1549 #else /* NO POSIX TIMERS */
1550
main(int argc,const char * argv[])1551 int main(int argc, const char *argv[])
1552 {
1553 exit(77);
1554 }
1555
1556 #endif
1557