Annotation of embedaddon/strongswan/src/libcharon/kernel/kernel_interface.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2019 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2010 Martin Willi
! 6: * Copyright (C) 2010 revosec AG
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify it
! 9: * under the terms of the GNU General Public License as published by the
! 10: * Free Software Foundation; either version 2 of the License, or (at your
! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 12: *
! 13: * This program is distributed in the hope that it will be useful, but
! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 16: * for more details.
! 17: */
! 18:
! 19: /*
! 20: * Copyright (c) 2012 Nanoteq Pty Ltd
! 21: *
! 22: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 23: * of this software and associated documentation files (the "Software"), to deal
! 24: * in the Software without restriction, including without limitation the rights
! 25: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 26: * copies of the Software, and to permit persons to whom the Software is
! 27: * furnished to do so, subject to the following conditions:
! 28: *
! 29: * The above copyright notice and this permission notice shall be included in
! 30: * all copies or substantial portions of the Software.
! 31: *
! 32: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 33: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 34: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 35: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 36: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 37: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 38: * THE SOFTWARE.
! 39: */
! 40:
! 41: #include "kernel_interface.h"
! 42:
! 43: #include <utils/debug.h>
! 44: #include <threading/mutex.h>
! 45: #include <collections/linked_list.h>
! 46: #include <collections/hashtable.h>
! 47: #include <collections/array.h>
! 48:
! 49: typedef struct private_kernel_interface_t private_kernel_interface_t;
! 50:
! 51: typedef struct kernel_algorithm_t kernel_algorithm_t;
! 52:
! 53: /**
! 54: * Mapping of IKE algorithms to kernel-specific algorithm identifiers
! 55: */
! 56: struct kernel_algorithm_t {
! 57:
! 58: /**
! 59: * Transform type of the algorithm
! 60: */
! 61: transform_type_t type;
! 62:
! 63: /**
! 64: * Identifier specified in IKE
! 65: */
! 66: uint16_t ike;
! 67:
! 68: /**
! 69: * Identifier as defined in pfkeyv2.h
! 70: */
! 71: uint16_t kernel;
! 72:
! 73: /**
! 74: * Name of the algorithm in linux crypto API
! 75: */
! 76: char *name;
! 77: };
! 78:
! 79: /**
! 80: * Private data of a kernel_interface_t object.
! 81: */
! 82: struct private_kernel_interface_t {
! 83:
! 84: /**
! 85: * Public part of kernel_interface_t object.
! 86: */
! 87: kernel_interface_t public;
! 88:
! 89: /**
! 90: * Registered IPsec constructor
! 91: */
! 92: kernel_ipsec_constructor_t ipsec_constructor;
! 93:
! 94: /**
! 95: * Registered net constructor
! 96: */
! 97: kernel_net_constructor_t net_constructor;
! 98:
! 99: /**
! 100: * ipsec interface
! 101: */
! 102: kernel_ipsec_t *ipsec;
! 103:
! 104: /**
! 105: * network interface
! 106: */
! 107: kernel_net_t *net;
! 108:
! 109: /**
! 110: * mutex for listeners
! 111: */
! 112: mutex_t *mutex;
! 113:
! 114: /**
! 115: * list of registered listeners
! 116: */
! 117: linked_list_t *listeners;
! 118:
! 119: /**
! 120: * Reqid entries indexed by reqids
! 121: */
! 122: hashtable_t *reqids;
! 123:
! 124: /**
! 125: * Reqid entries indexed by traffic selectors
! 126: */
! 127: hashtable_t *reqids_by_ts;
! 128:
! 129: /**
! 130: * Previously used reqids that have been released
! 131: */
! 132: array_t *released_reqids;
! 133:
! 134: /**
! 135: * mutex for algorithm mappings
! 136: */
! 137: mutex_t *mutex_algs;
! 138:
! 139: /**
! 140: * List of algorithm mappings (kernel_algorithm_t*)
! 141: */
! 142: linked_list_t *algorithms;
! 143:
! 144: /**
! 145: * List of interface names to include or exclude (char*), NULL if interfaces
! 146: * are not filtered
! 147: */
! 148: linked_list_t *ifaces_filter;
! 149:
! 150: /**
! 151: * TRUE to exclude interfaces listed in ifaces_filter, FALSE to consider
! 152: * only those listed there
! 153: */
! 154: bool ifaces_exclude;
! 155: };
! 156:
! 157: METHOD(kernel_interface_t, get_features, kernel_feature_t,
! 158: private_kernel_interface_t *this)
! 159: {
! 160: kernel_feature_t features = 0;
! 161:
! 162: if (this->ipsec && this->ipsec->get_features)
! 163: {
! 164: features |= this->ipsec->get_features(this->ipsec);
! 165: }
! 166: if (this->net && this->net->get_features)
! 167: {
! 168: features |= this->net->get_features(this->net);
! 169: }
! 170: return features;
! 171: }
! 172:
! 173: METHOD(kernel_interface_t, get_spi, status_t,
! 174: private_kernel_interface_t *this, host_t *src, host_t *dst,
! 175: uint8_t protocol, uint32_t *spi)
! 176: {
! 177: if (!this->ipsec)
! 178: {
! 179: return NOT_SUPPORTED;
! 180: }
! 181: return this->ipsec->get_spi(this->ipsec, src, dst, protocol, spi);
! 182: }
! 183:
! 184: METHOD(kernel_interface_t, get_cpi, status_t,
! 185: private_kernel_interface_t *this, host_t *src, host_t *dst,
! 186: uint16_t *cpi)
! 187: {
! 188: if (!this->ipsec)
! 189: {
! 190: return NOT_SUPPORTED;
! 191: }
! 192: return this->ipsec->get_cpi(this->ipsec, src, dst, cpi);
! 193: }
! 194:
! 195: /**
! 196: * Reqid mapping entry
! 197: */
! 198: typedef struct {
! 199: /** allocated reqid */
! 200: uint32_t reqid;
! 201: /** references to this entry */
! 202: u_int refs;
! 203: /** inbound mark used for SA */
! 204: mark_t mark_in;
! 205: /** outbound mark used for SA */
! 206: mark_t mark_out;
! 207: /** inbound interface ID used for SA */
! 208: uint32_t if_id_in;
! 209: /** outbound interface ID used for SA */
! 210: uint32_t if_id_out;
! 211: /** local traffic selectors */
! 212: array_t *local;
! 213: /** remote traffic selectors */
! 214: array_t *remote;
! 215: } reqid_entry_t;
! 216:
! 217: /**
! 218: * Destroy a reqid mapping entry
! 219: */
! 220: static void reqid_entry_destroy(reqid_entry_t *entry)
! 221: {
! 222: array_destroy_offset(entry->local, offsetof(traffic_selector_t, destroy));
! 223: array_destroy_offset(entry->remote, offsetof(traffic_selector_t, destroy));
! 224: free(entry);
! 225: }
! 226:
! 227: /**
! 228: * Hashtable hash function for reqid entries using reqid as key
! 229: */
! 230: static u_int hash_reqid(reqid_entry_t *entry)
! 231: {
! 232: return chunk_hash_inc(chunk_from_thing(entry->reqid),
! 233: chunk_hash_inc(chunk_from_thing(entry->mark_in),
! 234: chunk_hash_inc(chunk_from_thing(entry->mark_out),
! 235: chunk_hash_inc(chunk_from_thing(entry->if_id_in),
! 236: chunk_hash(chunk_from_thing(entry->if_id_out))))));
! 237: }
! 238:
! 239: /**
! 240: * Hashtable equals function for reqid entries using reqid as key
! 241: */
! 242: static bool equals_reqid(reqid_entry_t *a, reqid_entry_t *b)
! 243: {
! 244: return a->reqid == b->reqid &&
! 245: a->mark_in.value == b->mark_in.value &&
! 246: a->mark_in.mask == b->mark_in.mask &&
! 247: a->mark_out.value == b->mark_out.value &&
! 248: a->mark_out.mask == b->mark_out.mask &&
! 249: a->if_id_in == b->if_id_in &&
! 250: a->if_id_out == b->if_id_out;
! 251: }
! 252:
! 253: /**
! 254: * Hash an array of traffic selectors
! 255: */
! 256: static u_int hash_ts_array(array_t *array, u_int hash)
! 257: {
! 258: enumerator_t *enumerator;
! 259: traffic_selector_t *ts;
! 260:
! 261: enumerator = array_create_enumerator(array);
! 262: while (enumerator->enumerate(enumerator, &ts))
! 263: {
! 264: hash = ts->hash(ts, hash);
! 265: }
! 266: enumerator->destroy(enumerator);
! 267:
! 268: return hash;
! 269: }
! 270:
! 271: /**
! 272: * Hashtable hash function for reqid entries using traffic selectors as key
! 273: */
! 274: static u_int hash_reqid_by_ts(reqid_entry_t *entry)
! 275: {
! 276: return hash_ts_array(entry->local, hash_ts_array(entry->remote,
! 277: chunk_hash_inc(chunk_from_thing(entry->mark_in),
! 278: chunk_hash_inc(chunk_from_thing(entry->mark_out),
! 279: chunk_hash_inc(chunk_from_thing(entry->if_id_in),
! 280: chunk_hash(chunk_from_thing(entry->if_id_out)))))));
! 281: }
! 282:
! 283: /**
! 284: * Compare two array with traffic selectors for equality
! 285: */
! 286: static bool ts_array_equals(array_t *a, array_t *b)
! 287: {
! 288: traffic_selector_t *tsa, *tsb;
! 289: enumerator_t *ae, *be;
! 290: bool equal = TRUE;
! 291:
! 292: if (array_count(a) != array_count(b))
! 293: {
! 294: return FALSE;
! 295: }
! 296:
! 297: ae = array_create_enumerator(a);
! 298: be = array_create_enumerator(b);
! 299: while (equal && ae->enumerate(ae, &tsa) && be->enumerate(be, &tsb))
! 300: {
! 301: equal = tsa->equals(tsa, tsb);
! 302: }
! 303: ae->destroy(ae);
! 304: be->destroy(be);
! 305:
! 306: return equal;
! 307: }
! 308:
! 309: /**
! 310: * Hashtable equals function for reqid entries using traffic selectors as key
! 311: */
! 312: static bool equals_reqid_by_ts(reqid_entry_t *a, reqid_entry_t *b)
! 313: {
! 314: return ts_array_equals(a->local, b->local) &&
! 315: ts_array_equals(a->remote, b->remote) &&
! 316: a->mark_in.value == b->mark_in.value &&
! 317: a->mark_in.mask == b->mark_in.mask &&
! 318: a->mark_out.value == b->mark_out.value &&
! 319: a->mark_out.mask == b->mark_out.mask &&
! 320: a->if_id_in == b->if_id_in &&
! 321: a->if_id_out == b->if_id_out;
! 322: }
! 323:
! 324: /**
! 325: * Create an array from copied traffic selector list items
! 326: */
! 327: static array_t *array_from_ts_list(linked_list_t *list)
! 328: {
! 329: enumerator_t *enumerator;
! 330: traffic_selector_t *ts;
! 331: array_t *array;
! 332:
! 333: array = array_create(0, 0);
! 334:
! 335: enumerator = list->create_enumerator(list);
! 336: while (enumerator->enumerate(enumerator, &ts))
! 337: {
! 338: array_insert(array, ARRAY_TAIL, ts->clone(ts));
! 339: }
! 340: enumerator->destroy(enumerator);
! 341:
! 342: return array;
! 343: }
! 344:
! 345: METHOD(kernel_interface_t, alloc_reqid, status_t,
! 346: private_kernel_interface_t *this,
! 347: linked_list_t *local_ts, linked_list_t *remote_ts,
! 348: mark_t mark_in, mark_t mark_out, uint32_t if_id_in, uint32_t if_id_out,
! 349: uint32_t *reqid)
! 350: {
! 351: static uint32_t counter = 0;
! 352: reqid_entry_t *entry = NULL, *tmpl;
! 353: status_t status = SUCCESS;
! 354:
! 355: INIT(tmpl,
! 356: .local = array_from_ts_list(local_ts),
! 357: .remote = array_from_ts_list(remote_ts),
! 358: .mark_in = mark_in,
! 359: .mark_out = mark_out,
! 360: .if_id_in = if_id_in,
! 361: .if_id_out = if_id_out,
! 362: .reqid = *reqid,
! 363: );
! 364:
! 365: this->mutex->lock(this->mutex);
! 366: if (tmpl->reqid)
! 367: {
! 368: /* search by reqid if given */
! 369: entry = this->reqids->get(this->reqids, tmpl);
! 370: }
! 371: if (entry)
! 372: {
! 373: /* we don't require a traffic selector match for explicit reqids,
! 374: * as we want to reuse a reqid for trap-triggered policies that
! 375: * got narrowed during negotiation. */
! 376: reqid_entry_destroy(tmpl);
! 377: }
! 378: else
! 379: {
! 380: /* search by traffic selectors */
! 381: entry = this->reqids_by_ts->get(this->reqids_by_ts, tmpl);
! 382: if (entry)
! 383: {
! 384: reqid_entry_destroy(tmpl);
! 385: }
! 386: else
! 387: {
! 388: /* none found, create a new entry, allocating a reqid */
! 389: entry = tmpl;
! 390: if (!array_remove(this->released_reqids, ARRAY_HEAD, &entry->reqid))
! 391: {
! 392: entry->reqid = ++counter;
! 393: }
! 394: this->reqids_by_ts->put(this->reqids_by_ts, entry, entry);
! 395: this->reqids->put(this->reqids, entry, entry);
! 396: }
! 397: *reqid = entry->reqid;
! 398: }
! 399: entry->refs++;
! 400: this->mutex->unlock(this->mutex);
! 401:
! 402: return status;
! 403: }
! 404:
! 405: METHOD(kernel_interface_t, release_reqid, status_t,
! 406: private_kernel_interface_t *this, uint32_t reqid,
! 407: mark_t mark_in, mark_t mark_out, uint32_t if_id_in, uint32_t if_id_out)
! 408: {
! 409: reqid_entry_t *entry, tmpl = {
! 410: .reqid = reqid,
! 411: .mark_in = mark_in,
! 412: .mark_out = mark_out,
! 413: .if_id_in = if_id_in,
! 414: .if_id_out = if_id_out,
! 415: };
! 416:
! 417: this->mutex->lock(this->mutex);
! 418: entry = this->reqids->remove(this->reqids, &tmpl);
! 419: if (entry)
! 420: {
! 421: if (--entry->refs == 0)
! 422: {
! 423: array_insert_create_value(&this->released_reqids, sizeof(uint32_t),
! 424: ARRAY_TAIL, &entry->reqid);
! 425: entry = this->reqids_by_ts->remove(this->reqids_by_ts, entry);
! 426: if (entry)
! 427: {
! 428: reqid_entry_destroy(entry);
! 429: }
! 430: }
! 431: else
! 432: {
! 433: this->reqids->put(this->reqids, entry, entry);
! 434: }
! 435: }
! 436: this->mutex->unlock(this->mutex);
! 437:
! 438: if (entry)
! 439: {
! 440: return SUCCESS;
! 441: }
! 442: return NOT_FOUND;
! 443: }
! 444:
! 445: METHOD(kernel_interface_t, add_sa, status_t,
! 446: private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
! 447: kernel_ipsec_add_sa_t *data)
! 448: {
! 449: if (!this->ipsec)
! 450: {
! 451: return NOT_SUPPORTED;
! 452: }
! 453: return this->ipsec->add_sa(this->ipsec, id, data);
! 454: }
! 455:
! 456: METHOD(kernel_interface_t, update_sa, status_t,
! 457: private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
! 458: kernel_ipsec_update_sa_t *data)
! 459: {
! 460: if (!this->ipsec)
! 461: {
! 462: return NOT_SUPPORTED;
! 463: }
! 464: return this->ipsec->update_sa(this->ipsec, id, data);
! 465: }
! 466:
! 467: METHOD(kernel_interface_t, query_sa, status_t,
! 468: private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
! 469: kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
! 470: time_t *time)
! 471: {
! 472: if (!this->ipsec)
! 473: {
! 474: return NOT_SUPPORTED;
! 475: }
! 476: return this->ipsec->query_sa(this->ipsec, id, data, bytes, packets, time);
! 477: }
! 478:
! 479: METHOD(kernel_interface_t, del_sa, status_t,
! 480: private_kernel_interface_t *this, kernel_ipsec_sa_id_t *id,
! 481: kernel_ipsec_del_sa_t *data)
! 482: {
! 483: if (!this->ipsec)
! 484: {
! 485: return NOT_SUPPORTED;
! 486: }
! 487: return this->ipsec->del_sa(this->ipsec, id, data);
! 488: }
! 489:
! 490: METHOD(kernel_interface_t, flush_sas, status_t,
! 491: private_kernel_interface_t *this)
! 492: {
! 493: if (!this->ipsec)
! 494: {
! 495: return NOT_SUPPORTED;
! 496: }
! 497: return this->ipsec->flush_sas(this->ipsec);
! 498: }
! 499:
! 500: METHOD(kernel_interface_t, add_policy, status_t,
! 501: private_kernel_interface_t *this, kernel_ipsec_policy_id_t *id,
! 502: kernel_ipsec_manage_policy_t *data)
! 503: {
! 504: if (!this->ipsec)
! 505: {
! 506: return NOT_SUPPORTED;
! 507: }
! 508: return this->ipsec->add_policy(this->ipsec, id, data);
! 509: }
! 510:
! 511: METHOD(kernel_interface_t, query_policy, status_t,
! 512: private_kernel_interface_t *this, kernel_ipsec_policy_id_t *id,
! 513: kernel_ipsec_query_policy_t *data, time_t *use_time)
! 514: {
! 515: if (!this->ipsec)
! 516: {
! 517: return NOT_SUPPORTED;
! 518: }
! 519: return this->ipsec->query_policy(this->ipsec, id, data, use_time);
! 520: }
! 521:
! 522: METHOD(kernel_interface_t, del_policy, status_t,
! 523: private_kernel_interface_t *this, kernel_ipsec_policy_id_t *id,
! 524: kernel_ipsec_manage_policy_t *data)
! 525: {
! 526: if (!this->ipsec)
! 527: {
! 528: return NOT_SUPPORTED;
! 529: }
! 530: return this->ipsec->del_policy(this->ipsec, id, data);
! 531: }
! 532:
! 533: METHOD(kernel_interface_t, flush_policies, status_t,
! 534: private_kernel_interface_t *this)
! 535: {
! 536: if (!this->ipsec)
! 537: {
! 538: return NOT_SUPPORTED;
! 539: }
! 540: return this->ipsec->flush_policies(this->ipsec);
! 541: }
! 542:
! 543: METHOD(kernel_interface_t, get_source_addr, host_t*,
! 544: private_kernel_interface_t *this, host_t *dest, host_t *src)
! 545: {
! 546: if (!this->net)
! 547: {
! 548: return NULL;
! 549: }
! 550: return this->net->get_source_addr(this->net, dest, src);
! 551: }
! 552:
! 553: METHOD(kernel_interface_t, get_nexthop, host_t*,
! 554: private_kernel_interface_t *this, host_t *dest, int prefix, host_t *src,
! 555: char **iface)
! 556: {
! 557: if (!this->net)
! 558: {
! 559: return NULL;
! 560: }
! 561: return this->net->get_nexthop(this->net, dest, prefix, src, iface);
! 562: }
! 563:
! 564: METHOD(kernel_interface_t, get_interface, bool,
! 565: private_kernel_interface_t *this, host_t *host, char **name)
! 566: {
! 567: if (!this->net)
! 568: {
! 569: return NULL;
! 570: }
! 571: return this->net->get_interface(this->net, host, name);
! 572: }
! 573:
! 574: METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*,
! 575: private_kernel_interface_t *this, kernel_address_type_t which)
! 576: {
! 577: if (!this->net)
! 578: {
! 579: return enumerator_create_empty();
! 580: }
! 581: return this->net->create_address_enumerator(this->net, which);
! 582: }
! 583:
! 584: METHOD(kernel_interface_t, create_local_subnet_enumerator, enumerator_t*,
! 585: private_kernel_interface_t *this)
! 586: {
! 587: if (!this->net || !this->net->create_local_subnet_enumerator)
! 588: {
! 589: return enumerator_create_empty();
! 590: }
! 591: return this->net->create_local_subnet_enumerator(this->net);
! 592: }
! 593:
! 594: METHOD(kernel_interface_t, add_ip, status_t,
! 595: private_kernel_interface_t *this, host_t *virtual_ip, int prefix,
! 596: char *iface)
! 597: {
! 598: if (!this->net)
! 599: {
! 600: return NOT_SUPPORTED;
! 601: }
! 602: return this->net->add_ip(this->net, virtual_ip, prefix, iface);
! 603: }
! 604:
! 605: METHOD(kernel_interface_t, del_ip, status_t,
! 606: private_kernel_interface_t *this, host_t *virtual_ip, int prefix, bool wait)
! 607: {
! 608: if (!this->net)
! 609: {
! 610: return NOT_SUPPORTED;
! 611: }
! 612: return this->net->del_ip(this->net, virtual_ip, prefix, wait);
! 613: }
! 614:
! 615: METHOD(kernel_interface_t, add_route, status_t,
! 616: private_kernel_interface_t *this, chunk_t dst_net,
! 617: uint8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name,
! 618: bool pass)
! 619: {
! 620: if (!this->net)
! 621: {
! 622: return NOT_SUPPORTED;
! 623: }
! 624: return this->net->add_route(this->net, dst_net, prefixlen, gateway,
! 625: src_ip, if_name, pass);
! 626: }
! 627:
! 628: METHOD(kernel_interface_t, del_route, status_t,
! 629: private_kernel_interface_t *this, chunk_t dst_net,
! 630: uint8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name,
! 631: bool pass)
! 632: {
! 633: if (!this->net)
! 634: {
! 635: return NOT_SUPPORTED;
! 636: }
! 637: return this->net->del_route(this->net, dst_net, prefixlen, gateway,
! 638: src_ip, if_name, pass);
! 639: }
! 640:
! 641: METHOD(kernel_interface_t, bypass_socket, bool,
! 642: private_kernel_interface_t *this, int fd, int family)
! 643: {
! 644: if (!this->ipsec)
! 645: {
! 646: return FALSE;
! 647: }
! 648: return this->ipsec->bypass_socket(this->ipsec, fd, family);
! 649: }
! 650:
! 651: METHOD(kernel_interface_t, enable_udp_decap, bool,
! 652: private_kernel_interface_t *this, int fd, int family, uint16_t port)
! 653: {
! 654: if (!this->ipsec)
! 655: {
! 656: return FALSE;
! 657: }
! 658: return this->ipsec->enable_udp_decap(this->ipsec, fd, family, port);
! 659: }
! 660:
! 661: METHOD(kernel_interface_t, is_interface_usable, bool,
! 662: private_kernel_interface_t *this, const char *iface)
! 663: {
! 664: if (!this->ifaces_filter)
! 665: {
! 666: return TRUE;
! 667: }
! 668: return this->ifaces_filter->find_first(this->ifaces_filter,
! 669: linked_list_match_str, NULL, iface) != this->ifaces_exclude;
! 670: }
! 671:
! 672: METHOD(kernel_interface_t, all_interfaces_usable, bool,
! 673: private_kernel_interface_t *this)
! 674: {
! 675: return !this->ifaces_filter;
! 676: }
! 677:
! 678: METHOD(kernel_interface_t, get_address_by_ts, status_t,
! 679: private_kernel_interface_t *this, traffic_selector_t *ts,
! 680: host_t **ip, bool *vip)
! 681: {
! 682: enumerator_t *addrs;
! 683: host_t *host;
! 684: int family;
! 685: bool found = FALSE;
! 686:
! 687: DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts);
! 688:
! 689: /* if we have a family which includes localhost, we do not
! 690: * search for an IP, we use the default */
! 691: family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
! 692:
! 693: if (family == AF_INET)
! 694: {
! 695: host = host_create_from_string("127.0.0.1", 0);
! 696: }
! 697: else
! 698: {
! 699: host = host_create_from_string("::1", 0);
! 700: }
! 701:
! 702: if (ts->includes(ts, host))
! 703: {
! 704: *ip = host_create_any(family);
! 705: if (vip)
! 706: {
! 707: *vip = FALSE;
! 708: }
! 709: host->destroy(host);
! 710: DBG2(DBG_KNL, "using host %H", *ip);
! 711: return SUCCESS;
! 712: }
! 713: host->destroy(host);
! 714:
! 715: /* try virtual IPs only first (on all interfaces) */
! 716: addrs = create_address_enumerator(this,
! 717: ADDR_TYPE_ALL ^ ADDR_TYPE_REGULAR);
! 718: while (addrs->enumerate(addrs, (void**)&host))
! 719: {
! 720: if (ts->includes(ts, host))
! 721: {
! 722: found = TRUE;
! 723: *ip = host->clone(host);
! 724: if (vip)
! 725: {
! 726: *vip = TRUE;
! 727: }
! 728: break;
! 729: }
! 730: }
! 731: addrs->destroy(addrs);
! 732:
! 733: if (!found)
! 734: { /* then try the regular addresses (on all interfaces) */
! 735: addrs = create_address_enumerator(this,
! 736: ADDR_TYPE_ALL ^ ADDR_TYPE_VIRTUAL);
! 737: while (addrs->enumerate(addrs, (void**)&host))
! 738: {
! 739: if (ts->includes(ts, host))
! 740: {
! 741: found = TRUE;
! 742: *ip = host->clone(host);
! 743: if (vip)
! 744: {
! 745: *vip = FALSE;
! 746: }
! 747: break;
! 748: }
! 749: }
! 750: addrs->destroy(addrs);
! 751: }
! 752:
! 753: if (!found)
! 754: {
! 755: DBG2(DBG_KNL, "no local address found in traffic selector %R", ts);
! 756: return FAILED;
! 757: }
! 758:
! 759: DBG2(DBG_KNL, "using host %H", *ip);
! 760: return SUCCESS;
! 761: }
! 762:
! 763:
! 764: METHOD(kernel_interface_t, add_ipsec_interface, bool,
! 765: private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
! 766: {
! 767: if (!this->ipsec)
! 768: {
! 769: this->ipsec_constructor = constructor;
! 770: this->ipsec = constructor();
! 771: return this->ipsec != NULL;
! 772: }
! 773: return FALSE;
! 774: }
! 775:
! 776: METHOD(kernel_interface_t, remove_ipsec_interface, bool,
! 777: private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
! 778: {
! 779: if (constructor == this->ipsec_constructor && this->ipsec)
! 780: {
! 781: this->ipsec->destroy(this->ipsec);
! 782: this->ipsec = NULL;
! 783: return TRUE;
! 784: }
! 785: return FALSE;
! 786: }
! 787:
! 788: METHOD(kernel_interface_t, add_net_interface, bool,
! 789: private_kernel_interface_t *this, kernel_net_constructor_t constructor)
! 790: {
! 791: if (!this->net)
! 792: {
! 793: this->net_constructor = constructor;
! 794: this->net = constructor();
! 795: return this->net != NULL;
! 796: }
! 797: return FALSE;
! 798: }
! 799:
! 800: METHOD(kernel_interface_t, remove_net_interface, bool,
! 801: private_kernel_interface_t *this, kernel_net_constructor_t constructor)
! 802: {
! 803: if (constructor == this->net_constructor && this->net)
! 804: {
! 805: this->net->destroy(this->net);
! 806: this->net = NULL;
! 807: return TRUE;
! 808: }
! 809: return FALSE;
! 810: }
! 811:
! 812: METHOD(kernel_interface_t, add_listener, void,
! 813: private_kernel_interface_t *this, kernel_listener_t *listener)
! 814: {
! 815: this->mutex->lock(this->mutex);
! 816: this->listeners->insert_last(this->listeners, listener);
! 817: this->mutex->unlock(this->mutex);
! 818: }
! 819:
! 820: METHOD(kernel_interface_t, remove_listener, void,
! 821: private_kernel_interface_t *this, kernel_listener_t *listener)
! 822: {
! 823: this->mutex->lock(this->mutex);
! 824: this->listeners->remove(this->listeners, listener, NULL);
! 825: this->mutex->unlock(this->mutex);
! 826: }
! 827:
! 828: METHOD(kernel_interface_t, acquire, void,
! 829: private_kernel_interface_t *this, uint32_t reqid,
! 830: traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
! 831: {
! 832: kernel_listener_t *listener;
! 833: enumerator_t *enumerator;
! 834: this->mutex->lock(this->mutex);
! 835: enumerator = this->listeners->create_enumerator(this->listeners);
! 836: while (enumerator->enumerate(enumerator, &listener))
! 837: {
! 838: if (listener->acquire &&
! 839: !listener->acquire(listener, reqid, src_ts, dst_ts))
! 840: {
! 841: this->listeners->remove_at(this->listeners, enumerator);
! 842: }
! 843: }
! 844: enumerator->destroy(enumerator);
! 845: this->mutex->unlock(this->mutex);
! 846: }
! 847:
! 848: METHOD(kernel_interface_t, expire, void,
! 849: private_kernel_interface_t *this, uint8_t protocol, uint32_t spi,
! 850: host_t *dst, bool hard)
! 851: {
! 852: kernel_listener_t *listener;
! 853: enumerator_t *enumerator;
! 854:
! 855: this->mutex->lock(this->mutex);
! 856: enumerator = this->listeners->create_enumerator(this->listeners);
! 857: while (enumerator->enumerate(enumerator, &listener))
! 858: {
! 859: if (listener->expire &&
! 860: !listener->expire(listener, protocol, spi, dst, hard))
! 861: {
! 862: this->listeners->remove_at(this->listeners, enumerator);
! 863: }
! 864: }
! 865: enumerator->destroy(enumerator);
! 866: this->mutex->unlock(this->mutex);
! 867: }
! 868:
! 869: METHOD(kernel_interface_t, mapping, void,
! 870: private_kernel_interface_t *this, uint8_t protocol, uint32_t spi,
! 871: host_t *dst, host_t *remote)
! 872: {
! 873: kernel_listener_t *listener;
! 874: enumerator_t *enumerator;
! 875:
! 876: this->mutex->lock(this->mutex);
! 877: enumerator = this->listeners->create_enumerator(this->listeners);
! 878: while (enumerator->enumerate(enumerator, &listener))
! 879: {
! 880: if (listener->mapping &&
! 881: !listener->mapping(listener, protocol, spi, dst, remote))
! 882: {
! 883: this->listeners->remove_at(this->listeners, enumerator);
! 884: }
! 885: }
! 886: enumerator->destroy(enumerator);
! 887: this->mutex->unlock(this->mutex);
! 888: }
! 889:
! 890: METHOD(kernel_interface_t, migrate, void,
! 891: private_kernel_interface_t *this, uint32_t reqid,
! 892: traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
! 893: policy_dir_t direction, host_t *local, host_t *remote)
! 894: {
! 895: kernel_listener_t *listener;
! 896: enumerator_t *enumerator;
! 897: this->mutex->lock(this->mutex);
! 898: enumerator = this->listeners->create_enumerator(this->listeners);
! 899: while (enumerator->enumerate(enumerator, &listener))
! 900: {
! 901: if (listener->migrate &&
! 902: !listener->migrate(listener, reqid, src_ts, dst_ts, direction,
! 903: local, remote))
! 904: {
! 905: this->listeners->remove_at(this->listeners, enumerator);
! 906: }
! 907: }
! 908: enumerator->destroy(enumerator);
! 909: this->mutex->unlock(this->mutex);
! 910: }
! 911:
! 912: static bool call_roam(kernel_listener_t *listener, bool *roam)
! 913: {
! 914: return listener->roam && !listener->roam(listener, *roam);
! 915: }
! 916:
! 917: METHOD(kernel_interface_t, roam, void,
! 918: private_kernel_interface_t *this, bool address)
! 919: {
! 920: this->mutex->lock(this->mutex);
! 921: this->listeners->remove(this->listeners, &address, (void*)call_roam);
! 922: this->mutex->unlock(this->mutex);
! 923: }
! 924:
! 925: METHOD(kernel_interface_t, tun, void,
! 926: private_kernel_interface_t *this, tun_device_t *tun, bool created)
! 927: {
! 928: kernel_listener_t *listener;
! 929: enumerator_t *enumerator;
! 930: this->mutex->lock(this->mutex);
! 931: enumerator = this->listeners->create_enumerator(this->listeners);
! 932: while (enumerator->enumerate(enumerator, &listener))
! 933: {
! 934: if (listener->tun &&
! 935: !listener->tun(listener, tun, created))
! 936: {
! 937: this->listeners->remove_at(this->listeners, enumerator);
! 938: }
! 939: }
! 940: enumerator->destroy(enumerator);
! 941: this->mutex->unlock(this->mutex);
! 942: }
! 943:
! 944: METHOD(kernel_interface_t, register_algorithm, void,
! 945: private_kernel_interface_t *this, uint16_t alg_id, transform_type_t type,
! 946: uint16_t kernel_id, char *kernel_name)
! 947: {
! 948: kernel_algorithm_t *algorithm;
! 949:
! 950: INIT(algorithm,
! 951: .type = type,
! 952: .ike = alg_id,
! 953: .kernel = kernel_id,
! 954: .name = strdup(kernel_name),
! 955: );
! 956:
! 957: this->mutex_algs->lock(this->mutex_algs);
! 958: this->algorithms->insert_first(this->algorithms, algorithm);
! 959: this->mutex_algs->unlock(this->mutex_algs);
! 960: }
! 961:
! 962: METHOD(kernel_interface_t, lookup_algorithm, bool,
! 963: private_kernel_interface_t *this, uint16_t alg_id, transform_type_t type,
! 964: uint16_t *kernel_id, char **kernel_name)
! 965: {
! 966: kernel_algorithm_t *algorithm;
! 967: enumerator_t *enumerator;
! 968: bool found = FALSE;
! 969:
! 970: this->mutex_algs->lock(this->mutex_algs);
! 971: enumerator = this->algorithms->create_enumerator(this->algorithms);
! 972: while (enumerator->enumerate(enumerator, &algorithm))
! 973: {
! 974: if (algorithm->type == type && algorithm->ike == alg_id)
! 975: {
! 976: if (kernel_id)
! 977: {
! 978: *kernel_id = algorithm->kernel;
! 979: }
! 980: if (kernel_name)
! 981: {
! 982: *kernel_name = algorithm->name;
! 983: }
! 984: found = TRUE;
! 985: break;
! 986: }
! 987: }
! 988: enumerator->destroy(enumerator);
! 989: this->mutex_algs->unlock(this->mutex_algs);
! 990: return found;
! 991: }
! 992:
! 993: METHOD(kernel_interface_t, destroy, void,
! 994: private_kernel_interface_t *this)
! 995: {
! 996: kernel_algorithm_t *algorithm;
! 997:
! 998: while (this->algorithms->remove_first(this->algorithms,
! 999: (void**)&algorithm) == SUCCESS)
! 1000: {
! 1001: free(algorithm->name);
! 1002: free(algorithm);
! 1003: }
! 1004: this->algorithms->destroy(this->algorithms);
! 1005: this->mutex_algs->destroy(this->mutex_algs);
! 1006: DESTROY_IF(this->ipsec);
! 1007: DESTROY_IF(this->net);
! 1008: DESTROY_FUNCTION_IF(this->ifaces_filter, (void*)free);
! 1009: this->reqids->destroy(this->reqids);
! 1010: this->reqids_by_ts->destroy(this->reqids_by_ts);
! 1011: array_destroy(this->released_reqids);
! 1012: this->listeners->destroy(this->listeners);
! 1013: this->mutex->destroy(this->mutex);
! 1014: free(this);
! 1015: }
! 1016:
! 1017: /*
! 1018: * Described in header-file
! 1019: */
! 1020: kernel_interface_t *kernel_interface_create()
! 1021: {
! 1022: private_kernel_interface_t *this;
! 1023: char *ifaces;
! 1024:
! 1025: INIT(this,
! 1026: .public = {
! 1027: .get_features = _get_features,
! 1028: .get_spi = _get_spi,
! 1029: .get_cpi = _get_cpi,
! 1030: .alloc_reqid = _alloc_reqid,
! 1031: .release_reqid = _release_reqid,
! 1032: .add_sa = _add_sa,
! 1033: .update_sa = _update_sa,
! 1034: .query_sa = _query_sa,
! 1035: .del_sa = _del_sa,
! 1036: .flush_sas = _flush_sas,
! 1037: .add_policy = _add_policy,
! 1038: .query_policy = _query_policy,
! 1039: .del_policy = _del_policy,
! 1040: .flush_policies = _flush_policies,
! 1041: .get_source_addr = _get_source_addr,
! 1042: .get_nexthop = _get_nexthop,
! 1043: .get_interface = _get_interface,
! 1044: .create_address_enumerator = _create_address_enumerator,
! 1045: .create_local_subnet_enumerator = _create_local_subnet_enumerator,
! 1046: .add_ip = _add_ip,
! 1047: .del_ip = _del_ip,
! 1048: .add_route = _add_route,
! 1049: .del_route = _del_route,
! 1050: .bypass_socket = _bypass_socket,
! 1051: .enable_udp_decap = _enable_udp_decap,
! 1052:
! 1053: .is_interface_usable = _is_interface_usable,
! 1054: .all_interfaces_usable = _all_interfaces_usable,
! 1055: .get_address_by_ts = _get_address_by_ts,
! 1056: .add_ipsec_interface = _add_ipsec_interface,
! 1057: .remove_ipsec_interface = _remove_ipsec_interface,
! 1058: .add_net_interface = _add_net_interface,
! 1059: .remove_net_interface = _remove_net_interface,
! 1060:
! 1061: .add_listener = _add_listener,
! 1062: .remove_listener = _remove_listener,
! 1063: .register_algorithm = _register_algorithm,
! 1064: .lookup_algorithm = _lookup_algorithm,
! 1065: .acquire = _acquire,
! 1066: .expire = _expire,
! 1067: .mapping = _mapping,
! 1068: .migrate = _migrate,
! 1069: .roam = _roam,
! 1070: .tun = _tun,
! 1071: .destroy = _destroy,
! 1072: },
! 1073: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
! 1074: .listeners = linked_list_create(),
! 1075: .mutex_algs = mutex_create(MUTEX_TYPE_DEFAULT),
! 1076: .algorithms = linked_list_create(),
! 1077: .reqids = hashtable_create((hashtable_hash_t)hash_reqid,
! 1078: (hashtable_equals_t)equals_reqid, 8),
! 1079: .reqids_by_ts = hashtable_create((hashtable_hash_t)hash_reqid_by_ts,
! 1080: (hashtable_equals_t)equals_reqid_by_ts, 8),
! 1081: );
! 1082:
! 1083: ifaces = lib->settings->get_str(lib->settings,
! 1084: "%s.interfaces_use", NULL, lib->ns);
! 1085: if (!ifaces)
! 1086: {
! 1087: this->ifaces_exclude = TRUE;
! 1088: ifaces = lib->settings->get_str(lib->settings,
! 1089: "%s.interfaces_ignore", NULL, lib->ns);
! 1090: }
! 1091: if (ifaces)
! 1092: {
! 1093: enumerator_t *enumerator;
! 1094: char *iface;
! 1095:
! 1096: enumerator = enumerator_create_token(ifaces, ",", " ");
! 1097: while (enumerator->enumerate(enumerator, &iface))
! 1098: {
! 1099: if (!this->ifaces_filter)
! 1100: {
! 1101: this->ifaces_filter = linked_list_create();
! 1102: }
! 1103: this->ifaces_filter->insert_last(this->ifaces_filter,
! 1104: strdup(iface));
! 1105: }
! 1106: enumerator->destroy(enumerator);
! 1107: }
! 1108:
! 1109: return &this->public;
! 1110: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>