swanctl: Include ca_id property in list-conns command
[strongswan.git] / src / swanctl / commands / list_conns.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
4 *
5 * Copyright (C) 2016-2018 Andreas Steffen
6 * HSR Hochschule fuer Technik Rapperswil
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #define _GNU_SOURCE
20 #include <stdio.h>
21 #include <errno.h>
22
23 #include "command.h"
24
25 #include <collections/hashtable.h>
26
27 /**
28 * Free hashtable with contained strings
29 */
30 static void free_hashtable(hashtable_t *hashtable)
31 {
32 enumerator_t *enumerator;
33 char *str;
34
35 enumerator = hashtable->create_enumerator(hashtable);
36 while (enumerator->enumerate(enumerator, NULL, &str))
37 {
38 free(str);
39 }
40 enumerator->destroy(enumerator);
41
42 hashtable->destroy(hashtable);
43 }
44
45 CALLBACK(values, int,
46 hashtable_t *sa, vici_res_t *res, char *name, void *value, int len)
47 {
48 chunk_t chunk;
49 char *str;
50
51 chunk = chunk_create(value, len);
52 if (chunk_printable(chunk, NULL, ' '))
53 {
54 if (asprintf(&str, "%.*s", len, value) >= 0)
55 {
56 free(sa->put(sa, name, str));
57 }
58 }
59 return 0;
60 }
61
62
63 CALLBACK(list, int,
64 hashtable_t *sa, vici_res_t *res, char *name, void *value, int len)
65 {
66 chunk_t chunk;
67 char *str;
68
69 chunk = chunk_create(value, len);
70 if (chunk_printable(chunk, NULL, ' '))
71 {
72 str = sa->get(sa, name);
73 if (asprintf(&str, "%s%s%.*s",
74 str ?: "", str ? " " : "", len, value) >= 0)
75 {
76 free(sa->put(sa, name, str));
77 }
78 }
79 return 0;
80 }
81
82 CALLBACK(children_sn, int,
83 hashtable_t *ike, vici_res_t *res, char *name)
84 {
85 hashtable_t *child;
86 char *mode, *interface, *priority;
87 char *rekey_time, *rekey_bytes, *rekey_packets, *dpd_action, *dpd_delay;
88 bool no_time, no_bytes, no_packets, no_dpd, or = FALSE;
89 int ret;
90
91 child = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1);
92 ret = vici_parse_cb(res, NULL, values, list, child);
93 if (ret == 0)
94 {
95 mode = child->get(child, "mode");
96 printf(" %s: %s, ", name, mode);
97
98 rekey_time = child->get(child, "rekey_time");
99 rekey_bytes = child->get(child, "rekey_bytes");
100 rekey_packets = child->get(child, "rekey_packets");
101 dpd_action = child->get(child, "dpd_action");
102 dpd_delay = ike->get(ike, "dpd_delay");
103
104 no_time = streq(rekey_time, "0");
105 no_bytes = streq(rekey_bytes, "0");
106 no_packets = streq(rekey_packets, "0");
107 no_dpd = streq(dpd_delay, "0");
108
109 if (strcaseeq(mode, "PASS") || strcaseeq(mode, "DROP") ||
110 (no_time && no_bytes && no_packets))
111 {
112 printf("no rekeying");
113 }
114 else
115 {
116 printf("rekeying every");
117 if (!no_time)
118 {
119 printf(" %ss", rekey_time);
120 or = TRUE;
121 }
122 if (!no_bytes)
123 {
124 printf("%s %s bytes", or ? " or" : "", rekey_bytes);
125 or = TRUE;
126 }
127 if (!no_packets)
128 {
129 printf("%s %s packets", or ? " or" : "", rekey_packets);
130 }
131 }
132 if (!no_dpd)
133 {
134 printf(", dpd action is %s", dpd_action);
135 }
136 printf("\n");
137
138 printf(" local: %s\n", child->get(child, "local-ts"));
139 printf(" remote: %s\n", child->get(child, "remote-ts"));
140
141 interface = child->get(child, "interface");
142 if (interface)
143 {
144 printf(" interface: %s\n", interface);
145 }
146
147 priority = child->get(child, "priority");
148 if (priority)
149 {
150 printf(" priority: %s\n", priority);
151 }
152 }
153 free_hashtable(child);
154 return ret;
155 }
156
157 CALLBACK(conn_sn, int,
158 hashtable_t *ike, vici_res_t *res, char *name)
159 {
160 int ret = 0;
161
162 if (streq(name, "children"))
163 {
164 return vici_parse_cb(res, children_sn, NULL, NULL, ike);
165 }
166 if (strpfx(name, "local") || strpfx(name, "remote"))
167 {
168 hashtable_t *auth;
169 char *class;
170
171 auth = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1);
172 ret = vici_parse_cb(res, NULL, values, list, auth);
173 if (ret == 0)
174 {
175 class = auth->get(auth, "class") ?: "unspecified";
176 if (strcaseeq(class, "EAP"))
177 {
178 class = auth->get(auth, "eap-type") ?: class;
179 }
180 printf(" %s %s authentication:\n",
181 strpfx(name, "local") ? "local" : "remote", class);
182 if (auth->get(auth, "id"))
183 {
184 printf(" id: %s\n", auth->get(auth, "id"));
185 }
186 if (auth->get(auth, "ca_id"))
187 {
188 printf(" ca_id: %s\n", auth->get(auth, "ca_id"));
189 }
190 if (auth->get(auth, "eap_id"))
191 {
192 printf(" eap_id: %s\n", auth->get(auth, "eap_id"));
193 }
194 if (auth->get(auth, "xauth_id"))
195 {
196 printf(" xauth_id: %s\n", auth->get(auth, "xauth_id"));
197 }
198 if (auth->get(auth, "aaa_id"))
199 {
200 printf(" aaa_id: %s\n", auth->get(auth, "aaa_id"));
201 }
202 if (auth->get(auth, "groups"))
203 {
204 printf(" groups: %s\n", auth->get(auth, "groups"));
205 }
206 if (auth->get(auth, "cert_policy"))
207 {
208 printf(" cert policy: %s\n", auth->get(auth, "cert_policy"));
209 }
210 if (auth->get(auth, "certs"))
211 {
212 printf(" certs: %s\n", auth->get(auth, "certs"));
213 }
214 if (auth->get(auth, "cacerts"))
215 {
216 printf(" cacerts: %s\n", auth->get(auth, "cacerts"));
217 }
218 }
219 free_hashtable(auth);
220 }
221 return ret;
222 }
223
224 CALLBACK(conn_list, int,
225 hashtable_t *sa, vici_res_t *res, char *name, void *value, int len)
226 {
227 if (chunk_printable(chunk_create(value, len), NULL, ' '))
228 {
229 if (streq(name, "local_addrs"))
230 {
231 printf(" local: %.*s\n", len, value);
232 }
233 if (streq(name, "remote_addrs"))
234 {
235 printf(" remote: %.*s\n", len, value);
236 }
237 }
238 return 0;
239 }
240
241 CALLBACK(conns, int,
242 void *null, vici_res_t *res, char *name)
243 {
244 int ret;
245 char *version, *reauth_time, *rekey_time, *dpd_delay, *ppk_id, *ppk_req;
246 hashtable_t *ike;
247
248 version = vici_find_str(res, "", "%s.version", name);
249 reauth_time = vici_find_str(res, "0", "%s.reauth_time", name);
250 rekey_time = vici_find_str(res, "0", "%s.rekey_time", name);
251 dpd_delay = vici_find_str(res, "0", "%s.dpd_delay", name);
252
253 ike = hashtable_create(hashtable_hash_str, hashtable_equals_str, 1);
254 free(ike->put(ike,"dpd_delay", strdup(dpd_delay)));
255
256 printf("%s: %s, ", name, version);
257 if (streq(version, "IKEv1"))
258 {
259 if (streq(reauth_time, "0"))
260 {
261 reauth_time = rekey_time;
262 }
263 }
264 if (streq(reauth_time, "0"))
265 {
266 printf("no reauthentication");
267 }
268 else
269 {
270 printf("reauthentication every %ss", reauth_time);
271 }
272 if (!streq(version, "IKEv1"))
273 {
274 if (streq(rekey_time, "0"))
275 {
276 printf(", no rekeying");
277 }
278 else
279 {
280 printf(", rekeying every %ss", rekey_time);
281 }
282 }
283 if (!streq(dpd_delay, "0"))
284 {
285 printf(", dpd delay %ss", dpd_delay);
286 }
287 printf("\n");
288
289 ppk_id = vici_find_str(res, NULL, "%s.ppk_id", name);
290 ppk_req = vici_find_str(res, NULL, "%s.ppk_required", name);
291 if (ppk_id || ppk_req)
292 {
293 printf(" ppk: %s%s%srequired\n", ppk_id ?: "", ppk_id ? ", " : "",
294 !ppk_req || !streq(ppk_req, "yes") ? "not " : "");
295 }
296
297 ret = vici_parse_cb(res, conn_sn, NULL, conn_list, ike);
298 free_hashtable(ike);
299 return ret;
300 }
301
302 CALLBACK(list_cb, void,
303 command_format_options_t *format, char *name, vici_res_t *res)
304 {
305 if (*format & COMMAND_FORMAT_RAW)
306 {
307 vici_dump(res, "list-conn event", *format & COMMAND_FORMAT_PRETTY,
308 stdout);
309 }
310 else
311 {
312 if (vici_parse_cb(res, conns, NULL, NULL, NULL) != 0)
313 {
314 fprintf(stderr, "parsing conn event failed: %s\n", strerror(errno));
315 }
316 }
317 }
318
319 static int list_conns(vici_conn_t *conn)
320 {
321 vici_req_t *req;
322 vici_res_t *res;
323 command_format_options_t format = COMMAND_FORMAT_NONE;
324 char *arg;
325 int ret;
326
327 while (TRUE)
328 {
329 switch (command_getopt(&arg))
330 {
331 case 'h':
332 return command_usage(NULL);
333 case 'P':
334 format |= COMMAND_FORMAT_PRETTY;
335 /* fall through to raw */
336 case 'r':
337 format |= COMMAND_FORMAT_RAW;
338 continue;
339 case EOF:
340 break;
341 default:
342 return command_usage("invalid --list-conns option");
343 }
344 break;
345 }
346 if (vici_register(conn, "list-conn", list_cb, &format) != 0)
347 {
348 ret = errno;
349 fprintf(stderr, "registering for connections failed: %s\n",
350 strerror(errno));
351 return ret;
352 }
353 req = vici_begin("list-conns");
354 res = vici_submit(req, conn);
355 if (!res)
356 {
357 ret = errno;
358 fprintf(stderr, "list-conns request failed: %s\n", strerror(errno));
359 return ret;
360 }
361 if (format & COMMAND_FORMAT_RAW)
362 {
363 vici_dump(res, "list-conns reply", format & COMMAND_FORMAT_PRETTY,
364 stdout);
365 }
366 vici_free_res(res);
367 return 0;
368 }
369
370 /**
371 * Register the command.
372 */
373 static void __attribute__ ((constructor))reg()
374 {
375 command_register((command_t) {
376 list_conns, 'L', "list-conns", "list loaded configurations",
377 {"[--raw|--pretty]"},
378 {
379 {"help", 'h', 0, "show usage information"},
380 {"raw", 'r', 0, "dump raw response message"},
381 {"pretty", 'P', 0, "dump raw response message in pretty print"},
382 }
383 });
384 }