stroke: Allow specifying the ipsec.secrets location in strongswan.conf
[strongswan.git] / src / libcharon / plugins / stroke / stroke_counter.c
1 /*
2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 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 #include "stroke_counter.h"
17
18 #include <threading/spinlock.h>
19 #include <collections/hashtable.h>
20
21 ENUM(stroke_counter_type_names,
22 COUNTER_INIT_IKE_SA_REKEY, COUNTER_OUT_INFORMATIONAL_RSP,
23 "ikeInitRekey",
24 "ikeRspRekey",
25 "ikeChildSaRekey",
26 "ikeInInvalid",
27 "ikeInInvalidSpi",
28 "ikeInInitReq",
29 "ikeInInitRsp",
30 "ikeOutInitReq",
31 "ikeOutInitRsp",
32 "ikeInAuthReq",
33 "ikeInAuthRsp",
34 "ikeOutAuthReq",
35 "ikeOutAuthRsp",
36 "ikeInCrChildReq",
37 "ikeInCrChildRsp",
38 "ikeOutCrChildReq",
39 "ikeOutCrChildRsp",
40 "ikeInInfoReq",
41 "ikeInInfoRsp",
42 "ikeOutInfoReq",
43 "ikeOutInfoRsp",
44 );
45
46 typedef struct private_stroke_counter_t private_stroke_counter_t;
47
48 /**
49 * Private data of an stroke_counter_t object.
50 */
51 struct private_stroke_counter_t {
52
53 /**
54 * Public stroke_counter_t interface.
55 */
56 stroke_counter_t public;
57
58 /**
59 * Global counter values
60 */
61 u_int64_t counter[COUNTER_MAX];
62
63 /**
64 * Counters for specific connection names, char* => entry_t
65 */
66 hashtable_t *conns;
67
68 /**
69 * Lock for counter values
70 */
71 spinlock_t *lock;
72 };
73
74 /**
75 * Counters for a specific connection name
76 */
77 typedef struct {
78 /** connection name */
79 char *name;
80 /** counter values for connection */
81 u_int64_t counter[COUNTER_MAX];
82 } entry_t;
83
84 /**
85 * Destroy named entry
86 */
87 static void destroy_entry(entry_t *this)
88 {
89 free(this->name);
90 free(this);
91 }
92
93 /**
94 * Hashtable hash function
95 */
96 static u_int hash(char *name)
97 {
98 return chunk_hash(chunk_from_str(name));
99 }
100
101 /**
102 * Hashtable equals function
103 */
104 static bool equals(char *a, char *b)
105 {
106 return streq(a, b);
107 }
108
109 /**
110 * Get the name of an IKE_SA, but return NULL if it is not known yet
111 */
112 static char *get_ike_sa_name(ike_sa_t *ike_sa)
113 {
114 peer_cfg_t *peer_cfg;
115
116 if (ike_sa)
117 {
118 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
119 if (peer_cfg)
120 {
121 return peer_cfg->get_name(peer_cfg);
122 }
123 }
124 return NULL;
125 }
126
127 /**
128 * Increase a counter for a named entry
129 */
130 static void count_named(private_stroke_counter_t *this,
131 ike_sa_t *ike_sa, stroke_counter_type_t type)
132 {
133 entry_t *entry;
134 char *name;
135
136 name = get_ike_sa_name(ike_sa);
137 if (name)
138 {
139 entry = this->conns->get(this->conns, name);
140 if (!entry)
141 {
142 INIT(entry,
143 .name = strdup(name),
144 );
145 this->conns->put(this->conns, entry->name, entry);
146 }
147 entry->counter[type]++;
148 }
149 }
150
151 METHOD(listener_t, alert, bool,
152 private_stroke_counter_t *this, ike_sa_t *ike_sa,
153 alert_t alert, va_list args)
154 {
155 stroke_counter_type_t type;
156
157 switch (alert)
158 {
159 case ALERT_INVALID_IKE_SPI:
160 type = COUNTER_IN_INVALID_IKE_SPI;
161 break;
162 case ALERT_PARSE_ERROR_HEADER:
163 case ALERT_PARSE_ERROR_BODY:
164 type = COUNTER_IN_INVALID;
165 break;
166 default:
167 return TRUE;
168 }
169
170 this->lock->lock(this->lock);
171 this->counter[type]++;
172 count_named(this, ike_sa, type);
173 this->lock->unlock(this->lock);
174
175 return TRUE;
176 }
177
178 METHOD(listener_t, ike_rekey, bool,
179 private_stroke_counter_t *this, ike_sa_t *old, ike_sa_t *new)
180 {
181 stroke_counter_type_t type;
182 ike_sa_id_t *id;
183
184 id = new->get_id(new);
185 if (id->is_initiator(id))
186 {
187 type = COUNTER_INIT_IKE_SA_REKEY;
188 }
189 else
190 {
191 type = COUNTER_RESP_IKE_SA_REKEY;
192 }
193
194 this->lock->lock(this->lock);
195 this->counter[type]++;
196 count_named(this, old, type);
197 this->lock->unlock(this->lock);
198
199 return TRUE;
200 }
201
202 METHOD(listener_t, child_rekey, bool,
203 private_stroke_counter_t *this, ike_sa_t *ike_sa,
204 child_sa_t *old, child_sa_t *new)
205 {
206 this->lock->lock(this->lock);
207 this->counter[COUNTER_CHILD_SA_REKEY]++;
208 count_named(this, ike_sa, COUNTER_CHILD_SA_REKEY);
209 this->lock->unlock(this->lock);
210
211 return TRUE;
212 }
213
214 METHOD(listener_t, message_hook, bool,
215 private_stroke_counter_t *this, ike_sa_t *ike_sa, message_t *message,
216 bool incoming, bool plain)
217 {
218 stroke_counter_type_t type;
219 bool request;
220
221 if ((incoming && !plain) || (!incoming && !plain))
222 { /* handle each message only once */
223 return TRUE;
224 }
225
226 request = message->get_request(message);
227 switch (message->get_exchange_type(message))
228 {
229 case IKE_SA_INIT:
230 if (incoming)
231 {
232 type = request ? COUNTER_IN_IKE_SA_INIT_REQ
233 : COUNTER_IN_IKE_SA_INIT_RSP;
234 }
235 else
236 {
237 type = request ? COUNTER_OUT_IKE_SA_INIT_REQ
238 : COUNTER_OUT_IKE_SA_INIT_RES;
239 }
240 break;
241 case IKE_AUTH:
242 if (incoming)
243 {
244 type = request ? COUNTER_IN_IKE_AUTH_REQ
245 : COUNTER_IN_IKE_AUTH_RSP;
246 }
247 else
248 {
249 type = request ? COUNTER_OUT_IKE_AUTH_REQ
250 : COUNTER_OUT_IKE_AUTH_RSP;
251 }
252 break;
253 case CREATE_CHILD_SA:
254 if (incoming)
255 {
256 type = request ? COUNTER_IN_CREATE_CHILD_SA_REQ
257 : COUNTER_IN_CREATE_CHILD_SA_RSP;
258 }
259 else
260 {
261 type = request ? COUNTER_OUT_CREATE_CHILD_SA_REQ
262 : COUNTER_OUT_CREATE_CHILD_SA_RSP;
263 }
264 break;
265 case INFORMATIONAL:
266 if (incoming)
267 {
268 type = request ? COUNTER_IN_INFORMATIONAL_REQ
269 : COUNTER_IN_INFORMATIONAL_RSP;
270 }
271 else
272 {
273 type = request ? COUNTER_OUT_INFORMATIONAL_REQ
274 : COUNTER_OUT_INFORMATIONAL_RSP;
275 }
276 break;
277 default:
278 return TRUE;
279 }
280
281 this->lock->lock(this->lock);
282 this->counter[type]++;
283 count_named(this, ike_sa, type);
284 this->lock->unlock(this->lock);
285
286 return TRUE;
287 }
288
289 /**
290 * Print a single counter value to out
291 */
292 static void print_counter(FILE *out, stroke_counter_type_t type,
293 u_int64_t counter)
294 {
295 fprintf(out, "%-18N %12llu\n", stroke_counter_type_names, type, counter);
296 }
297
298 /**
299 * Print IKE counters for a specific connection
300 */
301 static void print_one(private_stroke_counter_t *this, FILE *out, char *name)
302 {
303 u_int64_t counter[COUNTER_MAX];
304 entry_t *entry;
305 int i;
306
307 this->lock->lock(this->lock);
308 entry = this->conns->get(this->conns, name);
309 if (entry)
310 {
311 for (i = 0; i < countof(this->counter); i++)
312 {
313 counter[i] = entry->counter[i];
314 }
315 }
316 this->lock->unlock(this->lock);
317
318 if (entry)
319 {
320 fprintf(out, "\nList of IKE counters for '%s':\n\n", name);
321 for (i = 0; i < countof(this->counter); i++)
322 {
323 print_counter(out, i, counter[i]);
324 }
325 }
326 else
327 {
328 fprintf(out, "No IKE counters found for '%s'\n", name);
329 }
330 }
331
332 /**
333 * Print counters for all connections
334 */
335 static void print_all(private_stroke_counter_t *this, FILE *out)
336 {
337 enumerator_t *enumerator;
338 entry_t *entry;
339 linked_list_t *list;
340 char *name;
341
342 list = linked_list_create();
343
344 this->lock->lock(this->lock);
345 enumerator = this->conns->create_enumerator(this->conns);
346 while (enumerator->enumerate(enumerator, &name, &entry))
347 {
348 list->insert_last(list, strdup(name));
349 }
350 enumerator->destroy(enumerator);
351 this->lock->unlock(this->lock);
352
353 enumerator = list->create_enumerator(list);
354 while (enumerator->enumerate(enumerator, &name))
355 {
356 print_one(this, out, name);
357 }
358 enumerator->destroy(enumerator);
359
360 list->destroy_function(list, free);
361 }
362
363 /**
364 * Print global counters
365 */
366 static void print_global(private_stroke_counter_t *this, FILE *out)
367 {
368 u_int64_t counter[COUNTER_MAX];
369 int i;
370
371 this->lock->lock(this->lock);
372 for (i = 0; i < countof(this->counter); i++)
373 {
374 counter[i] = this->counter[i];
375 }
376 this->lock->unlock(this->lock);
377
378 fprintf(out, "\nList of IKE counters:\n\n");
379
380 for (i = 0; i < countof(this->counter); i++)
381 {
382 print_counter(out, i, counter[i]);
383 }
384 }
385
386 METHOD(stroke_counter_t, print, void,
387 private_stroke_counter_t *this, FILE *out, char *name)
388 {
389 if (name)
390 {
391 if (streq(name, "all"))
392 {
393 return print_all(this, out);
394 }
395 return print_one(this, out, name);
396 }
397 return print_global(this, out);
398 }
399
400 METHOD(stroke_counter_t, reset, void,
401 private_stroke_counter_t *this, char *name)
402 {
403 this->lock->lock(this->lock);
404 if (name)
405 {
406 entry_t *entry;
407
408 entry = this->conns->remove(this->conns, name);
409 if (entry)
410 {
411 destroy_entry(entry);
412 }
413 }
414 else
415 {
416 memset(&this->counter, 0, sizeof(this->counter));
417 }
418 this->lock->unlock(this->lock);
419 }
420
421 METHOD(stroke_counter_t, destroy, void,
422 private_stroke_counter_t *this)
423 {
424 enumerator_t *enumerator;
425 char *name;
426 entry_t *entry;
427
428 enumerator = this->conns->create_enumerator(this->conns);
429 while (enumerator->enumerate(enumerator, &name, &entry))
430 {
431 destroy_entry(entry);
432 }
433 enumerator->destroy(enumerator);
434 this->conns->destroy(this->conns);
435 this->lock->destroy(this->lock);
436 free(this);
437 }
438
439 /**
440 * See header
441 */
442 stroke_counter_t *stroke_counter_create()
443 {
444 private_stroke_counter_t *this;
445
446 INIT(this,
447 .public = {
448 .listener = {
449 .alert = _alert,
450 .ike_rekey = _ike_rekey,
451 .child_rekey = _child_rekey,
452 .message = _message_hook,
453 },
454 .print = _print,
455 .reset = _reset,
456 .destroy = _destroy,
457 },
458 .conns = hashtable_create((hashtable_hash_t)hash,
459 (hashtable_equals_t)equals, 4),
460 .lock = spinlock_create(),
461 );
462
463 return &this->public;
464 }