prototype of sql pool administration utility
[strongswan.git] / src / charon / plugins / sql / pool.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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 * $Id$
16 */
17
18 #define _GNU_SOURCE
19 #include <getopt.h>
20 #include <unistd.h>
21 #include <stdio.h>
22
23 #include <debug.h>
24 #include <library.h>
25 #include <utils/host.h>
26
27 /**
28 * global database handle
29 */
30 database_t *db;
31
32 /**
33 * create a host from a blob
34 */
35 static host_t *host_create_from_blob(chunk_t blob)
36 {
37 return host_create_from_chunk(blob.len == 4 ? AF_INET : AF_INET6, blob, 0);
38 }
39
40 /**
41 * print usage info
42 */
43 static void usage()
44 {
45 printf("\
46 Usage:\n\
47 ipsec pool --status|--add|--del|--resize [options]\n\
48 \n\
49 ipsec pool --status\n\
50 Show a list of installed pools with statistics.\n\
51 \n\
52 ipsec pool --add <name> --start <start> --end <end> --timeout <timeout>\n\
53 Add a new pool to the database.\n\
54 name: Name of the pool, as used in ipsec.conf rightsourceip=%%name\n\
55 start: Start address of the pool\n\
56 end: End address of the pool\n\
57 timeout: Lease time in hours, 0 for static leases\n\
58 \n\
59 ipsec pool --del <name>\n\
60 Delete a pool from the database.\n\
61 name: Name of the pool to delete\n\
62 \n\
63 ipsec pool --resize <name> --end <end>\n\
64 Grow or shrink an existing pool.\n\
65 name: Name of the pool to resize\n\
66 end: New end address for the pool\n\
67 \n\
68 ipsec pool --leases <name> --filter <filter>\n\
69 Show lease information using filters:\n\
70 name: Name of the pool to show leases from\n\
71 filter: Filter stiring:\n\
72 \n");
73 exit(0);
74 }
75
76 /**
77 * ipsec pool --status - show pool overview
78 */
79 static void status()
80 {
81 enumerator_t *pool, *lease;
82 bool found = FALSE;
83
84 pool = db->query(db, "SELECT id, name, start, end, timeout FROM pools",
85 DB_INT, DB_TEXT, DB_BLOB, DB_BLOB, DB_UINT);
86 if (pool)
87 {
88 char *name;
89 chunk_t start_chunk, end_chunk;
90 host_t *start, *end;
91 u_int id, timeout, online = 0;
92
93 while (pool->enumerate(pool, &id, &name,
94 &start_chunk, &end_chunk, &timeout))
95 {
96 if (!found)
97 {
98 printf("%8s %15s %15s %8s %6s\n",
99 "name", "start", "end", "lease", "online");
100 found = TRUE;
101 }
102
103 start = host_create_from_blob(start_chunk);
104 end = host_create_from_blob(end_chunk);
105
106 lease = db->query(db, "SELECT COUNT(*) FROM leases "
107 "WHERE pool = ? AND release = NULL",
108 DB_UINT, id, DB_INT);
109 if (lease)
110 {
111 lease->enumerate(lease, &online);
112 lease->destroy(lease);
113 }
114
115 printf("%8s %15H %15H ", name, start, end);
116 if (timeout)
117 {
118 printf("%7dh ", timeout/3600);
119 }
120 else
121 {
122 printf("%8s ", "static");
123 }
124 printf("%6d\n", online);
125
126 DESTROY_IF(start);
127 DESTROY_IF(end);
128 }
129 pool->destroy(pool);
130 }
131 if (!found)
132 {
133 printf("no pools found.\n");
134 }
135 exit(0);
136 }
137
138 /**
139 * ipsec pool --add - add a new pool
140 */
141 static void add(char *name, host_t *start, host_t *end, int timeout)
142 {
143 if (db->execute(db, NULL,
144 "INSERT INTO pools (name, start, end, next, timeout) "
145 "VALUES (?, ?, ?, ?, ?)",
146 DB_TEXT, name, DB_BLOB, start->get_address(start),
147 DB_BLOB, end->get_address(end), DB_BLOB, start->get_address(start),
148 DB_INT, timeout*3600) != 1)
149 {
150 fprintf(stderr, "creating pool failed.\n");
151 exit(-1);
152 }
153 exit(0);
154 }
155
156 /**
157 * ipsec pool --del - delete a pool
158 */
159 static void del(char *name)
160 {
161 enumerator_t *query;
162 u_int id;
163 bool found = FALSE;
164
165 query = db->query(db, "SELECT id FROM pools WHERE name = ?",
166 DB_TEXT, name, DB_UINT);
167 if (!query)
168 {
169 fprintf(stderr, "deleting pool failed.\n");
170 exit(-1);
171 }
172 while (query->enumerate(query, &id))
173 {
174 found = TRUE;
175 if (db->execute(db, NULL,
176 "DELETE FROM pools WHERE id = ?", DB_UINT, id) != 1 ||
177 db->execute(db, NULL,
178 "DELETE FROM leases WHERE pool = ?", DB_UINT, id) < 0)
179 {
180 fprintf(stderr, "deleting pool failed.\n");
181 query->destroy(query);
182 exit(-1);
183 }
184 }
185 query->destroy(query);
186 if (!found)
187 {
188 fprintf(stderr, "pool '%s' not found.\n", name);
189 exit(-1);
190 }
191 exit(0);
192 }
193
194 /**
195 * ipsec pool --resize - resize a pool
196 */
197 static void resize(char *name, host_t *end)
198 {
199 /* TODO: check for active leases if we are decreasing pool size */
200 if (db->execute(db, NULL,
201 "UPDATE pools SET end = ? WHERE name = ?",
202 DB_BLOB, end->get_address(end), DB_TEXT, name) <= 0)
203 {
204 fprintf(stderr, "pool '%s' not found.\n", name);
205 exit(-1);
206 }
207 exit(0);
208 }
209
210 /**
211 * ipsec pool --leases - show lease information of a pool
212 */
213 static void leases(char *name, char *filter)
214 {
215 enumerator_t *query;
216 chunk_t address_chunk, identity_chunk;
217 int identity_type;
218 u_int acquire, release;
219 host_t *address;
220 identification_t *identity;
221 bool found = FALSE;
222
223 query = db->query(db, "SELECT name, address, identities.type, "
224 "identities.data, acquire, release "
225 "FROM leases JOIN pools ON leases.pool = pools.id "
226 "JOIN identities ON leases.identity = identities.id "
227 "WHERE (? or name = ?)",
228 DB_INT, name == NULL, DB_TEXT, name,
229 DB_TEXT, DB_BLOB, DB_INT, DB_BLOB, DB_UINT, DB_UINT);
230 if (!query)
231 {
232 fprintf(stderr, "querying leases failed.\n");
233 exit(-1);
234 }
235 while (query->enumerate(query, &name, &address_chunk,
236 &identity_type, &identity_chunk, &acquire, &release))
237 {
238 if (!found)
239 {
240 found = TRUE;
241 printf("%8s %15s %20s %16s %16s %7s\n",
242 "name", "address", "identity", "start", "end", "status");
243 }
244 address = host_create_from_blob(address_chunk);
245 identity = identification_create_from_encoding(identity_type, identity_chunk);
246
247 printf("%8s %15H %20D %16d %16d, %7s\n",
248 name, address, identity, acquire, release, "hum");
249 DESTROY_IF(address);
250 identity->destroy(identity);
251 }
252 query->destroy(query);
253 if (!found)
254 {
255 fprintf(stderr, "no matching leases found.\n");
256 exit(-1);
257 }
258 exit(0);
259 }
260
261 /**
262 * atexit handler to close db on shutdown
263 */
264 static void close_database(void)
265 {
266 db->destroy(db);
267 }
268
269 /**
270 * Logging hook for library logs, using stderr output
271 */
272 static void dbg_stderr(int level, char *fmt, ...)
273 {
274 va_list args;
275
276 if (level <= 1)
277 {
278 va_start(args, fmt);
279 vfprintf(stderr, fmt, args);
280 fprintf(stderr, "\n");
281 va_end(args);
282 }
283 }
284
285 int main(int argc, char *argv[])
286 {
287 char *uri, *name = "", *filter = "";
288 int timeout = 0;
289 host_t *start = NULL, *end = NULL;
290 enum {
291 OP_USAGE,
292 OP_STATUS,
293 OP_ADD,
294 OP_DEL,
295 OP_RESIZE,
296 OP_LEASES,
297 } operation = OP_USAGE;
298
299 dbg = dbg_stderr;
300 library_init(STRONGSWAN_CONF);
301 atexit(library_deinit);
302
303 lib->plugins->load(lib->plugins, IPSEC_PLUGINDIR, "libstrongswan-sqlite");
304
305 uri = lib->settings->get_str(lib->settings, "charon.plugins.sql.database", NULL);
306 if (!uri)
307 {
308 fprintf(stderr, "database URI charon.plugins.sql.database not set.\n");
309 exit(-1);
310 }
311 db = lib->db->create(lib->db, uri);
312 if (!db)
313 {
314 fprintf(stderr, "opening database failed.\n");
315 exit(-1);
316 }
317 atexit(close_database);
318
319 while (TRUE)
320 {
321 int c;
322
323 struct option long_opts[] = {
324 { "help", no_argument, NULL, 'h' },
325
326 { "status", no_argument, NULL, 'w' },
327 { "add", required_argument, NULL, 'a' },
328 { "del", required_argument, NULL, 'd' },
329 { "resize", required_argument, NULL, 'r' },
330 { "leases", optional_argument, NULL, 'l' },
331
332 { "start", required_argument, NULL, 's' },
333 { "end", required_argument, NULL, 'e' },
334 { "timeout", required_argument, NULL, 't' },
335 { "filter", required_argument, NULL, 'f' },
336 { 0,0,0,0 }
337 };
338
339 c = getopt_long(argc, argv, "", long_opts, NULL);
340 switch (c)
341 {
342 case EOF:
343 break;
344 case 'h':
345 break;
346 case 'w':
347 operation = OP_STATUS;
348 break;
349 case 'a':
350 operation = OP_ADD;
351 name = optarg;
352 continue;
353 case 'd':
354 operation = OP_DEL;
355 name = optarg;
356 continue;
357 case 'r':
358 operation = OP_RESIZE;
359 name = optarg;
360 continue;
361 case 'l':
362 operation = OP_LEASES;
363 name = optarg;
364 continue;
365 case 's':
366 start = host_create_from_string(optarg, 0);
367 if (start == NULL)
368 {
369 fprintf(stderr, "invalid start address: '%s'.\n", optarg);
370 operation = OP_USAGE;
371 break;
372 }
373 continue;
374 case 'e':
375 end = host_create_from_string(optarg, 0);
376 if (end == NULL)
377 {
378 fprintf(stderr, "invalid end address: '%s'.\n", optarg);
379 operation = OP_USAGE;
380 break;
381 }
382 continue;
383 case 't':
384 timeout = atoi(optarg);
385 if (timeout == 0 && strcmp(optarg, "0") != 0)
386 {
387 fprintf(stderr, "invalid timeout '%s'.\n", optarg);
388 operation = OP_USAGE;
389 break;
390 }
391 continue;
392 case 'f':
393 filter = optarg;
394 continue;
395 default:
396 operation = OP_USAGE;
397 break;
398 }
399 break;
400 }
401
402 switch (operation)
403 {
404 case OP_USAGE:
405 usage();
406 break;
407 case OP_STATUS:
408 status();
409 break;
410 case OP_ADD:
411 if (start == NULL || end == NULL)
412 {
413 fprintf(stderr, "missing arguments.\n");
414 usage();
415 }
416 add(name, start, end, timeout);
417 break;
418 case OP_DEL:
419 del(name);
420 break;
421 case OP_RESIZE:
422 if (end == NULL)
423 {
424 fprintf(stderr, "missing arguments.\n");
425 usage();
426 }
427 resize(name, end);
428 break;
429 case OP_LEASES:
430 leases(name, filter);
431 break;
432 }
433 exit(0);
434 }
435