Annotation of embedaddon/strongswan/src/libcharon/sa/redirect_manager.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2015 Tobias Brunner
! 3: * HSR 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:
! 16: #include "redirect_manager.h"
! 17:
! 18: #include <collections/linked_list.h>
! 19: #include <threading/rwlock.h>
! 20: #include <bio/bio_reader.h>
! 21: #include <bio/bio_writer.h>
! 22:
! 23: typedef struct private_redirect_manager_t private_redirect_manager_t;
! 24:
! 25: /**
! 26: * Private data
! 27: */
! 28: struct private_redirect_manager_t {
! 29:
! 30: /**
! 31: * Public interface
! 32: */
! 33: redirect_manager_t public;
! 34:
! 35: /**
! 36: * Registered providers
! 37: */
! 38: linked_list_t *providers;
! 39:
! 40: /**
! 41: * Lock to access list of providers
! 42: */
! 43: rwlock_t *lock;
! 44: };
! 45:
! 46:
! 47: /**
! 48: * Gateway identify types
! 49: *
! 50: * The encoding is the same as that for corresponding ID payloads.
! 51: */
! 52: typedef enum {
! 53: /** IPv4 address of the VPN gateway */
! 54: GATEWAY_ID_TYPE_IPV4 = 1,
! 55: /** IPv6 address of the VPN gateway */
! 56: GATEWAY_ID_TYPE_IPV6 = 2,
! 57: /** FQDN of the VPN gateway */
! 58: GATEWAY_ID_TYPE_FQDN = 3,
! 59: } gateway_id_type_t;
! 60:
! 61: /**
! 62: * Mapping of gateway identity types to identity types
! 63: */
! 64: static id_type_t gateway_to_id_type(gateway_id_type_t type)
! 65: {
! 66: switch (type)
! 67: {
! 68: case GATEWAY_ID_TYPE_IPV4:
! 69: return ID_IPV4_ADDR;
! 70: case GATEWAY_ID_TYPE_IPV6:
! 71: return ID_IPV6_ADDR;
! 72: case GATEWAY_ID_TYPE_FQDN:
! 73: return ID_FQDN;
! 74: default:
! 75: return 0;
! 76: }
! 77: }
! 78:
! 79: /**
! 80: * Mapping of identity types to gateway identity types
! 81: */
! 82: static gateway_id_type_t id_type_to_gateway(id_type_t type)
! 83: {
! 84: switch (type)
! 85: {
! 86: case ID_IPV4_ADDR:
! 87: return GATEWAY_ID_TYPE_IPV4;
! 88: case ID_IPV6_ADDR:
! 89: return GATEWAY_ID_TYPE_IPV6;
! 90: case ID_FQDN:
! 91: return GATEWAY_ID_TYPE_FQDN;
! 92: default:
! 93: return 0;
! 94: }
! 95: }
! 96:
! 97: METHOD(redirect_manager_t, add_provider, void,
! 98: private_redirect_manager_t *this, redirect_provider_t *provider)
! 99: {
! 100: this->lock->write_lock(this->lock);
! 101: this->providers->insert_last(this->providers, provider);
! 102: this->lock->unlock(this->lock);
! 103: }
! 104:
! 105: METHOD(redirect_manager_t, remove_provider, void,
! 106: private_redirect_manager_t *this, redirect_provider_t *provider)
! 107: {
! 108: this->lock->write_lock(this->lock);
! 109: this->providers->remove(this->providers, provider, NULL);
! 110: this->lock->unlock(this->lock);
! 111: }
! 112:
! 113: /**
! 114: * Determine whether a client should be redirected using the callback with the
! 115: * given offset into the redirect_provider_t interface.
! 116: */
! 117: static bool should_redirect(private_redirect_manager_t *this, ike_sa_t *ike_sa,
! 118: identification_t **gateway, size_t offset)
! 119: {
! 120: enumerator_t *enumerator;
! 121: void *provider;
! 122: bool redirect = FALSE;
! 123:
! 124: this->lock->read_lock(this->lock);
! 125: enumerator = this->providers->create_enumerator(this->providers);
! 126: while (enumerator->enumerate(enumerator, &provider))
! 127: {
! 128: bool (**method)(void*,ike_sa_t*,identification_t**) = provider + offset;
! 129: if (*method && (*method)(provider, ike_sa, gateway))
! 130: {
! 131: if (*gateway && id_type_to_gateway((*gateway)->get_type(*gateway)))
! 132: {
! 133: redirect = TRUE;
! 134: break;
! 135: }
! 136: else
! 137: {
! 138: DBG1(DBG_CFG, "redirect provider returned invalid gateway ID");
! 139: DESTROY_IF(*gateway);
! 140: }
! 141: }
! 142: }
! 143: enumerator->destroy(enumerator);
! 144: this->lock->unlock(this->lock);
! 145: return redirect;
! 146: }
! 147:
! 148: METHOD(redirect_manager_t, redirect_on_init, bool,
! 149: private_redirect_manager_t *this, ike_sa_t *ike_sa,
! 150: identification_t **gateway)
! 151: {
! 152: return should_redirect(this, ike_sa, gateway,
! 153: offsetof(redirect_provider_t, redirect_on_init));
! 154: }
! 155:
! 156: METHOD(redirect_manager_t, redirect_on_auth, bool,
! 157: private_redirect_manager_t *this, ike_sa_t *ike_sa,
! 158: identification_t **gateway)
! 159: {
! 160: return should_redirect(this, ike_sa, gateway,
! 161: offsetof(redirect_provider_t, redirect_on_auth));
! 162: }
! 163:
! 164: METHOD(redirect_manager_t, destroy, void,
! 165: private_redirect_manager_t *this)
! 166: {
! 167: this->providers->destroy(this->providers);
! 168: this->lock->destroy(this->lock);
! 169: free(this);
! 170: }
! 171:
! 172: /*
! 173: * Described in header
! 174: */
! 175: redirect_manager_t *redirect_manager_create()
! 176: {
! 177: private_redirect_manager_t *this;
! 178:
! 179: INIT(this,
! 180: .public = {
! 181: .add_provider = _add_provider,
! 182: .remove_provider = _remove_provider,
! 183: .redirect_on_init = _redirect_on_init,
! 184: .redirect_on_auth = _redirect_on_auth,
! 185: .destroy = _destroy,
! 186: },
! 187: .providers = linked_list_create(),
! 188: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
! 189: );
! 190:
! 191: return &this->public;
! 192: }
! 193:
! 194: /*
! 195: * Encoding of a REDIRECT or REDIRECTED_FROM notify
! 196: *
! 197: 1 2 3
! 198: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
! 199: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 200: | Next Payload |C| RESERVED | Payload Length |
! 201: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 202: |Protocol ID(=0)| SPI Size (=0) | Notify Message Type |
! 203: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 204: | GW Ident Type | GW Ident Len | |
! 205: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~
! 206: ~ New Responder GW Identity ~
! 207: | |
! 208: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 209: | |
! 210: ~ Nonce Data ~
! 211: | |
! 212: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 213: */
! 214:
! 215: /*
! 216: * Described in header
! 217: */
! 218: chunk_t redirect_data_create(identification_t *gw, chunk_t nonce)
! 219: {
! 220: gateway_id_type_t type;
! 221: bio_writer_t *writer;
! 222: chunk_t data;
! 223:
! 224: type = id_type_to_gateway(gw->get_type(gw));
! 225: if (!type)
! 226: {
! 227: return chunk_empty;
! 228: }
! 229:
! 230: writer = bio_writer_create(0);
! 231: writer->write_uint8(writer, type);
! 232: writer->write_data8(writer, gw->get_encoding(gw));
! 233: if (nonce.ptr)
! 234: {
! 235: writer->write_data(writer, nonce);
! 236: }
! 237:
! 238: data = writer->extract_buf(writer);
! 239: writer->destroy(writer);
! 240: return data;
! 241: }
! 242:
! 243: /*
! 244: * Described in header
! 245: */
! 246: identification_t *redirect_data_parse(chunk_t data, chunk_t *nonce)
! 247: {
! 248: bio_reader_t *reader;
! 249: id_type_t id_type;
! 250: chunk_t gateway;
! 251: uint8_t type;
! 252:
! 253: reader = bio_reader_create(data);
! 254: if (!reader->read_uint8(reader, &type) ||
! 255: !reader->read_data8(reader, &gateway))
! 256: {
! 257: DBG1(DBG_ENC, "invalid REDIRECT notify data");
! 258: reader->destroy(reader);
! 259: return NULL;
! 260: }
! 261: id_type = gateway_to_id_type(type);
! 262: if (!id_type)
! 263: {
! 264: DBG1(DBG_ENC, "invalid gateway ID type (%d) in REDIRECT notify", type);
! 265: reader->destroy(reader);
! 266: return NULL;
! 267: }
! 268: if (nonce)
! 269: {
! 270: *nonce = chunk_clone(reader->peek(reader));
! 271: }
! 272: reader->destroy(reader);
! 273: return identification_create_from_encoding(id_type, gateway);
! 274: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>