Return to pool.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / pool |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2011-2017 Tobias Brunner ! 3: * Copyright (C) 2008 Martin Willi ! 4: * HSR Hochschule fuer Technik Rapperswil ! 5: * ! 6: * This program is free software; you can redistribute it and/or modify it ! 7: * under the terms of the GNU General Public License as published by the ! 8: * Free Software Foundation; either version 2 of the License, or (at your ! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. ! 10: * ! 11: * This program is distributed in the hope that it will be useful, but ! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ! 14: * for more details. ! 15: */ ! 16: ! 17: #define _GNU_SOURCE ! 18: #include <getopt.h> ! 19: #include <unistd.h> ! 20: #include <stdio.h> ! 21: #include <time.h> ! 22: #include <string.h> ! 23: #include <errno.h> ! 24: ! 25: #include <utils/debug.h> ! 26: #include <library.h> ! 27: #include <collections/array.h> ! 28: #include <networking/host.h> ! 29: #include <utils/identification.h> ! 30: #include <attributes/attributes.h> ! 31: ! 32: #include "pool_attributes.h" ! 33: #include "pool_usage.h" ! 34: ! 35: /** ! 36: * global database handle ! 37: */ ! 38: database_t *db; ! 39: ! 40: /** ! 41: * --start/--end addresses of various subcommands ! 42: */ ! 43: host_t *start_addr = NULL, *end_addr = NULL; ! 44: ! 45: /** ! 46: * whether --add should --replace an existing pool ! 47: */ ! 48: bool replace_pool = FALSE; ! 49: ! 50: /** ! 51: * forward declarations ! 52: */ ! 53: static void del(char *name); ! 54: static void do_args(int argc, char *argv[]); ! 55: ! 56: /** ! 57: * Create or replace a pool by name ! 58: */ ! 59: static u_int create_pool(char *name, chunk_t start, chunk_t end, u_int timeout) ! 60: { ! 61: enumerator_t *e; ! 62: int pool; ! 63: bool exists; ! 64: ! 65: e = db->query(db, "SELECT id FROM pools WHERE name = ?", ! 66: DB_TEXT, name, DB_UINT); ! 67: exists = e && e->enumerate(e, &pool); ! 68: DESTROY_IF(e); ! 69: ! 70: if (exists) ! 71: { ! 72: if (!replace_pool) ! 73: { ! 74: fprintf(stderr, "pool '%s' exists.\n", name); ! 75: exit(EXIT_FAILURE); ! 76: } ! 77: del(name); ! 78: } ! 79: if (db->execute(db, &pool, ! 80: "INSERT INTO pools (name, start, end, timeout) VALUES (?, ?, ?, ?)", ! 81: DB_TEXT, name, DB_BLOB, start, DB_BLOB, end, ! 82: DB_UINT, timeout) != 1) ! 83: { ! 84: fprintf(stderr, "creating pool failed.\n"); ! 85: exit(EXIT_FAILURE); ! 86: } ! 87: ! 88: return pool; ! 89: } ! 90: ! 91: /** ! 92: * instead of a pool handle a DNS or NBNS attribute ! 93: */ ! 94: static bool is_attribute(char *name) ! 95: { ! 96: return strcaseeq(name, "dns") || strcaseeq(name, "nbns") || ! 97: strcaseeq(name, "wins"); ! 98: } ! 99: ! 100: /** ! 101: * calculate the size of a pool using start and end address chunk ! 102: */ ! 103: static u_int get_pool_size(chunk_t start, chunk_t end) ! 104: { ! 105: u_int *start_ptr, *end_ptr; ! 106: ! 107: if (start.len < sizeof(u_int) || end.len < sizeof(u_int)) ! 108: { ! 109: return 0; ! 110: } ! 111: start_ptr = (u_int*)(start.ptr + start.len - sizeof(u_int)); ! 112: end_ptr = (u_int*)(end.ptr + end.len - sizeof(u_int)); ! 113: return ntohl(*end_ptr) - ntohl(*start_ptr) + 1; ! 114: } ! 115: ! 116: /** ! 117: * ipsec pool --status - show pool overview ! 118: */ ! 119: static void status(void) ! 120: { ! 121: enumerator_t *ns, *pool, *lease; ! 122: host_t *server; ! 123: chunk_t value; ! 124: bool found = FALSE; ! 125: ! 126: /* enumerate IPv4 DNS servers */ ! 127: ns = db->query(db, "SELECT value FROM attributes WHERE type = ?", ! 128: DB_INT, INTERNAL_IP4_DNS, DB_BLOB); ! 129: if (ns) ! 130: { ! 131: while (ns->enumerate(ns, &value)) ! 132: { ! 133: if (!found) ! 134: { ! 135: printf("dns servers:"); ! 136: found = TRUE; ! 137: } ! 138: server = host_create_from_chunk(AF_INET, value, 0); ! 139: if (server) ! 140: { ! 141: printf(" %H", server); ! 142: server->destroy(server); ! 143: } ! 144: } ! 145: ns->destroy(ns); ! 146: } ! 147: ! 148: /* enumerate IPv6 DNS servers */ ! 149: ns = db->query(db, "SELECT value FROM attributes WHERE type = ?", ! 150: DB_INT, INTERNAL_IP6_DNS, DB_BLOB); ! 151: if (ns) ! 152: { ! 153: while (ns->enumerate(ns, &value)) ! 154: { ! 155: if (!found) ! 156: { ! 157: printf("dns servers:"); ! 158: found = TRUE; ! 159: } ! 160: server = host_create_from_chunk(AF_INET6, value, 0); ! 161: if (server) ! 162: { ! 163: printf(" %H", server); ! 164: server->destroy(server); ! 165: } ! 166: } ! 167: ns->destroy(ns); ! 168: } ! 169: if (found) ! 170: { ! 171: printf("\n"); ! 172: } ! 173: else ! 174: { ! 175: printf("no dns servers found.\n"); ! 176: } ! 177: found = FALSE; ! 178: ! 179: /* enumerate IPv4 NBNS servers */ ! 180: ns = db->query(db, "SELECT value FROM attributes WHERE type = ?", ! 181: DB_INT, INTERNAL_IP4_NBNS, DB_BLOB); ! 182: if (ns) ! 183: { ! 184: while (ns->enumerate(ns, &value)) ! 185: { ! 186: if (!found) ! 187: { ! 188: printf("nbns servers:"); ! 189: found = TRUE; ! 190: } ! 191: server = host_create_from_chunk(AF_INET, value, 0); ! 192: if (server) ! 193: { ! 194: printf(" %H", server); ! 195: server->destroy(server); ! 196: } ! 197: } ! 198: ns->destroy(ns); ! 199: } ! 200: ! 201: /* enumerate IPv6 NBNS servers */ ! 202: ns = db->query(db, "SELECT value FROM attributes WHERE type = ?", ! 203: DB_INT, INTERNAL_IP6_NBNS, DB_BLOB); ! 204: if (ns) ! 205: { ! 206: while (ns->enumerate(ns, &value)) ! 207: { ! 208: if (!found) ! 209: { ! 210: printf("nbns servers:"); ! 211: found = TRUE; ! 212: } ! 213: server = host_create_from_chunk(AF_INET6, value, 0); ! 214: if (server) ! 215: { ! 216: printf(" %H", server); ! 217: server->destroy(server); ! 218: } ! 219: } ! 220: ns->destroy(ns); ! 221: } ! 222: if (found) ! 223: { ! 224: printf("\n"); ! 225: } ! 226: else ! 227: { ! 228: printf("no nbns servers found.\n"); ! 229: } ! 230: found = FALSE; ! 231: ! 232: pool = db->query(db, "SELECT id, name, start, end, timeout FROM pools", ! 233: DB_INT, DB_TEXT, DB_BLOB, DB_BLOB, DB_UINT); ! 234: if (pool) ! 235: { ! 236: char *name; ! 237: chunk_t start_chunk, end_chunk; ! 238: host_t *start, *end; ! 239: u_int id, timeout, online = 0, used = 0, size = 0; ! 240: ! 241: while (pool->enumerate(pool, &id, &name, ! 242: &start_chunk, &end_chunk, &timeout)) ! 243: { ! 244: if (!found) ! 245: { ! 246: printf("%8s %15s %15s %8s %6s %11s %11s\n", "name", "start", ! 247: "end", "timeout", "size", "online", "usage"); ! 248: found = TRUE; ! 249: } ! 250: ! 251: start = host_create_from_chunk(AF_UNSPEC, start_chunk, 0); ! 252: end = host_create_from_chunk(AF_UNSPEC, end_chunk, 0); ! 253: if (start->is_anyaddr(start) && end->is_anyaddr(end)) ! 254: { ! 255: printf("%8s %15s %15s ", name, "n/a", "n/a"); ! 256: } ! 257: else ! 258: { ! 259: printf("%8s %15H %15H ", name, start, end); ! 260: } ! 261: if (timeout) ! 262: { ! 263: if (timeout >= 60 * 300) ! 264: { ! 265: printf("%7dh ", timeout/3600); ! 266: } ! 267: else if (timeout >= 300) ! 268: { ! 269: printf("%7dm ", timeout/60); ! 270: } ! 271: else ! 272: { ! 273: printf("%7ds ", timeout); ! 274: } ! 275: } ! 276: else ! 277: { ! 278: printf("%8s ", "static"); ! 279: } ! 280: /* get total number of hosts in the pool */ ! 281: lease = db->query(db, "SELECT COUNT(*) FROM addresses " ! 282: "WHERE pool = ?", DB_UINT, id, DB_INT); ! 283: if (lease) ! 284: { ! 285: lease->enumerate(lease, &size); ! 286: lease->destroy(lease); ! 287: } ! 288: if (!size) ! 289: { /* empty pool */ ! 290: printf("%6d %11s %11s ", 0, "n/a", "n/a"); ! 291: goto next_pool; ! 292: } ! 293: printf("%6d ", size); ! 294: /* get number of online hosts */ ! 295: lease = db->query(db, "SELECT COUNT(*) FROM addresses " ! 296: "WHERE pool = ? AND released = 0", ! 297: DB_UINT, id, DB_INT); ! 298: if (lease) ! 299: { ! 300: lease->enumerate(lease, &online); ! 301: lease->destroy(lease); ! 302: } ! 303: printf("%5d (%2d%%) ", online, online*100/size); ! 304: /* get number of online or valid leases */ ! 305: lease = db->query(db, "SELECT COUNT(*) FROM addresses " ! 306: "WHERE addresses.pool = ? " ! 307: "AND ((? AND acquired != 0) " ! 308: " OR released = 0 OR released > ?) ", ! 309: DB_UINT, id, DB_UINT, !timeout, ! 310: DB_UINT, time(NULL) - timeout, DB_UINT); ! 311: if (lease) ! 312: { ! 313: lease->enumerate(lease, &used); ! 314: lease->destroy(lease); ! 315: } ! 316: printf("%5d (%2d%%) ", used, used*100/size); ! 317: ! 318: next_pool: ! 319: printf("\n"); ! 320: DESTROY_IF(start); ! 321: DESTROY_IF(end); ! 322: } ! 323: pool->destroy(pool); ! 324: } ! 325: if (!found) ! 326: { ! 327: printf("no pools found.\n"); ! 328: } ! 329: } ! 330: ! 331: /** ! 332: * ipsec pool --add - add a new pool ! 333: */ ! 334: static void add(char *name, host_t *start, host_t *end, u_int timeout) ! 335: { ! 336: chunk_t start_chunk, end_chunk, cur_addr; ! 337: u_int id, count; ! 338: ! 339: start_chunk = start->get_address(start); ! 340: end_chunk = end->get_address(end); ! 341: cur_addr = chunk_clonea(start_chunk); ! 342: count = get_pool_size(start_chunk, end_chunk); ! 343: ! 344: if (start_chunk.len != end_chunk.len || ! 345: memcmp(start_chunk.ptr, end_chunk.ptr, start_chunk.len) > 0) ! 346: { ! 347: fprintf(stderr, "invalid start/end pair specified.\n"); ! 348: exit(EXIT_FAILURE); ! 349: } ! 350: id = create_pool(name, start_chunk, end_chunk, timeout); ! 351: printf("allocating %d addresses... ", count); ! 352: fflush(stdout); ! 353: db->transaction(db, FALSE); ! 354: while (TRUE) ! 355: { ! 356: db->execute(db, NULL, ! 357: "INSERT INTO addresses (pool, address, identity, acquired, released) " ! 358: "VALUES (?, ?, ?, ?, ?)", ! 359: DB_UINT, id, DB_BLOB, cur_addr, DB_UINT, 0, DB_UINT, 0, DB_UINT, 1); ! 360: if (chunk_equals(cur_addr, end_chunk)) ! 361: { ! 362: break; ! 363: } ! 364: chunk_increment(cur_addr); ! 365: } ! 366: db->commit(db); ! 367: printf("done.\n"); ! 368: } ! 369: ! 370: static bool add_address(u_int pool_id, char *address_str, int *family) ! 371: { ! 372: host_t *address; ! 373: int user_id = 0; ! 374: ! 375: char *pos_eq = strchr(address_str, '='); ! 376: if (pos_eq != NULL) ! 377: { ! 378: identification_t *id = identification_create_from_string(pos_eq + 1); ! 379: user_id = get_identity(id); ! 380: id->destroy(id); ! 381: ! 382: if (user_id == 0) ! 383: { ! 384: return FALSE; ! 385: } ! 386: *pos_eq = '\0'; ! 387: } ! 388: ! 389: address = host_create_from_string(address_str, 0); ! 390: if (address == NULL) ! 391: { ! 392: fprintf(stderr, "invalid address '%s'.\n", address_str); ! 393: return FALSE; ! 394: } ! 395: if (family && *family != AF_UNSPEC && ! 396: *family != address->get_family(address)) ! 397: { ! 398: fprintf(stderr, "invalid address family '%s'.\n", address_str); ! 399: address->destroy(address); ! 400: return FALSE; ! 401: } ! 402: ! 403: if (db->execute(db, NULL, ! 404: "INSERT INTO addresses " ! 405: "(pool, address, identity, acquired, released) " ! 406: "VALUES (?, ?, ?, ?, ?)", ! 407: DB_UINT, pool_id, DB_BLOB, address->get_address(address), ! 408: DB_UINT, user_id, DB_UINT, 0, DB_UINT, 1) != 1) ! 409: { ! 410: fprintf(stderr, "inserting address '%s' failed.\n", address_str); ! 411: address->destroy(address); ! 412: return FALSE; ! 413: } ! 414: if (family) ! 415: { ! 416: *family = address->get_family(address); ! 417: } ! 418: address->destroy(address); ! 419: ! 420: return TRUE; ! 421: } ! 422: ! 423: static void add_addresses(char *pool, char *path, u_int timeout) ! 424: { ! 425: u_int pool_id, count = 0; ! 426: int family = AF_UNSPEC; ! 427: char address_str[512]; ! 428: host_t *addr; ! 429: FILE *file; ! 430: ! 431: db->transaction(db, FALSE); ! 432: ! 433: addr = host_create_from_string("%any", 0); ! 434: pool_id = create_pool(pool, addr->get_address(addr), ! 435: addr->get_address(addr), timeout); ! 436: addr->destroy(addr); ! 437: ! 438: file = (strcmp(path, "-") == 0 ? stdin : fopen(path, "r")); ! 439: if (file == NULL) ! 440: { ! 441: fprintf(stderr, "opening '%s' failed: %s\n", path, strerror(errno)); ! 442: exit(-1); ! 443: } ! 444: ! 445: printf("starting allocation... "); ! 446: fflush(stdout); ! 447: ! 448: while (fgets(address_str, sizeof(address_str), file)) ! 449: { ! 450: size_t addr_len = strlen(address_str); ! 451: char *last_chr = address_str + addr_len - 1; ! 452: if (*last_chr == '\n') ! 453: { ! 454: if (addr_len == 1) ! 455: { /* end of input */ ! 456: break; ! 457: } ! 458: *last_chr = '\0'; ! 459: } ! 460: if (add_address(pool_id, address_str, &family) == FALSE) ! 461: { ! 462: if (file != stdin) ! 463: { ! 464: fclose(file); ! 465: } ! 466: exit(EXIT_FAILURE); ! 467: } ! 468: ++count; ! 469: } ! 470: ! 471: if (file != stdin) ! 472: { ! 473: fclose(file); ! 474: } ! 475: ! 476: if (family == AF_INET6) ! 477: { /* update address family if necessary */ ! 478: addr = host_create_from_string("%any6", 0); ! 479: if (db->execute(db, NULL, ! 480: "UPDATE pools SET start = ?, end = ? WHERE id = ?", ! 481: DB_BLOB, addr->get_address(addr), ! 482: DB_BLOB, addr->get_address(addr), DB_UINT, pool_id) <= 0) ! 483: { ! 484: addr->destroy(addr); ! 485: fprintf(stderr, "updating pool address family failed.\n"); ! 486: exit(EXIT_FAILURE); ! 487: } ! 488: addr->destroy(addr); ! 489: } ! 490: ! 491: db->commit(db); ! 492: ! 493: printf("%d addresses done.\n", count); ! 494: } ! 495: ! 496: /** ! 497: * ipsec pool --del - delete a pool ! 498: */ ! 499: static void del(char *name) ! 500: { ! 501: enumerator_t *query; ! 502: u_int id; ! 503: bool found = FALSE; ! 504: ! 505: query = db->query(db, "SELECT id FROM pools WHERE name = ?", ! 506: DB_TEXT, name, DB_UINT); ! 507: if (!query) ! 508: { ! 509: fprintf(stderr, "deleting pool failed.\n"); ! 510: exit(EXIT_FAILURE); ! 511: } ! 512: while (query->enumerate(query, &id)) ! 513: { ! 514: found = TRUE; ! 515: if (db->execute(db, NULL, ! 516: "DELETE FROM leases WHERE address IN (" ! 517: " SELECT id FROM addresses WHERE pool = ?)", DB_UINT, id) < 0 || ! 518: db->execute(db, NULL, ! 519: "DELETE FROM addresses WHERE pool = ?", DB_UINT, id) < 0 || ! 520: db->execute(db, NULL, ! 521: "DELETE FROM pools WHERE id = ?", DB_UINT, id) < 0) ! 522: { ! 523: fprintf(stderr, "deleting pool failed.\n"); ! 524: query->destroy(query); ! 525: exit(EXIT_FAILURE); ! 526: } ! 527: } ! 528: query->destroy(query); ! 529: if (!found) ! 530: { ! 531: fprintf(stderr, "pool '%s' not found.\n", name); ! 532: exit(EXIT_FAILURE); ! 533: } ! 534: } ! 535: ! 536: /** ! 537: * ipsec pool --resize - resize a pool ! 538: */ ! 539: static void resize(char *name, host_t *end) ! 540: { ! 541: enumerator_t *query; ! 542: chunk_t old_addr, new_addr, cur_addr; ! 543: u_int id, count; ! 544: host_t *old_end; ! 545: ! 546: new_addr = end->get_address(end); ! 547: ! 548: query = db->query(db, "SELECT id, end FROM pools WHERE name = ?", ! 549: DB_TEXT, name, DB_UINT, DB_BLOB); ! 550: if (!query || !query->enumerate(query, &id, &old_addr)) ! 551: { ! 552: DESTROY_IF(query); ! 553: fprintf(stderr, "resizing pool failed.\n"); ! 554: exit(EXIT_FAILURE); ! 555: } ! 556: if (old_addr.len != new_addr.len || ! 557: memcmp(new_addr.ptr, old_addr.ptr, old_addr.len) < 0) ! 558: { ! 559: fprintf(stderr, "shrinking of pools not supported.\n"); ! 560: query->destroy(query); ! 561: exit(EXIT_FAILURE); ! 562: } ! 563: cur_addr = chunk_clonea(old_addr); ! 564: count = get_pool_size(old_addr, new_addr) - 1; ! 565: query->destroy(query); ! 566: ! 567: /* Check whether pool is resizable */ ! 568: old_end = host_create_from_chunk(AF_UNSPEC, old_addr, 0); ! 569: if (old_end && old_end->is_anyaddr(old_end)) ! 570: { ! 571: fprintf(stderr, "pool is not resizable.\n"); ! 572: old_end->destroy(old_end); ! 573: exit(EXIT_FAILURE); ! 574: } ! 575: DESTROY_IF(old_end); ! 576: ! 577: db->transaction(db, FALSE); ! 578: if (db->execute(db, NULL, ! 579: "UPDATE pools SET end = ? WHERE name = ?", ! 580: DB_BLOB, new_addr, DB_TEXT, name) <= 0) ! 581: { ! 582: fprintf(stderr, "pool '%s' not found.\n", name); ! 583: exit(EXIT_FAILURE); ! 584: } ! 585: ! 586: printf("allocating %d new addresses... ", count); ! 587: fflush(stdout); ! 588: while (count-- > 0) ! 589: { ! 590: chunk_increment(cur_addr); ! 591: db->execute(db, NULL, ! 592: "INSERT INTO addresses (pool, address, identity, acquired, released) " ! 593: "VALUES (?, ?, ?, ?, ?)", ! 594: DB_UINT, id, DB_BLOB, cur_addr, DB_UINT, 0, DB_UINT, 0, DB_UINT, 1); ! 595: } ! 596: db->commit(db); ! 597: printf("done.\n"); ! 598: ! 599: } ! 600: ! 601: /** ! 602: * create the lease query using the filter string ! 603: */ ! 604: static enumerator_t *create_lease_query(char *filter, array_t **to_free) ! 605: { ! 606: enumerator_t *query; ! 607: chunk_t id_chunk = chunk_empty, addr_chunk = chunk_empty; ! 608: id_type_t id_type = 0; ! 609: u_int tstamp = 0; ! 610: bool online = FALSE, valid = FALSE, expired = FALSE; ! 611: char *value, *pos, *pool = NULL; ! 612: enum { ! 613: FIL_POOL = 0, ! 614: FIL_ID, ! 615: FIL_ADDR, ! 616: FIL_TSTAMP, ! 617: FIL_STATE, ! 618: }; ! 619: char *const token[] = { ! 620: [FIL_POOL] = "pool", ! 621: [FIL_ID] = "id", ! 622: [FIL_ADDR] = "addr", ! 623: [FIL_TSTAMP] = "tstamp", ! 624: [FIL_STATE] = "status", ! 625: NULL ! 626: }; ! 627: ! 628: /* if the filter string contains a distinguished name as a ID, we replace ! 629: * ", " by "/ " in order to not confuse the getsubopt parser */ ! 630: pos = filter; ! 631: while ((pos = strchr(pos, ','))) ! 632: { ! 633: if (pos[1] == ' ') ! 634: { ! 635: pos[0] = '/'; ! 636: } ! 637: pos++; ! 638: } ! 639: ! 640: while (filter && *filter != '\0') ! 641: { ! 642: switch (getsubopt(&filter, token, &value)) ! 643: { ! 644: case FIL_POOL: ! 645: if (value) ! 646: { ! 647: pool = value; ! 648: } ! 649: break; ! 650: case FIL_ID: ! 651: if (value) ! 652: { ! 653: identification_t *id; ! 654: ! 655: id = identification_create_from_string(value); ! 656: id_type = id->get_type(id); ! 657: id_chunk = chunk_clone(id->get_encoding(id)); ! 658: array_insert_create(to_free, ARRAY_TAIL, id_chunk.ptr); ! 659: id->destroy(id); ! 660: } ! 661: break; ! 662: case FIL_ADDR: ! 663: if (value) ! 664: { ! 665: host_t *addr; ! 666: ! 667: addr = host_create_from_string(value, 0); ! 668: if (!addr) ! 669: { ! 670: fprintf(stderr, "invalid 'addr' in filter string.\n"); ! 671: exit(EXIT_FAILURE); ! 672: } ! 673: addr_chunk = chunk_clone(addr->get_address(addr)); ! 674: array_insert_create(to_free, ARRAY_TAIL, addr_chunk.ptr); ! 675: addr->destroy(addr); ! 676: } ! 677: break; ! 678: case FIL_TSTAMP: ! 679: if (value) ! 680: { ! 681: tstamp = atoi(value); ! 682: } ! 683: if (tstamp == 0) ! 684: { ! 685: online = TRUE; ! 686: } ! 687: break; ! 688: case FIL_STATE: ! 689: if (value) ! 690: { ! 691: if (streq(value, "online")) ! 692: { ! 693: online = TRUE; ! 694: } ! 695: else if (streq(value, "valid")) ! 696: { ! 697: valid = TRUE; ! 698: } ! 699: else if (streq(value, "expired")) ! 700: { ! 701: expired = TRUE; ! 702: } ! 703: else ! 704: { ! 705: fprintf(stderr, "invalid 'state' in filter string.\n"); ! 706: exit(EXIT_FAILURE); ! 707: } ! 708: } ! 709: break; ! 710: default: ! 711: fprintf(stderr, "invalid filter string.\n"); ! 712: exit(EXIT_FAILURE); ! 713: } ! 714: } ! 715: query = db->query(db, ! 716: "SELECT name, addresses.address, identities.type, " ! 717: "identities.data, leases.acquired, leases.released, timeout " ! 718: "FROM leases JOIN addresses ON leases.address = addresses.id " ! 719: "JOIN pools ON addresses.pool = pools.id " ! 720: "JOIN identities ON leases.identity = identities.id " ! 721: "WHERE (? OR name = ?) " ! 722: "AND (? OR (identities.type = ? AND identities.data = ?)) " ! 723: "AND (? OR addresses.address = ?) " ! 724: "AND (? OR (? >= leases.acquired AND (? <= leases.released))) " ! 725: "AND (? OR leases.released > ? - timeout) " ! 726: "AND (? OR leases.released < ? - timeout) " ! 727: "AND ? " ! 728: "UNION " ! 729: "SELECT name, address, identities.type, identities.data, " ! 730: "acquired, released, timeout FROM addresses " ! 731: "JOIN pools ON addresses.pool = pools.id " ! 732: "JOIN identities ON addresses.identity = identities.id " ! 733: "WHERE ? AND released = 0 " ! 734: "AND (? OR name = ?) " ! 735: "AND (? OR (identities.type = ? AND identities.data = ?)) " ! 736: "AND (? OR address = ?)", ! 737: DB_INT, pool == NULL, DB_TEXT, pool, ! 738: DB_INT, !id_chunk.ptr, ! 739: DB_INT, id_type, ! 740: DB_BLOB, id_chunk, ! 741: DB_INT, !addr_chunk.ptr, ! 742: DB_BLOB, addr_chunk, ! 743: DB_INT, tstamp == 0, DB_UINT, tstamp, DB_UINT, tstamp, ! 744: DB_INT, !valid, DB_INT, time(NULL), ! 745: DB_INT, !expired, DB_INT, time(NULL), ! 746: DB_INT, !online, ! 747: /* union */ ! 748: DB_INT, !(valid || expired), ! 749: DB_INT, pool == NULL, DB_TEXT, pool, ! 750: DB_INT, !id_chunk.ptr, ! 751: DB_INT, id_type, ! 752: DB_BLOB, id_chunk, ! 753: DB_INT, !addr_chunk.ptr, ! 754: DB_BLOB, addr_chunk, ! 755: /* res */ ! 756: DB_TEXT, DB_BLOB, DB_INT, DB_BLOB, DB_UINT, DB_UINT, DB_UINT); ! 757: return query; ! 758: } ! 759: ! 760: /** ! 761: * ipsec pool --leases - show lease information of a pool ! 762: */ ! 763: static void leases(char *filter, bool utc) ! 764: { ! 765: enumerator_t *query; ! 766: array_t *to_free = NULL; ! 767: chunk_t address_chunk, identity_chunk; ! 768: int identity_type; ! 769: char *name; ! 770: u_int db_acquired, db_released, db_timeout; ! 771: time_t acquired, released, timeout; ! 772: host_t *address; ! 773: identification_t *identity; ! 774: bool found = FALSE; ! 775: ! 776: query = create_lease_query(filter, &to_free); ! 777: if (!query) ! 778: { ! 779: fprintf(stderr, "querying leases failed.\n"); ! 780: exit(EXIT_FAILURE); ! 781: } ! 782: while (query->enumerate(query, &name, &address_chunk, &identity_type, ! 783: &identity_chunk, &db_acquired, &db_released, &db_timeout)) ! 784: { ! 785: if (!found) ! 786: { ! 787: int len = utc ? 25 : 21; ! 788: ! 789: found = TRUE; ! 790: printf("%-8s %-15s %-7s %-*s %-*s %s\n", ! 791: "name", "address", "status", len, "start", len, "end", "identity"); ! 792: } ! 793: address = host_create_from_chunk(AF_UNSPEC, address_chunk, 0); ! 794: identity = identification_create_from_encoding(identity_type, identity_chunk); ! 795: ! 796: /* u_int is not always equal to time_t */ ! 797: acquired = (time_t)db_acquired; ! 798: released = (time_t)db_released; ! 799: timeout = (time_t)db_timeout; ! 800: ! 801: printf("%-8s %-15H ", name, address); ! 802: if (released == 0) ! 803: { ! 804: printf("%-7s ", "online"); ! 805: } ! 806: else if (timeout == 0) ! 807: { ! 808: printf("%-7s ", "static"); ! 809: } ! 810: else if (released >= time(NULL) - timeout) ! 811: { ! 812: printf("%-7s ", "valid"); ! 813: } ! 814: else ! 815: { ! 816: printf("%-7s ", "expired"); ! 817: } ! 818: ! 819: printf(" %T ", &acquired, utc); ! 820: if (released) ! 821: { ! 822: printf("%T ", &released, utc); ! 823: } ! 824: else ! 825: { ! 826: printf(" "); ! 827: if (utc) ! 828: { ! 829: printf(" "); ! 830: } ! 831: } ! 832: printf("%Y\n", identity); ! 833: DESTROY_IF(address); ! 834: identity->destroy(identity); ! 835: } ! 836: query->destroy(query); ! 837: if (to_free) ! 838: { ! 839: array_destroy_function(to_free, (void*)free, NULL); ! 840: } ! 841: if (!found) ! 842: { ! 843: fprintf(stderr, "no matching leases found.\n"); ! 844: exit(EXIT_FAILURE); ! 845: } ! 846: } ! 847: ! 848: /** ! 849: * ipsec pool --purge - delete expired leases ! 850: */ ! 851: static void purge(char *name) ! 852: { ! 853: int purged = 0; ! 854: ! 855: purged = db->execute(db, NULL, ! 856: "DELETE FROM leases WHERE address IN (" ! 857: " SELECT id FROM addresses WHERE pool IN (" ! 858: " SELECT id FROM pools WHERE name = ?))", ! 859: DB_TEXT, name); ! 860: if (purged < 0) ! 861: { ! 862: fprintf(stderr, "purging pool '%s' failed.\n", name); ! 863: exit(EXIT_FAILURE); ! 864: } ! 865: fprintf(stderr, "purged %d leases in pool '%s'.\n", purged, name); ! 866: } ! 867: ! 868: #define ARGV_SIZE 32 ! 869: ! 870: static void argv_add(char **argv, int argc, char *value) ! 871: { ! 872: if (argc >= ARGV_SIZE) ! 873: { ! 874: fprintf(stderr, "too many arguments: %s\n", value); ! 875: exit(EXIT_FAILURE); ! 876: } ! 877: argv[argc] = value; ! 878: } ! 879: ! 880: /** ! 881: * ipsec pool --batch - read commands from a file ! 882: */ ! 883: static void batch(char *argv0, char *name) ! 884: { ! 885: char command[512]; ! 886: ! 887: FILE *file = strncmp(name, "-", 1) == 0 ? stdin : fopen(name, "r"); ! 888: if (file == NULL) ! 889: { ! 890: fprintf(stderr, "opening '%s' failed: %s\n", name, strerror(errno)); ! 891: exit(EXIT_FAILURE); ! 892: } ! 893: ! 894: db->transaction(db, FALSE); ! 895: while (fgets(command, sizeof(command), file)) ! 896: { ! 897: char *argv[ARGV_SIZE], *start; ! 898: int i, argc = 0; ! 899: size_t cmd_len = strlen(command); ! 900: ! 901: /* ignore empty lines */ ! 902: if (cmd_len == 1 && *(command + cmd_len - 1) == '\n') ! 903: { ! 904: continue; ! 905: } ! 906: ! 907: /* parse command into argv */ ! 908: start = command; ! 909: argv_add(argv, argc++, argv0); ! 910: for (i = 0; i < cmd_len; ++i) ! 911: { ! 912: if (command[i] == ' ' || command[i] == '\n') ! 913: { ! 914: if (command + i == start) ! 915: { ! 916: /* ignore leading whitespace */ ! 917: ++start; ! 918: continue; ! 919: } ! 920: command[i] = '\0'; ! 921: argv_add(argv, argc++, start); ! 922: start = command + i + 1; ! 923: } ! 924: } ! 925: if (strlen(start) > 0) ! 926: { ! 927: argv_add(argv, argc++, start); ! 928: } ! 929: argv_add(argv, argc, NULL); ! 930: ! 931: do_args(argc, argv); ! 932: } ! 933: db->commit(db); ! 934: ! 935: if (file != stdin) ! 936: { ! 937: fclose(file); ! 938: } ! 939: } ! 940: ! 941: /** ! 942: * atexit handler to close db on shutdown ! 943: */ ! 944: static void cleanup(void) ! 945: { ! 946: db->destroy(db); ! 947: DESTROY_IF(start_addr); ! 948: DESTROY_IF(end_addr); ! 949: } ! 950: ! 951: static void do_args(int argc, char *argv[]) ! 952: { ! 953: char *name = "", *value = "", *filter = ""; ! 954: char *pool = NULL, *identity = NULL, *addresses = NULL; ! 955: value_type_t value_type = VALUE_NONE; ! 956: time_t timeout = 0; ! 957: bool utc = FALSE, hexout = FALSE; ! 958: ! 959: enum { ! 960: OP_UNDEF, ! 961: OP_USAGE, ! 962: OP_STATUS, ! 963: OP_STATUS_ATTR, ! 964: OP_ADD, ! 965: OP_ADD_ATTR, ! 966: OP_DEL, ! 967: OP_DEL_ATTR, ! 968: OP_SHOW_ATTR, ! 969: OP_RESIZE, ! 970: OP_LEASES, ! 971: OP_PURGE, ! 972: OP_BATCH ! 973: } operation = OP_UNDEF; ! 974: ! 975: /* reinit getopt state */ ! 976: optind = 0; ! 977: ! 978: while (TRUE) ! 979: { ! 980: int c; ! 981: ! 982: struct option long_opts[] = { ! 983: { "help", no_argument, NULL, 'h' }, ! 984: ! 985: { "utc", no_argument, NULL, 'u' }, ! 986: { "status", no_argument, NULL, 'w' }, ! 987: { "add", required_argument, NULL, 'a' }, ! 988: { "replace", required_argument, NULL, 'c' }, ! 989: { "del", required_argument, NULL, 'd' }, ! 990: { "resize", required_argument, NULL, 'r' }, ! 991: { "leases", no_argument, NULL, 'l' }, ! 992: { "purge", required_argument, NULL, 'p' }, ! 993: { "statusattr", no_argument, NULL, '1' }, ! 994: { "addattr", required_argument, NULL, '2' }, ! 995: { "delattr", required_argument, NULL, '3' }, ! 996: { "showattr", no_argument, NULL, '4' }, ! 997: { "batch", required_argument, NULL, 'b' }, ! 998: ! 999: { "start", required_argument, NULL, 's' }, ! 1000: { "end", required_argument, NULL, 'e' }, ! 1001: { "addresses", required_argument, NULL, 'y' }, ! 1002: { "timeout", required_argument, NULL, 't' }, ! 1003: { "filter", required_argument, NULL, 'f' }, ! 1004: { "addr", required_argument, NULL, 'v' }, ! 1005: { "mask", required_argument, NULL, 'v' }, ! 1006: { "server", required_argument, NULL, 'v' }, ! 1007: { "subnet", required_argument, NULL, 'n' }, ! 1008: { "string", required_argument, NULL, 'g' }, ! 1009: { "hex", required_argument, NULL, 'x' }, ! 1010: { "hexout", no_argument, NULL, '5' }, ! 1011: { "pool", required_argument, NULL, '6' }, ! 1012: { "identity", required_argument, NULL, '7' }, ! 1013: { 0,0,0,0 } ! 1014: }; ! 1015: ! 1016: c = getopt_long(argc, argv, "", long_opts, NULL); ! 1017: switch (c) ! 1018: { ! 1019: case EOF: ! 1020: break; ! 1021: case 'h': ! 1022: operation = OP_USAGE; ! 1023: break; ! 1024: case 'w': ! 1025: operation = OP_STATUS; ! 1026: break; ! 1027: case '1': ! 1028: operation = OP_STATUS_ATTR; ! 1029: break; ! 1030: case 'u': ! 1031: utc = TRUE; ! 1032: continue; ! 1033: case 'c': ! 1034: replace_pool = TRUE; ! 1035: /* fallthrough */ ! 1036: case 'a': ! 1037: name = optarg; ! 1038: operation = is_attribute(name) ? OP_ADD_ATTR : OP_ADD; ! 1039: if (replace_pool && operation == OP_ADD_ATTR) ! 1040: { ! 1041: fprintf(stderr, "invalid pool name: " ! 1042: "reserved for '%s' attribute.\n", optarg); ! 1043: usage(); ! 1044: exit(EXIT_FAILURE); ! 1045: } ! 1046: continue; ! 1047: case '2': ! 1048: name = optarg; ! 1049: operation = OP_ADD_ATTR; ! 1050: continue; ! 1051: case 'd': ! 1052: name = optarg; ! 1053: operation = is_attribute(name) ? OP_DEL_ATTR : OP_DEL; ! 1054: continue; ! 1055: case '3': ! 1056: name = optarg; ! 1057: operation = OP_DEL_ATTR; ! 1058: continue; ! 1059: case '4': ! 1060: operation = OP_SHOW_ATTR; ! 1061: continue; ! 1062: case 'r': ! 1063: name = optarg; ! 1064: operation = OP_RESIZE; ! 1065: continue; ! 1066: case 'l': ! 1067: operation = OP_LEASES; ! 1068: continue; ! 1069: case 'p': ! 1070: name = optarg; ! 1071: operation = OP_PURGE; ! 1072: continue; ! 1073: case 'b': ! 1074: name = optarg; ! 1075: if (operation == OP_BATCH) ! 1076: { ! 1077: fprintf(stderr, "--batch commands can not be nested\n"); ! 1078: exit(EXIT_FAILURE); ! 1079: } ! 1080: operation = OP_BATCH; ! 1081: continue; ! 1082: case 's': ! 1083: DESTROY_IF(start_addr); ! 1084: start_addr = host_create_from_string(optarg, 0); ! 1085: if (!start_addr) ! 1086: { ! 1087: fprintf(stderr, "invalid start address: '%s'.\n", optarg); ! 1088: usage(); ! 1089: exit(EXIT_FAILURE); ! 1090: } ! 1091: continue; ! 1092: case 'e': ! 1093: DESTROY_IF(end_addr); ! 1094: end_addr = host_create_from_string(optarg, 0); ! 1095: if (!end_addr) ! 1096: { ! 1097: fprintf(stderr, "invalid end address: '%s'.\n", optarg); ! 1098: usage(); ! 1099: exit(EXIT_FAILURE); ! 1100: } ! 1101: continue; ! 1102: case 't': ! 1103: if (!timespan_from_string(optarg, "h", &timeout)) ! 1104: { ! 1105: fprintf(stderr, "invalid timeout '%s'.\n", optarg); ! 1106: usage(); ! 1107: exit(EXIT_FAILURE); ! 1108: } ! 1109: continue; ! 1110: case 'f': ! 1111: filter = optarg; ! 1112: continue; ! 1113: case 'y': ! 1114: addresses = optarg; ! 1115: continue; ! 1116: case 'g': ! 1117: value_type = VALUE_STRING; ! 1118: value = optarg; ! 1119: continue; ! 1120: case 'n': ! 1121: value_type = VALUE_SUBNET; ! 1122: value = optarg; ! 1123: continue; ! 1124: case 'v': ! 1125: value_type = VALUE_ADDR; ! 1126: value = optarg; ! 1127: continue; ! 1128: case 'x': ! 1129: value_type = VALUE_HEX; ! 1130: value = optarg; ! 1131: continue; ! 1132: case '5': ! 1133: hexout = TRUE; ! 1134: continue; ! 1135: case '6': ! 1136: pool = optarg; ! 1137: continue; ! 1138: case '7': ! 1139: identity = optarg; ! 1140: continue; ! 1141: default: ! 1142: usage(); ! 1143: exit(EXIT_FAILURE); ! 1144: } ! 1145: break; ! 1146: } ! 1147: ! 1148: switch (operation) ! 1149: { ! 1150: case OP_USAGE: ! 1151: usage(); ! 1152: break; ! 1153: case OP_STATUS: ! 1154: status(); ! 1155: break; ! 1156: case OP_STATUS_ATTR: ! 1157: status_attr(hexout); ! 1158: break; ! 1159: case OP_ADD: ! 1160: if (addresses != NULL) ! 1161: { ! 1162: add_addresses(name, addresses, timeout); ! 1163: } ! 1164: else if (start_addr && end_addr) ! 1165: { ! 1166: add(name, start_addr, end_addr, timeout); ! 1167: } ! 1168: else ! 1169: { ! 1170: fprintf(stderr, "missing arguments.\n"); ! 1171: usage(); ! 1172: exit(EXIT_FAILURE); ! 1173: } ! 1174: break; ! 1175: case OP_ADD_ATTR: ! 1176: if (value_type == VALUE_NONE) ! 1177: { ! 1178: fprintf(stderr, "missing arguments.\n"); ! 1179: usage(); ! 1180: exit(EXIT_FAILURE); ! 1181: } ! 1182: if (identity && !pool) ! 1183: { ! 1184: fprintf(stderr, "--identity option can't be used without --pool.\n"); ! 1185: usage(); ! 1186: exit(EXIT_FAILURE); ! 1187: } ! 1188: add_attr(name, pool, identity, value, value_type); ! 1189: break; ! 1190: case OP_DEL: ! 1191: del(name); ! 1192: break; ! 1193: case OP_DEL_ATTR: ! 1194: if (identity && !pool) ! 1195: { ! 1196: fprintf(stderr, "--identity option can't be used without --pool.\n"); ! 1197: usage(); ! 1198: exit(EXIT_FAILURE); ! 1199: } ! 1200: del_attr(name, pool, identity, value, value_type); ! 1201: break; ! 1202: case OP_SHOW_ATTR: ! 1203: show_attr(); ! 1204: break; ! 1205: case OP_RESIZE: ! 1206: if (!end_addr) ! 1207: { ! 1208: fprintf(stderr, "missing arguments.\n"); ! 1209: usage(); ! 1210: exit(EXIT_FAILURE); ! 1211: } ! 1212: resize(name, end_addr); ! 1213: break; ! 1214: case OP_LEASES: ! 1215: leases(filter, utc); ! 1216: break; ! 1217: case OP_PURGE: ! 1218: purge(name); ! 1219: break; ! 1220: case OP_BATCH: ! 1221: if (name == NULL) ! 1222: { ! 1223: fprintf(stderr, "missing arguments.\n"); ! 1224: usage(); ! 1225: exit(EXIT_FAILURE); ! 1226: } ! 1227: batch(argv[0], name); ! 1228: break; ! 1229: default: ! 1230: usage(); ! 1231: exit(EXIT_FAILURE); ! 1232: } ! 1233: } ! 1234: ! 1235: int main(int argc, char *argv[]) ! 1236: { ! 1237: char *uri; ! 1238: ! 1239: atexit(library_deinit); ! 1240: ! 1241: /* initialize library */ ! 1242: if (!library_init(NULL, "pool")) ! 1243: { ! 1244: exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); ! 1245: } ! 1246: if (lib->integrity && ! 1247: !lib->integrity->check_file(lib->integrity, "pool", argv[0])) ! 1248: { ! 1249: fprintf(stderr, "integrity check of pool failed\n"); ! 1250: exit(SS_RC_DAEMON_INTEGRITY); ! 1251: } ! 1252: if (!lib->plugins->load(lib->plugins, ! 1253: lib->settings->get_str(lib->settings, "pool.load", PLUGINS))) ! 1254: { ! 1255: exit(SS_RC_INITIALIZATION_FAILED); ! 1256: } ! 1257: /* TODO: make database URI or setting key configurable via command line */ ! 1258: uri = lib->settings->get_str(lib->settings, ! 1259: "pool.database", ! 1260: lib->settings->get_str(lib->settings, ! 1261: "charon.plugins.attr-sql.database", ! 1262: lib->settings->get_str(lib->settings, ! 1263: "libhydra.plugins.attr-sql.database", NULL))); ! 1264: if (!uri) ! 1265: { ! 1266: fprintf(stderr, "database URI pool.database not set.\n"); ! 1267: exit(SS_RC_INITIALIZATION_FAILED); ! 1268: } ! 1269: db = lib->db->create(lib->db, uri); ! 1270: if (!db) ! 1271: { ! 1272: fprintf(stderr, "opening database failed.\n"); ! 1273: exit(SS_RC_INITIALIZATION_FAILED); ! 1274: } ! 1275: atexit(cleanup); ! 1276: ! 1277: do_args(argc, argv); ! 1278: ! 1279: exit(EXIT_SUCCESS); ! 1280: }