2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
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>.
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
17 * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
19 * Permission is hereby granted, free of charge, to any person obtaining a copy
20 * of this software and associated documentation files (the "Software"), to deal
21 * in the Software without restriction, including without limitation the rights
22 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 * copies of the Software, and to permit persons to whom the Software is
24 * furnished to do so, subject to the following conditions:
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 #include <collections/hashtable.h>
47 * Free hashtable with contained strings
49 static void free_hashtable(hashtable_t
*hashtable
)
51 enumerator_t
*enumerator
;
54 enumerator
= hashtable
->create_enumerator(hashtable
);
55 while (enumerator
->enumerate(enumerator
, NULL
, &str
))
59 enumerator
->destroy(enumerator
);
61 hashtable
->destroy(hashtable
);
64 CALLBACK(sa_values
, int,
65 hashtable_t
*sa
, vici_res_t
*res
, char *name
, void *value
, int len
)
70 chunk
= chunk_create(value
, len
);
71 if (chunk_printable(chunk
, NULL
, ' '))
73 if (asprintf(&str
, "%.*s", len
, value
) >= 0)
75 free(sa
->put(sa
, name
, str
));
82 CALLBACK(sa_list
, int,
83 hashtable_t
*sa
, vici_res_t
*res
, char *name
, void *value
, int len
)
88 chunk
= chunk_create(value
, len
);
89 if (chunk_printable(chunk
, NULL
, ' '))
91 str
= sa
->get(sa
, name
);
92 if (asprintf(&str
, "%s%s%.*s",
93 str ?
: "", str ?
" " : "", len
, value
) >= 0)
95 free(sa
->put(sa
, name
, str
));
101 CALLBACK(child_sas
, int,
102 hashtable_t
*ike
, vici_res_t
*res
, char *name
)
107 child
= hashtable_create(hashtable_hash_str
, hashtable_equals_str
, 1);
108 ret
= vici_parse_cb(res
, NULL
, sa_values
, sa_list
, child
);
111 printf(" %s: #%s, reqid %s, %s, %s%s, %s:",
112 name
, child
->get(child
, "uniqueid"), child
->get(child
, "reqid"),
113 child
->get(child
, "state"), child
->get(child
, "mode"),
114 child
->get(child
, "encap") ?
"-in-UDP" : "",
115 child
->get(child
, "protocol"));
117 if (child
->get(child
, "encr-alg"))
119 printf("%s", child
->get(child
, "encr-alg"));
120 if (child
->get(child
, "encr-keysize"))
122 printf("-%s", child
->get(child
, "encr-keysize"));
125 if (child
->get(child
, "integ-alg"))
127 if (child
->get(child
, "encr-alg"))
131 printf("%s", child
->get(child
, "integ-alg"));
132 if (child
->get(child
, "integ-keysize"))
134 printf("-%s", child
->get(child
, "integ-keysize"));
137 if (child
->get(child
, "prf-alg"))
139 printf("/%s", child
->get(child
, "prf-alg"));
141 if (child
->get(child
, "dh-group"))
143 printf("/%s", child
->get(child
, "dh-group"));
145 if (child
->get(child
, "esn"))
151 printf(" installed %ss ago", child
->get(child
, "install-time"));
152 if (child
->get(child
, "rekey-time"))
154 printf(", rekeying in %ss", child
->get(child
, "rekey-time"));
156 if (child
->get(child
, "life-time"))
158 printf(", expires in %ss", child
->get(child
, "life-time"));
162 printf(" in %s%s%s", child
->get(child
, "spi-in"),
163 child
->get(child
, "cpi-in") ?
"/" : "",
164 child
->get(child
, "cpi-in") ?
: "");
165 printf(", %6s bytes, %5s packets",
166 child
->get(child
, "bytes-in"), child
->get(child
, "packets-in"));
167 if (child
->get(child
, "use-in"))
169 printf(", %5ss ago", child
->get(child
, "use-in"));
173 printf(" out %s%s%s", child
->get(child
, "spi-out"),
174 child
->get(child
, "cpi-out") ?
"/" : "",
175 child
->get(child
, "cpi-out") ?
: "");
176 printf(", %6s bytes, %5s packets",
177 child
->get(child
, "bytes-out"), child
->get(child
, "packets-out"));
178 if (child
->get(child
, "use-out"))
180 printf(", %5ss ago", child
->get(child
, "use-out"));
184 printf(" local %s\n", child
->get(child
, "local-ts"));
185 printf(" remote %s\n", child
->get(child
, "remote-ts"));
187 free_hashtable(child
);
191 CALLBACK(ike_sa
, int,
192 hashtable_t
*ike
, vici_res_t
*res
, char *name
)
194 if (streq(name
, "child-sas"))
196 printf("%s: #%s, %s, IKEv%s, %s:%s\n",
197 ike
->get(ike
, "name"), ike
->get(ike
, "uniqueid"),
198 ike
->get(ike
, "state"), ike
->get(ike
, "version"),
199 ike
->get(ike
, "initiator-spi"), ike
->get(ike
, "responder-spi"));
201 printf(" local '%s' @ %s\n",
202 ike
->get(ike
, "local-id"), ike
->get(ike
, "local-host"));
203 printf(" remote '%s' @ %s",
204 ike
->get(ike
, "remote-id"), ike
->get(ike
, "remote-host"));
205 if (ike
->get(ike
, "remote-eap-id"))
207 printf(" EAP: '%s'", ike
->get(ike
, "remote-eap-id"));
209 if (ike
->get(ike
, "remote-xauth-id"))
211 printf(" XAuth: '%s'", ike
->get(ike
, "remote-xauth-id"));
215 if (ike
->get(ike
, "encr-alg"))
217 printf(" %s", ike
->get(ike
, "encr-alg"));
218 if (ike
->get(ike
, "encr-keysize"))
220 printf("-%s", ike
->get(ike
, "encr-keysize"));
222 if (ike
->get(ike
, "integ-alg"))
224 printf("/%s", ike
->get(ike
, "integ-alg"));
226 if (ike
->get(ike
, "integ-keysize"))
228 printf("-%s", ike
->get(ike
, "integ-keysize"));
230 printf("/%s", ike
->get(ike
, "prf-alg"));
231 printf("/%s", ike
->get(ike
, "dh-group"));
235 if (ike
->get(ike
, "established"))
237 printf(" established %ss ago", ike
->get(ike
, "established"));
238 if (ike
->get(ike
, "rekey-time"))
240 printf(", rekeying in %ss", ike
->get(ike
, "rekey-time"));
242 if (ike
->get(ike
, "reauth-time"))
244 printf(", reauth in %ss", ike
->get(ike
, "reauth-time"));
246 if (ike
->get(ike
, "life-time"))
248 printf(", expires in %ss", ike
->get(ike
, "life-time"));
253 if (ike
->get(ike
, "tasks-queued"))
255 printf(" queued: %s\n", ike
->get(ike
, "tasks-queued"));
257 if (ike
->get(ike
, "tasks-active"))
259 printf(" active: %s\n", ike
->get(ike
, "tasks-active"));
261 if (ike
->get(ike
, "tasks-passive"))
263 printf(" passive: %s\n", ike
->get(ike
, "tasks-passive"));
266 return vici_parse_cb(res
, child_sas
, NULL
, NULL
, ike
);
271 CALLBACK(ike_sas
, int,
272 void *null
, vici_res_t
*res
, char *name
)
277 ike
= hashtable_create(hashtable_hash_str
, hashtable_equals_str
, 1);
278 ike
->put(ike
, "name", strdup(name
));
279 ret
= vici_parse_cb(res
, ike_sa
, sa_values
, sa_list
, ike
);
284 CALLBACK(list_cb
, void,
285 command_format_options_t
*format
, char *name
, vici_res_t
*res
)
289 if (*format
& COMMAND_FORMAT_RAW
)
291 snprintf(buf
, sizeof(buf
), "%s event", name
);
292 vici_dump(res
, buf
, *format
& COMMAND_FORMAT_PRETTY
,
297 if (vici_parse_cb(res
, ike_sas
, NULL
, NULL
, NULL
) != 0)
299 fprintf(stderr
, "parsing SA event failed: %s\n", strerror(errno
));
304 static int list_sas(vici_conn_t
*conn
)
308 bool noblock
= FALSE
;
309 command_format_options_t format
= COMMAND_FORMAT_NONE
;
310 char *arg
, *ike
= NULL
;
315 switch (command_getopt(&arg
))
318 return command_usage(NULL
);
329 format
|= COMMAND_FORMAT_PRETTY
;
330 /* fall through to raw */
332 format
|= COMMAND_FORMAT_RAW
;
337 return command_usage("invalid --list-sas option");
341 if (vici_register(conn
, "list-sa", list_cb
, &format
) != 0)
344 fprintf(stderr
, "registering for SAs failed: %s\n", strerror(errno
));
347 req
= vici_begin("list-sas");
350 vici_add_key_valuef(req
, "ike", "%s", ike
);
354 vici_add_key_valuef(req
, "ike-id", "%d", ike_id
);
358 vici_add_key_valuef(req
, "noblock", "yes");
360 res
= vici_submit(req
, conn
);
364 fprintf(stderr
, "list-sas request failed: %s\n", strerror(errno
));
367 if (format
& COMMAND_FORMAT_RAW
)
369 vici_dump(res
, "list-sas reply", format
& COMMAND_FORMAT_PRETTY
,
376 static int monitor_sas(vici_conn_t
*conn
)
378 command_format_options_t format
= COMMAND_FORMAT_NONE
;
383 switch (command_getopt(&arg
))
386 return command_usage(NULL
);
388 format
|= COMMAND_FORMAT_PRETTY
;
389 /* fall through to raw */
391 format
|= COMMAND_FORMAT_RAW
;
396 return command_usage("invalid --monitor-sa option");
400 if (vici_register(conn
, "ike-updown", list_cb
, &format
) != 0)
402 fprintf(stderr
, "registering for IKE_SAs failed: %s\n",
406 if (vici_register(conn
, "child-updown", list_cb
, &format
) != 0)
408 fprintf(stderr
, "registering for CHILD_SAs failed: %s\n",
415 fprintf(stderr
, "disconnecting...\n");
421 * Register the command.
423 static void __attribute__ ((constructor
))reg()
425 command_register((command_t
) {
426 list_sas
, 'l', "list-sas", "list currently active IKE_SAs",
427 {"[--raw|--pretty]"},
429 {"help", 'h', 0, "show usage information"},
430 {"ike", 'i', 1, "filter IKE_SAs by name"},
431 {"ike-id", 'I', 1, "filter IKE_SAs by unique identifier"},
432 {"noblock", 'n', 0, "don't wait for IKE_SAs in use"},
433 {"raw", 'r', 0, "dump raw response message"},
434 {"pretty", 'P', 0, "dump raw response message in pretty print"},
439 static void __attribute__ ((constructor
))reg_monitor_sa()
441 command_register((command_t
) {
442 monitor_sas
, 'm', "monitor-sa", "monitor for IKE_SA and CHILD_SA changes",
443 {"[--raw|--pretty]"},
445 {"help", 'h', 0, "show usage information"},
446 {"raw", 'r', 0, "dump raw response message"},
447 {"pretty", 'P', 0, "dump raw response message in pretty print"},