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