testing: Added ha/active-passive scenario
[strongswan.git] / src / stroke / stroke.c
1 /*
2 * Copyright (C) 2007-2015 Tobias Brunner
3 * Copyright (C) 2006 Martin Willi
4 * Hochschule fuer Technik Rapperswil
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 <stdlib.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <getopt.h>
22
23 #include <library.h>
24
25 #include "stroke_msg.h"
26 #include "stroke_keywords.h"
27
28 struct stroke_token {
29 char *name;
30 stroke_keyword_t kw;
31 };
32
33 static char *daemon_name = "charon";
34 static int output_verbosity = 1; /* CONTROL */
35
36 static stroke_msg_t *create_stroke_msg(int type)
37 {
38 stroke_msg_t *msg;
39
40 INIT(msg,
41 .type = type,
42 .length = offsetof(stroke_msg_t, buffer),
43 );
44 return msg;
45 }
46
47 #define push_string(msg, field, str) \
48 push_string_impl(msg, offsetof(stroke_msg_t, field), str)
49
50 static void push_string_impl(stroke_msg_t **msg, size_t offset, char *string)
51 {
52 size_t cur_len = (*msg)->length, str_len;
53
54 if (!string)
55 {
56 return;
57 }
58 str_len = strlen(string) + 1;
59 if (cur_len + str_len >= UINT16_MAX)
60 {
61 (*msg)->length = UINT16_MAX;
62 return;
63 }
64 while (cur_len + str_len > sizeof(stroke_msg_t) + (*msg)->buflen)
65 {
66 *msg = realloc(*msg, sizeof(stroke_msg_t) + (*msg)->buflen +
67 STROKE_BUF_LEN_INC);
68 (*msg)->buflen += STROKE_BUF_LEN_INC;
69 }
70 (*msg)->length += str_len;
71 strcpy((char*)*msg + cur_len, string);
72 *(char**)((char*)*msg + offset) = (char*)cur_len;
73 }
74
75 static int send_stroke_msg(stroke_msg_t *msg)
76 {
77 stream_t *stream;
78 char *uri, buffer[512], *pass;
79 int count;
80
81 if (msg->length == UINT16_MAX)
82 {
83 fprintf(stderr, "stroke message exceeds maximum buffer size");
84 free(msg);
85 return -1;
86 }
87
88 msg->output_verbosity = output_verbosity;
89
90 uri = lib->settings->get_str(lib->settings, "%s.plugins.stroke.socket",
91 "unix://" STROKE_SOCKET, daemon_name);
92 stream = lib->streams->connect(lib->streams, uri);
93 if (!stream)
94 {
95 fprintf(stderr, "failed to connect to stroke socket '%s'\n", uri);
96 free(msg);
97 return -1;
98 }
99
100 if (!stream->write_all(stream, msg, msg->length))
101 {
102 fprintf(stderr, "sending stroke message failed\n");
103 stream->destroy(stream);
104 free(msg);
105 return -1;
106 }
107
108 while ((count = stream->read(stream, buffer, sizeof(buffer)-1, TRUE)) > 0)
109 {
110 buffer[count] = '\0';
111
112 /* we prompt if we receive a magic keyword */
113 if ((count >= 12 && streq(buffer + count - 12, "Passphrase:\n")) ||
114 (count >= 10 && streq(buffer + count - 10, "Password:\n")) ||
115 (count >= 5 && streq(buffer + count - 5, "PIN:\n")))
116 {
117 /* remove trailing newline */
118 pass = strrchr(buffer, '\n');
119 if (pass)
120 {
121 *pass = ' ';
122 }
123 #ifdef HAVE_GETPASS
124 pass = getpass(buffer);
125 #else
126 pass = "";
127 #endif
128 if (pass)
129 {
130 stream->write_all(stream, pass, strlen(pass));
131 stream->write_all(stream, "\n", 1);
132 }
133 }
134 else
135 {
136 printf("%s", buffer);
137 }
138 }
139 if (count < 0)
140 {
141 fprintf(stderr, "reading stroke response failed\n");
142 }
143 stream->destroy(stream);
144 free(msg);
145 return 0;
146 }
147
148 static int add_connection(char *name,
149 char *my_id, char *other_id,
150 char *my_addr, char *other_addr,
151 char *my_nets, char *other_nets)
152 {
153 stroke_msg_t *msg;
154
155 msg = create_stroke_msg(STR_ADD_CONN);
156
157 push_string(&msg, add_conn.name, name);
158 msg->add_conn.version = 2;
159 msg->add_conn.mode = 1;
160 msg->add_conn.mobike = 1;
161 msg->add_conn.dpd.action = 1;
162 msg->add_conn.install_policy = 1;
163
164 push_string(&msg, add_conn.me.id, my_id);
165 push_string(&msg, add_conn.me.address, my_addr);
166 msg->add_conn.me.ikeport = 500;
167 push_string(&msg, add_conn.me.subnets, my_nets);
168 msg->add_conn.me.sendcert = 1;
169 msg->add_conn.me.to_port = 65535;
170
171 push_string(&msg, add_conn.other.id, other_id);
172 push_string(&msg, add_conn.other.address, other_addr);
173 msg->add_conn.other.ikeport = 500;
174 push_string(&msg, add_conn.other.subnets, other_nets);
175 msg->add_conn.other.sendcert = 1;
176 msg->add_conn.other.to_port = 65535;
177
178 return send_stroke_msg(msg);
179 }
180
181 static int del_connection(char *name)
182 {
183 stroke_msg_t *msg;
184
185 msg = create_stroke_msg(STR_DEL_CONN);
186 push_string(&msg, initiate.name, name);
187 return send_stroke_msg(msg);
188 }
189
190 static int initiate_connection(char *name)
191 {
192 stroke_msg_t *msg;
193
194 msg = create_stroke_msg(STR_INITIATE);
195 push_string(&msg, initiate.name, name);
196 return send_stroke_msg(msg);
197 }
198
199 static int terminate_connection(char *name)
200 {
201 stroke_msg_t *msg;
202
203 msg = create_stroke_msg(STR_TERMINATE);
204 push_string(&msg, initiate.name, name);
205 return send_stroke_msg(msg);
206 }
207
208 static int terminate_connection_srcip(char *start, char *end)
209 {
210 stroke_msg_t *msg;
211
212 msg = create_stroke_msg(STR_TERMINATE_SRCIP);
213 push_string(&msg, terminate_srcip.start, start);
214 push_string(&msg, terminate_srcip.end, end);
215 return send_stroke_msg(msg);
216 }
217
218 static int rekey_connection(char *name)
219 {
220 stroke_msg_t *msg;
221
222 msg = create_stroke_msg(STR_REKEY);
223 push_string(&msg, rekey.name, name);
224 return send_stroke_msg(msg);
225 }
226
227 static int route_connection(char *name)
228 {
229 stroke_msg_t *msg;
230
231 msg = create_stroke_msg(STR_ROUTE);
232 push_string(&msg, route.name, name);
233 return send_stroke_msg(msg);
234 }
235
236 static int unroute_connection(char *name)
237 {
238 stroke_msg_t *msg;
239
240 msg = create_stroke_msg(STR_UNROUTE);
241 push_string(&msg, unroute.name, name);
242 return send_stroke_msg(msg);
243 }
244
245 static int show_status(stroke_keyword_t kw, char *connection)
246 {
247 stroke_msg_t *msg;
248
249 switch (kw)
250 {
251 case STROKE_STATUSALL:
252 msg = create_stroke_msg(STR_STATUS_ALL);
253 break;
254 case STROKE_STATUSALL_NOBLK:
255 msg = create_stroke_msg(STR_STATUS_ALL_NOBLK);
256 break;
257 default:
258 msg = create_stroke_msg(STR_STATUS);
259 break;
260 }
261 push_string(&msg, status.name, connection);
262 return send_stroke_msg(msg);
263 }
264
265 static int list_flags[] = {
266 LIST_PUBKEYS,
267 LIST_CERTS,
268 LIST_CACERTS,
269 LIST_OCSPCERTS,
270 LIST_AACERTS,
271 LIST_ACERTS,
272 LIST_GROUPS,
273 LIST_CAINFOS,
274 LIST_CRLS,
275 LIST_OCSP,
276 LIST_ALGS,
277 LIST_PLUGINS,
278 LIST_ALL
279 };
280
281 static int list(stroke_keyword_t kw, int utc)
282 {
283 stroke_msg_t *msg;
284
285 msg = create_stroke_msg(STR_LIST);
286 msg->list.utc = utc;
287 msg->list.flags = list_flags[kw - STROKE_LIST_FIRST];
288 return send_stroke_msg(msg);
289 }
290
291 static int reread_flags[] = {
292 REREAD_SECRETS,
293 REREAD_CACERTS,
294 REREAD_OCSPCERTS,
295 REREAD_AACERTS,
296 REREAD_ACERTS,
297 REREAD_CRLS,
298 REREAD_ALL
299 };
300
301 static int reread(stroke_keyword_t kw)
302 {
303 stroke_msg_t *msg;
304
305 msg = create_stroke_msg(STR_REREAD);
306 msg->reread.flags = reread_flags[kw - STROKE_REREAD_FIRST];
307 return send_stroke_msg(msg);
308 }
309
310 static int purge_flags[] = {
311 PURGE_OCSP,
312 PURGE_CRLS,
313 PURGE_CERTS,
314 PURGE_IKE,
315 };
316
317 static int purge(stroke_keyword_t kw)
318 {
319 stroke_msg_t *msg;
320
321 msg = create_stroke_msg(STR_PURGE);
322 msg->purge.flags = purge_flags[kw - STROKE_PURGE_FIRST];
323 return send_stroke_msg(msg);
324 }
325
326 static int export_flags[] = {
327 EXPORT_X509,
328 EXPORT_CONN_CERT,
329 EXPORT_CONN_CHAIN,
330 };
331
332 static int export(stroke_keyword_t kw, char *selector)
333 {
334 stroke_msg_t *msg;
335
336 msg = create_stroke_msg(STR_EXPORT);
337 push_string(&msg, export.selector, selector);
338 msg->export.flags = export_flags[kw - STROKE_EXPORT_FIRST];
339 return send_stroke_msg(msg);
340 }
341
342 static int leases(stroke_keyword_t kw, char *pool, char *address)
343 {
344 stroke_msg_t *msg;
345
346 msg = create_stroke_msg(STR_LEASES);
347 push_string(&msg, leases.pool, pool);
348 push_string(&msg, leases.address, address);
349 return send_stroke_msg(msg);
350 }
351
352 static int memusage()
353 {
354 stroke_msg_t *msg;
355
356 msg = create_stroke_msg(STR_MEMUSAGE);
357 return send_stroke_msg(msg);
358 }
359
360 static int user_credentials(char *name, char *user, char *pass)
361 {
362 stroke_msg_t *msg;
363
364 msg = create_stroke_msg(STR_USER_CREDS);
365 push_string(&msg, user_creds.name, name);
366 push_string(&msg, user_creds.username, user);
367 push_string(&msg, user_creds.password, pass);
368 return send_stroke_msg(msg);
369 }
370
371 static int counters(int reset, char *name)
372 {
373 stroke_msg_t *msg;
374
375 msg = create_stroke_msg(STR_COUNTERS);
376 push_string(&msg, counters.name, name);
377 msg->counters.reset = reset;
378 return send_stroke_msg(msg);
379 }
380
381 static int set_loglevel(char *type, u_int level)
382 {
383 stroke_msg_t *msg;
384
385 msg = create_stroke_msg(STR_LOGLEVEL);
386 push_string(&msg, loglevel.type, type);
387 msg->loglevel.level = level;
388 return send_stroke_msg(msg);
389 }
390
391 static int usage(char *error)
392 {
393 FILE *out = error ? stderr : stdout;
394
395 fprintf(out, "stroke [OPTIONS] command [ARGUMENTS]\n\n");
396 fprintf(out, "Options:\n");
397 fprintf(out, " -h, --help print this information.\n");
398 fprintf(out, " -d, --daemon=NAME name of the daemon.\n");
399 fprintf(out, "Commands:\n");
400 fprintf(out, " Add a connection:\n");
401 fprintf(out, " stroke add NAME MY_ID OTHER_ID MY_ADDR OTHER_ADDR\\\n");
402 fprintf(out, " MY_NET OTHER_NET\n");
403 fprintf(out, " where: ID is any IKEv2 ID \n");
404 fprintf(out, " ADDR is a IPv4 address\n");
405 fprintf(out, " NET is a IPv4 subnet in CIDR notation\n");
406 fprintf(out, " Delete a connection:\n");
407 fprintf(out, " stroke delete NAME\n");
408 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
409 fprintf(out, " Initiate a connection:\n");
410 fprintf(out, " stroke up NAME\n");
411 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
412 fprintf(out, " Initiate a connection without blocking:\n");
413 fprintf(out, " stroke up-nb NAME\n");
414 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
415 fprintf(out, " Terminate a connection:\n");
416 fprintf(out, " stroke down NAME\n");
417 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
418 fprintf(out, " Terminate a connection without blocking:\n");
419 fprintf(out, " stroke down-nb NAME\n");
420 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
421 fprintf(out, " Terminate a connection by remote srcip:\n");
422 fprintf(out, " stroke down-srcip START [END]\n");
423 fprintf(out, " where: START and optional END define the clients source IP\n");
424 fprintf(out, " Set loglevel for a logging type:\n");
425 fprintf(out, " stroke loglevel TYPE LEVEL\n");
426 fprintf(out, " where: TYPE is any|dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|esp|lib\n");
427 fprintf(out, " LEVEL is -1|0|1|2|3|4\n");
428 fprintf(out, " Show connection status:\n");
429 fprintf(out, " stroke status\n");
430 fprintf(out, " Show extended status information:\n");
431 fprintf(out, " stroke statusall\n");
432 fprintf(out, " Show extended status information without blocking:\n");
433 fprintf(out, " stroke statusall-nb\n");
434 fprintf(out, " Show list of authority and attribute certificates:\n");
435 fprintf(out, " stroke listcacerts|listocspcerts|listaacerts|listacerts\n");
436 fprintf(out, " Show list of end entity certificates, ca info records and crls:\n");
437 fprintf(out, " stroke listcerts|listcainfos|listcrls|listall\n");
438 fprintf(out, " Show list of supported algorithms:\n");
439 fprintf(out, " stroke listalgs\n");
440 fprintf(out, " Reload authority and attribute certificates:\n");
441 fprintf(out, " stroke rereadcacerts|rereadocspcerts|rereadaacerts|rereadacerts\n");
442 fprintf(out, " Reload secrets and crls:\n");
443 fprintf(out, " stroke rereadsecrets|rereadcrls|rereadall\n");
444 fprintf(out, " Purge ocsp cache entries:\n");
445 fprintf(out, " stroke purgeocsp\n");
446 fprintf(out, " Purge CRL cache entries:\n");
447 fprintf(out, " stroke purgecrls\n");
448 fprintf(out, " Purge X509 cache entries:\n");
449 fprintf(out, " stroke purgecerts\n");
450 fprintf(out, " Purge IKE_SAs without a CHILD_SA:\n");
451 fprintf(out, " stroke purgeike\n");
452 fprintf(out, " Export credentials to the console:\n");
453 fprintf(out, " stroke exportx509 DN\n");
454 fprintf(out, " stroke exportconncert connname\n");
455 fprintf(out, " stroke exportconnchain connname\n");
456 fprintf(out, " Show current memory usage:\n");
457 fprintf(out, " stroke memusage\n");
458 fprintf(out, " Show leases of a pool:\n");
459 fprintf(out, " stroke leases [POOL [ADDRESS]]\n");
460 fprintf(out, " Set username and password for a connection:\n");
461 fprintf(out, " stroke user-creds NAME USERNAME [PASSWORD]\n");
462 fprintf(out, " where: NAME is a connection name added with \"stroke add\"\n");
463 fprintf(out, " USERNAME is the username\n");
464 fprintf(out, " PASSWORD is the optional password, you'll be asked to enter it if not given\n");
465 fprintf(out, " Show IKE counters:\n");
466 fprintf(out, " stroke listcounters [connection-name]\n");
467
468 if (error)
469 {
470 fprintf(out, "\nError: %s\n", error);
471 return -1;
472 }
473 return 0;
474 }
475
476 int main(int argc, char *argv[])
477 {
478 const stroke_token_t *token;
479 char *cmd;
480 int res = 0;
481
482 library_init(NULL, "stroke");
483 atexit(library_deinit);
484
485 while (true)
486 {
487 struct option long_opts[] = {
488 {"help", no_argument, NULL, 'h' },
489 {"daemon", required_argument, NULL, 'd' },
490 {0,0,0,0},
491 };
492 switch (getopt_long(argc, argv, "hd:", long_opts, NULL))
493 {
494 case EOF:
495 break;
496 case 'h':
497 return usage(NULL);
498 case 'd':
499 daemon_name = optarg;
500 continue;
501 default:
502 return usage("invalid option");
503 }
504 break;
505 }
506
507 if (optind == argc)
508 {
509 return usage("command missing");
510 }
511
512 cmd = argv[optind++];
513 token = in_word_set(cmd, strlen(cmd));
514 if (token == NULL)
515 {
516 return usage("unknown command");
517 }
518
519 /* make argv/argc only cover positional arguments */
520 argv = &argv[optind];
521 argc = argc - optind;
522
523 switch (token->kw)
524 {
525 case STROKE_ADD:
526 if (argc < 7)
527 {
528 return usage("\"add\" needs more arguments...");
529 }
530 res = add_connection(argv[0], argv[1], argv[2], argv[3], argv[4],
531 argv[5], argv[6]);
532 break;
533 case STROKE_DELETE:
534 case STROKE_DEL:
535 if (argc < 1)
536 {
537 return usage("\"delete\" needs a connection name");
538 }
539 res = del_connection(argv[0]);
540 break;
541 case STROKE_UP_NOBLK:
542 output_verbosity = -1;
543 /* fall-through */
544 case STROKE_UP:
545 if (argc < 1)
546 {
547 return usage("\"up\" needs a connection name");
548 }
549 res = initiate_connection(argv[0]);
550 break;
551 case STROKE_DOWN_NOBLK:
552 output_verbosity = -1;
553 /* fall-through */
554 case STROKE_DOWN:
555 if (argc < 1)
556 {
557 return usage("\"down\" needs a connection name");
558 }
559 res = terminate_connection(argv[0]);
560 break;
561 case STROKE_DOWN_SRCIP:
562 if (argc < 1)
563 {
564 return usage("\"down-srcip\" needs start and optional end address");
565 }
566 res = terminate_connection_srcip(argv[0], argc > 1 ? argv[1] : NULL);
567 break;
568 case STROKE_REKEY:
569 if (argc < 1)
570 {
571 return usage("\"rekey\" needs a connection name");
572 }
573 res = rekey_connection(argv[0]);
574 break;
575 case STROKE_ROUTE:
576 if (argc < 1)
577 {
578 return usage("\"route\" needs a connection name");
579 }
580 res = route_connection(argv[0]);
581 break;
582 case STROKE_UNROUTE:
583 if (argc < 1)
584 {
585 return usage("\"unroute\" needs a connection name");
586 }
587 res = unroute_connection(argv[0]);
588 break;
589 case STROKE_LOGLEVEL:
590 if (argc < 2)
591 {
592 return usage("\"logtype\" needs more parameters...");
593 }
594 res = set_loglevel(argv[0], atoi(argv[1]));
595 break;
596 case STROKE_STATUS:
597 case STROKE_STATUSALL:
598 case STROKE_STATUSALL_NOBLK:
599 res = show_status(token->kw, argc ? argv[0] : NULL);
600 break;
601 case STROKE_LIST_PUBKEYS:
602 case STROKE_LIST_CERTS:
603 case STROKE_LIST_CACERTS:
604 case STROKE_LIST_OCSPCERTS:
605 case STROKE_LIST_AACERTS:
606 case STROKE_LIST_ACERTS:
607 case STROKE_LIST_CAINFOS:
608 case STROKE_LIST_CRLS:
609 case STROKE_LIST_OCSP:
610 case STROKE_LIST_ALGS:
611 case STROKE_LIST_PLUGINS:
612 case STROKE_LIST_ALL:
613 res = list(token->kw, argc && streq(argv[0], "--utc"));
614 break;
615 case STROKE_REREAD_SECRETS:
616 case STROKE_REREAD_CACERTS:
617 case STROKE_REREAD_OCSPCERTS:
618 case STROKE_REREAD_AACERTS:
619 case STROKE_REREAD_ACERTS:
620 case STROKE_REREAD_CRLS:
621 case STROKE_REREAD_ALL:
622 res = reread(token->kw);
623 break;
624 case STROKE_PURGE_OCSP:
625 case STROKE_PURGE_CRLS:
626 case STROKE_PURGE_CERTS:
627 case STROKE_PURGE_IKE:
628 res = purge(token->kw);
629 break;
630 case STROKE_EXPORT_X509:
631 case STROKE_EXPORT_CONN_CERT:
632 case STROKE_EXPORT_CONN_CHAIN:
633 if (argc < 1)
634 {
635 return usage("\"export\" needs a name");
636 }
637 res = export(token->kw, argv[0]);
638 break;
639 case STROKE_LEASES:
640 res = leases(token->kw, argc ? argv[0] : NULL,
641 argc > 1 ? argv[1] : NULL);
642 break;
643 case STROKE_MEMUSAGE:
644 res = memusage();
645 break;
646 case STROKE_USER_CREDS:
647 if (argc < 2)
648 {
649 return usage("\"user-creds\" needs a connection name, "
650 "username and optionally a password");
651 }
652 res = user_credentials(argv[0], argv[1], argc > 2 ? argv[2] : NULL);
653 break;
654 case STROKE_COUNTERS:
655 case STROKE_COUNTERS_RESET:
656 res = counters(token->kw == STROKE_COUNTERS_RESET,
657 argc ? argv[0] : NULL);
658 break;
659 default:
660 return usage(NULL);
661 }
662 return res;
663 }