Annotation of embedaddon/strongswan/src/libcharon/config/backend_manager.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2018 Tobias Brunner
! 3: * Copyright (C) 2007-2009 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: #include "backend_manager.h"
! 18:
! 19: #include <sys/types.h>
! 20:
! 21: #include <daemon.h>
! 22: #include <collections/linked_list.h>
! 23: #include <threading/rwlock.h>
! 24:
! 25:
! 26: typedef struct private_backend_manager_t private_backend_manager_t;
! 27:
! 28: /**
! 29: * Private data of an backend_manager_t object.
! 30: */
! 31: struct private_backend_manager_t {
! 32:
! 33: /**
! 34: * Public part of backend_manager_t object.
! 35: */
! 36: backend_manager_t public;
! 37:
! 38: /**
! 39: * list of registered backends
! 40: */
! 41: linked_list_t *backends;
! 42:
! 43: /**
! 44: * rwlock for backends
! 45: */
! 46: rwlock_t *lock;
! 47: };
! 48:
! 49: /**
! 50: * match of an ike_cfg
! 51: */
! 52: typedef enum ike_cfg_match_t {
! 53: /* doesn't match at all */
! 54: MATCH_NONE = 0x00,
! 55: /* match for a %any host. For both hosts, hence skip 0x02 */
! 56: MATCH_ANY = 0x01,
! 57: /* IKE version matches exactly (config is not for any version) */
! 58: MATCH_VERSION = 0x04,
! 59: /* local identity matches */
! 60: MATCH_ME = 0x08,
! 61: /* remote identity matches */
! 62: MATCH_OTHER = 0x10,
! 63: } ike_cfg_match_t;
! 64:
! 65: /**
! 66: * data to pass nested IKE enumerator
! 67: */
! 68: typedef struct {
! 69: private_backend_manager_t *this;
! 70: host_t *me;
! 71: host_t *other;
! 72: } ike_data_t;
! 73:
! 74: /**
! 75: * inner enumerator constructor for IKE cfgs
! 76: */
! 77: static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data)
! 78: {
! 79: return backend->create_ike_cfg_enumerator(backend, data->me, data->other);
! 80: }
! 81:
! 82: /**
! 83: * get a match of a candidate ike_cfg for two hosts
! 84: */
! 85: static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other,
! 86: ike_version_t version)
! 87: {
! 88: ike_cfg_match_t match = MATCH_NONE;
! 89: int quality;
! 90:
! 91: if (cand->get_version(cand) != IKE_ANY &&
! 92: version != cand->get_version(cand))
! 93: {
! 94: return MATCH_NONE;
! 95: }
! 96:
! 97: if (me)
! 98: {
! 99: quality = cand->match_me(cand, me);
! 100: if (!quality)
! 101: {
! 102: return MATCH_NONE;
! 103: }
! 104: match += quality * MATCH_ME;
! 105: }
! 106: else
! 107: {
! 108: match += MATCH_ANY;
! 109: }
! 110:
! 111: if (other)
! 112: {
! 113: quality = cand->match_other(cand, other);
! 114: if (!quality)
! 115: {
! 116: return MATCH_NONE;
! 117: }
! 118: match += quality * MATCH_OTHER;
! 119: }
! 120: else
! 121: {
! 122: match += MATCH_ANY;
! 123: }
! 124:
! 125: if (match != MATCH_NONE &&
! 126: cand->get_version(cand) != IKE_ANY)
! 127: { /* if we have a match, improve it if candidate version specified */
! 128: match += MATCH_VERSION;
! 129: }
! 130: return match;
! 131: }
! 132:
! 133: /**
! 134: * list element to help sorting
! 135: */
! 136: typedef struct {
! 137: ike_cfg_match_t match;
! 138: ike_cfg_t *cfg;
! 139: } ike_match_entry_t;
! 140:
! 141: CALLBACK(ike_enum_filter, bool,
! 142: linked_list_t *configs, enumerator_t *orig, va_list args)
! 143: {
! 144: ike_match_entry_t *entry;
! 145: ike_cfg_t **out;
! 146:
! 147: VA_ARGS_VGET(args, out);
! 148:
! 149: if (orig->enumerate(orig, &entry))
! 150: {
! 151: *out = entry->cfg;
! 152: return TRUE;
! 153: }
! 154: return FALSE;
! 155: }
! 156:
! 157: CALLBACK(ike_match_entry_list_destroy, void,
! 158: linked_list_t *configs)
! 159: {
! 160: ike_match_entry_t *entry;
! 161:
! 162: while (configs->remove_last(configs, (void**)&entry) == SUCCESS)
! 163: {
! 164: entry->cfg->destroy(entry->cfg);
! 165: free(entry);
! 166: }
! 167: configs->destroy(configs);
! 168: }
! 169:
! 170: /**
! 171: * Insert entry into match-sorted list
! 172: */
! 173: static void insert_sorted_ike(ike_match_entry_t *entry, linked_list_t *list)
! 174: {
! 175: enumerator_t *enumerator;
! 176: ike_match_entry_t *current;
! 177:
! 178: enumerator = list->create_enumerator(list);
! 179: while (enumerator->enumerate(enumerator, ¤t))
! 180: {
! 181: if (entry->match > current->match)
! 182: {
! 183: break;
! 184: }
! 185: }
! 186: list->insert_before(list, enumerator, entry);
! 187: enumerator->destroy(enumerator);
! 188: }
! 189:
! 190: /**
! 191: * Create a sorted list of all matching IKE configs
! 192: */
! 193: static linked_list_t *get_matching_ike_cfgs(private_backend_manager_t *this,
! 194: host_t *me, host_t *other,
! 195: ike_version_t version)
! 196: {
! 197: ike_cfg_t *current;
! 198: char *my_addr, *other_addr;
! 199: enumerator_t *enumerator;
! 200: ike_data_t *data;
! 201: linked_list_t *configs;
! 202: ike_cfg_match_t match;
! 203: ike_match_entry_t *entry;
! 204:
! 205: INIT(data,
! 206: .this = this,
! 207: .me = me,
! 208: .other = other,
! 209: );
! 210:
! 211: configs = linked_list_create();
! 212:
! 213: this->lock->read_lock(this->lock);
! 214: enumerator = enumerator_create_nested(
! 215: this->backends->create_enumerator(this->backends),
! 216: (void*)ike_enum_create, data, (void*)free);
! 217:
! 218: while (enumerator->enumerate(enumerator, ¤t))
! 219: {
! 220: my_addr = current->get_my_addr(current);
! 221: other_addr = current->get_other_addr(current);
! 222: match = get_ike_match(current, me, other, version);
! 223: DBG3(DBG_CFG, "ike config match: %d (%s...%s %N)", match, my_addr,
! 224: other_addr, ike_version_names, current->get_version(current));
! 225:
! 226: if (match)
! 227: {
! 228: DBG2(DBG_CFG, " candidate: %s...%s, prio %d",
! 229: my_addr, other_addr, match);
! 230:
! 231: INIT(entry,
! 232: .match = match,
! 233: .cfg = current->get_ref(current),
! 234: );
! 235: insert_sorted_ike(entry, configs);
! 236: }
! 237: }
! 238: enumerator->destroy(enumerator);
! 239: this->lock->unlock(this->lock);
! 240:
! 241: return configs;
! 242: }
! 243:
! 244: METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*,
! 245: private_backend_manager_t *this, host_t *me, host_t *other,
! 246: ike_version_t version)
! 247: {
! 248: linked_list_t *configs;
! 249: ike_match_entry_t *entry;
! 250: ike_cfg_t *found = NULL;
! 251: char *my_addr, *other_addr;
! 252:
! 253: DBG2(DBG_CFG, "looking for an %N config for %H...%H", ike_version_names,
! 254: version, me, other);
! 255:
! 256: configs = get_matching_ike_cfgs(this, me, other, version);
! 257: if (configs->get_first(configs, (void**)&entry) == SUCCESS)
! 258: {
! 259: found = entry->cfg->get_ref(entry->cfg);
! 260:
! 261: my_addr = found->get_my_addr(found);
! 262: other_addr = found->get_other_addr(found);
! 263: DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d",
! 264: my_addr, other_addr, entry->match);
! 265: }
! 266: ike_match_entry_list_destroy(configs);
! 267:
! 268: return found;
! 269: }
! 270:
! 271: METHOD(backend_manager_t, create_ike_cfg_enumerator, enumerator_t*,
! 272: private_backend_manager_t *this, host_t *me, host_t *other,
! 273: ike_version_t version)
! 274: {
! 275: linked_list_t *configs;
! 276:
! 277: DBG2(DBG_CFG, "looking for %N configs for %H...%H", ike_version_names,
! 278: version, me, other);
! 279:
! 280: configs = get_matching_ike_cfgs(this, me, other, version);
! 281:
! 282: return enumerator_create_filter(configs->create_enumerator(configs),
! 283: ike_enum_filter, configs,
! 284: ike_match_entry_list_destroy);
! 285: }
! 286:
! 287: /**
! 288: * Get the best ID match in one of the configs auth_cfg
! 289: */
! 290: static id_match_t get_peer_match(identification_t *id,
! 291: peer_cfg_t *cfg, bool local)
! 292: {
! 293: enumerator_t *enumerator;
! 294: auth_cfg_t *auth;
! 295: identification_t *candidate;
! 296: id_match_t match = ID_MATCH_NONE;
! 297: char *where = local ? "local" : "remote";
! 298: chunk_t data;
! 299:
! 300: if (!id)
! 301: {
! 302: DBG3(DBG_CFG, " %s id match: %d (%N)",
! 303: where, ID_MATCH_ANY, id_type_names, ID_ANY);
! 304: return ID_MATCH_ANY;
! 305: }
! 306:
! 307: /* compare first auth config only */
! 308: enumerator = cfg->create_auth_cfg_enumerator(cfg, local);
! 309: if (enumerator->enumerate(enumerator, &auth))
! 310: {
! 311: candidate = auth->get(auth, AUTH_RULE_IDENTITY);
! 312: if (candidate)
! 313: {
! 314: match = id->matches(id, candidate);
! 315: /* match vice-versa, as the proposed IDr might be ANY */
! 316: if (!match)
! 317: {
! 318: match = candidate->matches(candidate, id);
! 319: }
! 320: }
! 321: else
! 322: {
! 323: match = ID_MATCH_ANY;
! 324: }
! 325: }
! 326: enumerator->destroy(enumerator);
! 327:
! 328: data = id->get_encoding(id);
! 329: DBG3(DBG_CFG, " %s id match: %d (%N: %#B)",
! 330: where, match, id_type_names, id->get_type(id), &data);
! 331: return match;
! 332: }
! 333:
! 334: /**
! 335: * data to pass nested peer enumerator
! 336: */
! 337: typedef struct {
! 338: rwlock_t *lock;
! 339: identification_t *me;
! 340: identification_t *other;
! 341: } peer_data_t;
! 342:
! 343: /**
! 344: * list element to help sorting
! 345: */
! 346: typedef struct {
! 347: id_match_t match_peer;
! 348: ike_cfg_match_t match_ike;
! 349: peer_cfg_t *cfg;
! 350: } match_entry_t;
! 351:
! 352: /**
! 353: * inner enumerator constructor for peer cfgs
! 354: */
! 355: static enumerator_t *peer_enum_create(backend_t *backend, peer_data_t *data)
! 356: {
! 357: return backend->create_peer_cfg_enumerator(backend, data->me, data->other);
! 358: }
! 359:
! 360: /**
! 361: * unlock/cleanup peer enumerator
! 362: */
! 363: static void peer_enum_destroy(peer_data_t *data)
! 364: {
! 365: data->lock->unlock(data->lock);
! 366: free(data);
! 367: }
! 368:
! 369: CALLBACK(peer_enum_filter, bool,
! 370: linked_list_t *configs, enumerator_t *orig, va_list args)
! 371: {
! 372: match_entry_t *entry;
! 373: peer_cfg_t **out;
! 374:
! 375: VA_ARGS_VGET(args, out);
! 376:
! 377: if (orig->enumerate(orig, &entry))
! 378: {
! 379: *out = entry->cfg;
! 380: return TRUE;
! 381: }
! 382: return FALSE;
! 383: }
! 384:
! 385: CALLBACK(peer_enum_filter_destroy, void,
! 386: linked_list_t *configs)
! 387: {
! 388: match_entry_t *entry;
! 389:
! 390: while (configs->remove_last(configs, (void**)&entry) == SUCCESS)
! 391: {
! 392: entry->cfg->destroy(entry->cfg);
! 393: free(entry);
! 394: }
! 395: configs->destroy(configs);
! 396: }
! 397:
! 398: /**
! 399: * Insert entry into match-sorted list
! 400: */
! 401: static void insert_sorted(match_entry_t *entry, linked_list_t *list)
! 402: {
! 403: enumerator_t *enumerator;
! 404: match_entry_t *current;
! 405:
! 406: enumerator = list->create_enumerator(list);
! 407: while (enumerator->enumerate(enumerator, ¤t))
! 408: {
! 409: if ((entry->match_ike > current->match_ike &&
! 410: entry->match_peer >= current->match_peer) ||
! 411: (entry->match_ike >= current->match_ike &&
! 412: entry->match_peer > current->match_peer))
! 413: {
! 414: break;
! 415: }
! 416: }
! 417: list->insert_before(list, enumerator, entry);
! 418: enumerator->destroy(enumerator);
! 419: }
! 420:
! 421: METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*,
! 422: private_backend_manager_t *this, host_t *me, host_t *other,
! 423: identification_t *my_id, identification_t *other_id, ike_version_t version)
! 424: {
! 425: enumerator_t *enumerator;
! 426: peer_data_t *data;
! 427: peer_cfg_t *cfg;
! 428: linked_list_t *configs;
! 429:
! 430: INIT(data,
! 431: .lock = this->lock,
! 432: .me = my_id,
! 433: .other = other_id,
! 434: );
! 435:
! 436: /* create a sorted list with all matches */
! 437: this->lock->read_lock(this->lock);
! 438: enumerator = enumerator_create_nested(
! 439: this->backends->create_enumerator(this->backends),
! 440: (void*)peer_enum_create, data, (void*)peer_enum_destroy);
! 441:
! 442: if (!me && !other && !my_id && !other_id)
! 443: { /* shortcut if we are doing a "listall" */
! 444: return enumerator;
! 445: }
! 446:
! 447: configs = linked_list_create();
! 448: while (enumerator->enumerate(enumerator, &cfg))
! 449: {
! 450: ike_cfg_t *ike_cfg = cfg->get_ike_cfg(cfg);
! 451: ike_cfg_match_t match_ike;
! 452: id_match_t match_peer_me, match_peer_other;
! 453: match_entry_t *entry;
! 454: char *my_addr, *other_addr;
! 455:
! 456: match_ike = get_ike_match(ike_cfg, me, other, version);
! 457: my_addr = ike_cfg->get_my_addr(ike_cfg);
! 458: other_addr = ike_cfg->get_other_addr(ike_cfg);
! 459: DBG3(DBG_CFG, "peer config \"%s\", ike match: %d (%s...%s %N)",
! 460: cfg->get_name(cfg), match_ike, my_addr, other_addr,
! 461: ike_version_names, ike_cfg->get_version(ike_cfg));
! 462:
! 463: if (!match_ike)
! 464: {
! 465: continue;
! 466: }
! 467:
! 468: match_peer_me = get_peer_match(my_id, cfg, TRUE);
! 469: if (!match_peer_me)
! 470: {
! 471: continue;
! 472: }
! 473: match_peer_other = get_peer_match(other_id, cfg, FALSE);
! 474:
! 475: if (match_peer_other)
! 476: {
! 477: DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d (me/other/ike)",
! 478: cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike);
! 479: INIT(entry,
! 480: .match_peer = match_peer_me + match_peer_other,
! 481: .match_ike = match_ike,
! 482: .cfg = cfg->get_ref(cfg),
! 483: );
! 484: insert_sorted(entry, configs);
! 485: }
! 486: }
! 487: enumerator->destroy(enumerator);
! 488:
! 489: return enumerator_create_filter(configs->create_enumerator(configs),
! 490: peer_enum_filter, configs,
! 491: peer_enum_filter_destroy);
! 492: }
! 493:
! 494: METHOD(backend_manager_t, get_peer_cfg_by_name, peer_cfg_t*,
! 495: private_backend_manager_t *this, char *name)
! 496: {
! 497: backend_t *backend;
! 498: peer_cfg_t *config = NULL;
! 499: enumerator_t *enumerator;
! 500:
! 501: this->lock->read_lock(this->lock);
! 502: enumerator = this->backends->create_enumerator(this->backends);
! 503: while (config == NULL && enumerator->enumerate(enumerator, (void**)&backend))
! 504: {
! 505: config = backend->get_peer_cfg_by_name(backend, name);
! 506: }
! 507: enumerator->destroy(enumerator);
! 508: this->lock->unlock(this->lock);
! 509: return config;
! 510: }
! 511:
! 512: METHOD(backend_manager_t, remove_backend, void,
! 513: private_backend_manager_t *this, backend_t *backend)
! 514: {
! 515: this->lock->write_lock(this->lock);
! 516: this->backends->remove(this->backends, backend, NULL);
! 517: this->lock->unlock(this->lock);
! 518: }
! 519:
! 520: METHOD(backend_manager_t, add_backend, void,
! 521: private_backend_manager_t *this, backend_t *backend)
! 522: {
! 523: this->lock->write_lock(this->lock);
! 524: this->backends->insert_last(this->backends, backend);
! 525: this->lock->unlock(this->lock);
! 526: }
! 527:
! 528: METHOD(backend_manager_t, destroy, void,
! 529: private_backend_manager_t *this)
! 530: {
! 531: this->backends->destroy(this->backends);
! 532: this->lock->destroy(this->lock);
! 533: free(this);
! 534: }
! 535:
! 536: /*
! 537: * Described in header
! 538: */
! 539: backend_manager_t *backend_manager_create()
! 540: {
! 541: private_backend_manager_t *this;
! 542:
! 543: INIT(this,
! 544: .public = {
! 545: .get_ike_cfg = _get_ike_cfg,
! 546: .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
! 547: .get_peer_cfg_by_name = _get_peer_cfg_by_name,
! 548: .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
! 549: .add_backend = _add_backend,
! 550: .remove_backend = _remove_backend,
! 551: .destroy = _destroy,
! 552: },
! 553: .backends = linked_list_create(),
! 554: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
! 555: );
! 556:
! 557: return &this->public;
! 558: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>