diff options
Diffstat (limited to 'src/charon/sa/child_sa.c')
-rw-r--r-- | src/charon/sa/child_sa.c | 1112 |
1 files changed, 508 insertions, 604 deletions
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 7c4b398cf..d7a63d5e8 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2006-2008 Tobias Brunner - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -15,7 +15,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_sa.c 4358 2008-09-25 13:56:23Z tobias $ + * $Id: child_sa.c 4665 2008-11-17 00:01:34Z andreas $ */ #define _GNU_SOURCE @@ -23,36 +23,21 @@ #include <stdio.h> #include <string.h> +#include <time.h> #include <daemon.h> -ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DELETING, +ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING, "CREATED", "ROUTED", + "INSTALLING", "INSTALLED", + "UPDATING", "REKEYING", "DELETING", + "DESTROYING", ); -typedef struct sa_policy_t sa_policy_t; - -/** - * Struct used to store information for a policy. This - * is needed since we must provide all this information - * for deleting a policy... - */ -struct sa_policy_t { - /** - * Traffic selector for us - */ - traffic_selector_t *my_ts; - - /** - * Traffic selector for other - */ - traffic_selector_t *other_ts; -}; - typedef struct private_child_sa_t private_child_sa_t; /** @@ -64,83 +49,77 @@ struct private_child_sa_t { */ child_sa_t public; - struct { - /** address of peer */ - host_t *addr; - /** id of peer */ - identification_t *id; - /** actual used SPI, 0 if unused */ - u_int32_t spi; - /** Compression Parameter Index (CPI) used, 0 if unused */ - u_int16_t cpi; - } me, other; - /** - * Allocated SPI for a ESP proposal candidates + * address of us */ - u_int32_t alloc_esp_spi; + host_t *my_addr; /** - * Allocated SPI for a AH proposal candidates + * address of remote */ - u_int32_t alloc_ah_spi; + host_t *other_addr; /** - * Protocol used to protect this SA, ESP|AH + * our actually used SPI, 0 if unused */ - protocol_id_t protocol; + u_int32_t my_spi; /** - * List containing sa_policy_t objects + * others used SPI, 0 if unused */ - linked_list_t *policies; + u_int32_t other_spi; /** - * Seperate list for local traffic selectors + * our Compression Parameter Index (CPI) used, 0 if unused */ - linked_list_t *my_ts; + u_int16_t my_cpi; /** - * Seperate list for remote traffic selectors + * others Compression Parameter Index (CPI) used, 0 if unused */ - linked_list_t *other_ts; + u_int16_t other_cpi; /** - * reqid used for this child_sa + * List for local traffic selectors */ - u_int32_t reqid; + linked_list_t *my_ts; /** - * encryption algorithm used for this SA + * List for remote traffic selectors */ - u_int16_t enc_alg; + linked_list_t *other_ts; /** - * key size of enc_alg + * Allocated SPI for a ESP proposal candidates */ - u_int16_t enc_size; + u_int32_t alloc_esp_spi; /** - * integrity protection algorithm used for this SA + * Allocated SPI for a AH proposal candidates */ - u_int16_t int_alg; + u_int32_t alloc_ah_spi; /** - * key size of int_alg + * Protocol used to protect this SA, ESP|AH */ - u_int16_t int_size; + protocol_id_t protocol; /** - * time, on which SA was installed + * reqid used for this child_sa */ - time_t install_time; + u_int32_t reqid; /** - * absolute time when rekeying is sceduled + * absolute time when rekeying is scheduled */ time_t rekey_time; /** + * absolute time when the SA expires + */ + time_t expire_time; + + /** * state of the CHILD_SA */ child_sa_state_t state; @@ -166,23 +145,18 @@ struct private_child_sa_t { ipsec_mode_t mode; /** - * virtual IP assinged to local host - */ - host_t *virtual_ip; + * selected proposal + */ + proposal_t *proposal; /** * config used to create this child */ child_cfg_t *config; - - /** - * cached interface name for iptables - */ - char *iface; }; /** - * Implementation of child_sa_t.get_name. + * Implementation of child_sa_t.get_name */ static char *get_name(private_child_sa_t *this) { @@ -202,11 +176,7 @@ static u_int32_t get_reqid(private_child_sa_t *this) */ u_int32_t get_spi(private_child_sa_t *this, bool inbound) { - if (inbound) - { - return this->me.spi; - } - return this->other.spi; + return inbound ? this->my_spi : this->other_spi; } /** @@ -214,11 +184,7 @@ u_int32_t get_spi(private_child_sa_t *this, bool inbound) */ u_int16_t get_cpi(private_child_sa_t *this, bool inbound) { - if (inbound) - { - return this->me.cpi; - } - return this->other.cpi; + return inbound ? this->my_cpi : this->other_cpi; } /** @@ -230,6 +196,30 @@ protocol_id_t get_protocol(private_child_sa_t *this) } /** + * Implementation of child_sa_t.get_mode + */ +static ipsec_mode_t get_mode(private_child_sa_t *this) +{ + return this->mode; +} + +/** + * Implementation of child_sa_t.has_encap + */ +static bool has_encap(private_child_sa_t *this) +{ + return this->encap; +} + +/** + * Implementation of child_sa_t.get_ipcomp + */ +static ipcomp_transform_t get_ipcomp(private_child_sa_t *this) +{ + return this->ipcomp; +} + +/** * Implements child_sa_t.get_state */ static child_sa_state_t get_state(private_child_sa_t *this) @@ -245,207 +235,134 @@ static child_cfg_t* get_config(private_child_sa_t *this) return this->config; } +typedef struct policy_enumerator_t policy_enumerator_t; + /** - * Implementation of child_sa_t.get_stats. + * Private policy enumerator */ -static void get_stats(private_child_sa_t *this, ipsec_mode_t *mode, - encryption_algorithm_t *encr_algo, size_t *encr_len, - integrity_algorithm_t *int_algo, size_t *int_len, - u_int32_t *rekey, u_int32_t *use_in, u_int32_t *use_out, - u_int32_t *use_fwd) +struct policy_enumerator_t { + /** implements enumerator_t */ + enumerator_t public; + /** enumerator over own TS */ + enumerator_t *mine; + /** enumerator over others TS */ + enumerator_t *other; + /** list of others TS, to recreate enumerator */ + linked_list_t *list; + /** currently enumerating TS for "me" side */ + traffic_selector_t *ts; +}; + +/** + * enumerator function of create_policy_enumerator() + */ +static bool policy_enumerate(policy_enumerator_t *this, + traffic_selector_t **my_out, traffic_selector_t **other_out) { - sa_policy_t *policy; - iterator_t *iterator; - u_int32_t in = 0, out = 0, fwd = 0, time; + traffic_selector_t *other_ts; - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) + while (this->ts || this->mine->enumerate(this->mine, &this->ts)) { - - if (charon->kernel_interface->query_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_IN, &time) == SUCCESS) - { - in = max(in, time); + if (!this->other->enumerate(this->other, &other_ts)) + { /* end of others list, restart with new of mine */ + this->other->destroy(this->other); + this->other = this->list->create_enumerator(this->list); + this->ts = NULL; + continue; } - if (charon->kernel_interface->query_policy(charon->kernel_interface, - policy->my_ts, policy->other_ts, POLICY_OUT, &time) == SUCCESS) - { - out = max(out, time); + if (this->ts->get_type(this->ts) != other_ts->get_type(other_ts)) + { /* family mismatch */ + continue; } - if (charon->kernel_interface->query_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_FWD, &time) == SUCCESS) - { - fwd = max(fwd, time); + if (this->ts->get_protocol(this->ts) && + other_ts->get_protocol(other_ts) && + this->ts->get_protocol(this->ts) != other_ts->get_protocol(other_ts)) + { /* protocol mismatch */ + continue; } + *my_out = this->ts; + *other_out = other_ts; + return TRUE; } - iterator->destroy(iterator); + return FALSE; +} - *mode = this->mode; - *encr_algo = this->enc_alg; - *encr_len = this->enc_size; - *int_algo = this->int_alg; - *int_len = this->int_size; - *rekey = this->rekey_time; - *use_in = in; - *use_out = out; - *use_fwd = fwd; +/** + * destroy function of create_policy_enumerator() + */ +static void policy_destroy(policy_enumerator_t *this) +{ + this->mine->destroy(this->mine); + this->other->destroy(this->other); + free(this); } /** - * Run the up/down script + * Implementation of child_sa_t.create_policy_enumerator */ -static void updown(private_child_sa_t *this, bool up) +static enumerator_t* create_policy_enumerator(private_child_sa_t *this) { - sa_policy_t *policy; - iterator_t *iterator; - char *script; - - script = this->config->get_updown(this->config); + policy_enumerator_t *e = malloc_thing(policy_enumerator_t); - if (script == NULL) - { - return; - } + e->public.enumerate = (void*)policy_enumerate; + e->public.destroy = (void*)policy_destroy; + e->mine = this->my_ts->create_enumerator(this->my_ts); + e->other = this->other_ts->create_enumerator(this->other_ts); + e->list = this->other_ts; + e->ts = NULL; - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) - { - char command[1024]; - char *my_client, *other_client, *my_client_mask, *other_client_mask; - char *pos, *virtual_ip; - FILE *shell; - - /* get subnet/bits from string */ - asprintf(&my_client, "%R", policy->my_ts); - pos = strchr(my_client, '/'); - *pos = '\0'; - my_client_mask = pos + 1; - pos = strchr(my_client_mask, '['); - if (pos) - { - *pos = '\0'; - } - asprintf(&other_client, "%R", policy->other_ts); - pos = strchr(other_client, '/'); - *pos = '\0'; - other_client_mask = pos + 1; - pos = strchr(other_client_mask, '['); - if (pos) - { - *pos = '\0'; - } - - if (this->virtual_ip) - { - asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", - this->virtual_ip); - } - else - { - asprintf(&virtual_ip, ""); - } + return &e->public; +} - /* we cache the iface name, as it may not be available when - * the SA gets deleted */ - if (up) - { - free(this->iface); - this->iface = charon->kernel_interface->get_interface( - charon->kernel_interface, this->me.addr); - } - - /* build the command with all env variables. - * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing - */ - snprintf(command, sizeof(command), - "2>&1 " - "PLUTO_VERSION='1.1' " - "PLUTO_VERB='%s%s%s' " - "PLUTO_CONNECTION='%s' " - "PLUTO_INTERFACE='%s' " - "PLUTO_REQID='%u' " - "PLUTO_ME='%H' " - "PLUTO_MY_ID='%D' " - "PLUTO_MY_CLIENT='%s/%s' " - "PLUTO_MY_CLIENT_NET='%s' " - "PLUTO_MY_CLIENT_MASK='%s' " - "PLUTO_MY_PORT='%u' " - "PLUTO_MY_PROTOCOL='%u' " - "PLUTO_PEER='%H' " - "PLUTO_PEER_ID='%D' " - "PLUTO_PEER_CLIENT='%s/%s' " - "PLUTO_PEER_CLIENT_NET='%s' " - "PLUTO_PEER_CLIENT_MASK='%s' " - "PLUTO_PEER_PORT='%u' " - "PLUTO_PEER_PROTOCOL='%u' " - "%s" - "%s" - "%s", - up ? "up" : "down", - policy->my_ts->is_host(policy->my_ts, - this->me.addr) ? "-host" : "-client", - this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-v6", - this->config->get_name(this->config), - this->iface ? this->iface : "unknown", - this->reqid, - this->me.addr, - this->me.id, - my_client, my_client_mask, - my_client, my_client_mask, - policy->my_ts->get_from_port(policy->my_ts), - policy->my_ts->get_protocol(policy->my_ts), - this->other.addr, - this->other.id, - other_client, other_client_mask, - other_client, other_client_mask, - policy->other_ts->get_from_port(policy->other_ts), - policy->other_ts->get_protocol(policy->other_ts), - virtual_ip, - this->config->get_hostaccess(this->config) ? - "PLUTO_HOST_ACCESS='1' " : "", - script); - free(my_client); - free(other_client); - free(virtual_ip); - - DBG3(DBG_CHD, "running updown script: %s", command); - shell = popen(command, "r"); +/** + * Implementation of child_sa_t.get_usetime + */ +static u_int32_t get_usetime(private_child_sa_t *this, bool inbound) +{ + enumerator_t *enumerator; + traffic_selector_t *my_ts, *other_ts; + u_int32_t last_use = 0; - if (shell == NULL) - { - DBG1(DBG_CHD, "could not execute updown script '%s'", script); - return; - } + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + { + u_int32_t in, out, fwd; - while (TRUE) + if (inbound) { - char resp[128]; - - if (fgets(resp, sizeof(resp), shell) == NULL) + if (charon->kernel_interface->query_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_IN, &in) == SUCCESS) { - if (ferror(shell)) - { - DBG1(DBG_CHD, "error reading output from updown script"); - return; - } - else + last_use = max(last_use, in); + } + if (this->mode != MODE_TRANSPORT) + { + if (charon->kernel_interface->query_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_FWD, &fwd) == SUCCESS) { - break; + last_use = max(last_use, fwd); } } - else + } + else + { + if (charon->kernel_interface->query_policy(charon->kernel_interface, + my_ts, other_ts, POLICY_OUT, &out) == SUCCESS) { - char *e = resp + strlen(resp); - if (e > resp && e[-1] == '\n') - { /* trim trailing '\n' */ - e[-1] = '\0'; - } - DBG1(DBG_CHD, "updown: %s", resp); + last_use = max(last_use, out); } } - pclose(shell); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); + return last_use; +} + +/** + * Implementation of child_sa_t.get_lifetime + */ +static u_int32_t get_lifetime(private_child_sa_t *this, bool hard) +{ + return hard ? this->expire_time : this->rekey_time; } /** @@ -453,11 +370,8 @@ static void updown(private_child_sa_t *this, bool up) */ static void set_state(private_child_sa_t *this, child_sa_state_t state) { + charon->bus->child_state_change(charon->bus, &this->public, state); this->state = state; - if (state == CHILD_INSTALLED) - { - updown(this, TRUE); - } } /** @@ -474,7 +388,7 @@ static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal) { if (charon->kernel_interface->get_spi( charon->kernel_interface, - this->other.addr, this->me.addr, + this->other_addr, this->my_addr, PROTO_AH, this->reqid, &this->alloc_ah_spi) != SUCCESS) { @@ -490,7 +404,7 @@ static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal) { if (charon->kernel_interface->get_spi( charon->kernel_interface, - this->other.addr, this->me.addr, + this->other_addr, this->my_addr, PROTO_ESP, this->reqid, &this->alloc_esp_spi) != SUCCESS) { @@ -502,7 +416,6 @@ static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal) return SUCCESS; } - /** * Implements child_sa_t.alloc */ @@ -525,237 +438,213 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals) return SUCCESS; } +/** + * Install an SA for one direction + */ static status_t install(private_child_sa_t *this, proposal_t *proposal, - ipsec_mode_t mode, prf_plus_t *prf_plus, bool mine) + ipsec_mode_t mode, chunk_t integ, chunk_t encr, bool in) { - u_int32_t spi, soft, hard; - host_t *src; - host_t *dst; + u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size; + u_int32_t spi, soft, hard, now; + host_t *src, *dst; status_t status; - this->protocol = proposal->get_protocol(proposal); - - /* now we have to decide which spi to use. Use self allocated, if "mine", - * or the one in the proposal, if not "mine" (others). Additionally, + /* now we have to decide which spi to use. Use self allocated, if "in", + * or the one in the proposal, if not "in" (others). Additionally, * source and dest host switch depending on the role */ - if (mine) + if (in) { /* if we have allocated SPIs for AH and ESP, we must delete the unused * one. */ if (this->protocol == PROTO_ESP) { - this->me.spi = this->alloc_esp_spi; + this->my_spi = this->alloc_esp_spi; if (this->alloc_ah_spi) { - charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, - this->alloc_ah_spi, PROTO_AH); + charon->kernel_interface->del_sa(charon->kernel_interface, + this->my_addr, this->alloc_ah_spi, 0, PROTO_AH); } } else { - this->me.spi = this->alloc_ah_spi; + this->my_spi = this->alloc_ah_spi; if (this->alloc_esp_spi) { - charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, - this->alloc_esp_spi, PROTO_ESP); + charon->kernel_interface->del_sa(charon->kernel_interface, + this->my_addr, this->alloc_esp_spi, 0, PROTO_ESP); } } - spi = this->me.spi; - dst = this->me.addr; - src = this->other.addr; + spi = this->my_spi; + dst = this->my_addr; + src = this->other_addr; } else { - this->other.spi = proposal->get_spi(proposal); - spi = this->other.spi; - src = this->me.addr; - dst = this->other.addr; + this->other_spi = proposal->get_spi(proposal); + spi = this->other_spi; + src = this->my_addr; + dst = this->other_addr; } - DBG2(DBG_CHD, "adding %s %N SA", mine ? "inbound" : "outbound", + DBG2(DBG_CHD, "adding %s %N SA", in ? "inbound" : "outbound", protocol_id_names, this->protocol); - /* select encryption algo */ - if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, - &this->enc_alg, &this->enc_size)) - { - DBG2(DBG_CHD, " using %N for encryption", - encryption_algorithm_names, this->enc_alg); - } - - /* select integrity algo */ - if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, - &this->int_alg, &this->int_size)) - { - DBG2(DBG_CHD, " using %N for integrity", - integrity_algorithm_names, this->int_alg); - } - soft = this->config->get_lifetime(this->config, TRUE); - hard = this->config->get_lifetime(this->config, FALSE); - /* send SA down to the kernel */ DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst); - if (this->ipcomp != IPCOMP_NONE) - { - /* we install an additional IPComp SA */ - u_int32_t cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi)); - status = charon->kernel_interface->add_sa(charon->kernel_interface, - src, dst, cpi, IPPROTO_COMP, this->reqid, 0, 0, - ENCR_UNDEFINED, 0, AUTH_UNDEFINED, 0, NULL, mode, - this->ipcomp, FALSE, mine); - } + proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg, &size); + proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_alg, &size); + soft = this->config->get_lifetime(this->config, TRUE); + hard = this->config->get_lifetime(this->config, FALSE); + status = charon->kernel_interface->add_sa(charon->kernel_interface, - src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard, - this->enc_alg, this->enc_size, this->int_alg, this->int_size, - prf_plus, mode, IPCOMP_NONE, this->encap, mine); - - this->install_time = time(NULL); - this->rekey_time = this->install_time + soft; + src, dst, spi, this->protocol, this->reqid, + in ? soft : 0, hard, enc_alg, encr, int_alg, integ, + mode, this->ipcomp, in ? this->my_cpi : this->other_cpi, + this->encap, in); + + now = time(NULL); + this->rekey_time = now + soft; + this->expire_time = now + hard; return status; } -static status_t add(private_child_sa_t *this, proposal_t *proposal, - ipsec_mode_t mode, prf_plus_t *prf_plus) +/** + * Implementation of child_sa_t.add + */ +static status_t add(private_child_sa_t *this, + proposal_t *proposal, ipsec_mode_t mode, + chunk_t integ_in, chunk_t integ_out, + chunk_t encr_in, chunk_t encr_out) { - u_int32_t outbound_spi, inbound_spi; - - /* backup outbound spi, as alloc overwrites it */ - outbound_spi = proposal->get_spi(proposal); + this->proposal = proposal->clone(proposal); + this->protocol = proposal->get_protocol(proposal); - /* get SPIs inbound SAs */ + /* get SPIs for inbound SAs, write to proposal */ if (alloc_proposal(this, proposal) != SUCCESS) { return FAILED; } - inbound_spi = proposal->get_spi(proposal); - - /* install inbound SAs */ - if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS) + /* install inbound SAs using allocated SPI */ + if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS) { return FAILED; } - - /* install outbound SAs, restore spi*/ - proposal->set_spi(proposal, outbound_spi); - if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS) + /* install outbound SAs using received SPI*/ + if (install(this, this->proposal, mode, integ_out, encr_out, FALSE) != SUCCESS) { return FAILED; } - proposal->set_spi(proposal, inbound_spi); - return SUCCESS; } -static status_t update(private_child_sa_t *this, proposal_t *proposal, - ipsec_mode_t mode, prf_plus_t *prf_plus) +/** + * Implementation of child_sa_t.update + */ +static status_t update(private_child_sa_t *this, + proposal_t *proposal, ipsec_mode_t mode, + chunk_t integ_in, chunk_t integ_out, + chunk_t encr_in, chunk_t encr_out) { - u_int32_t inbound_spi; - - /* backup received spi, as install() overwrites it */ - inbound_spi = proposal->get_spi(proposal); + this->proposal = proposal->clone(proposal); + this->protocol = proposal->get_protocol(proposal); /* install outbound SAs */ - if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS) + if (install(this, proposal, mode, integ_out, encr_out, FALSE) != SUCCESS) { return FAILED; } - - /* restore spi */ - proposal->set_spi(proposal, inbound_spi); /* install inbound SAs */ - if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS) + if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS) { return FAILED; } - return SUCCESS; } +/** + * Implementation of child_sa_t.get_proposal + */ +static proposal_t* get_proposal(private_child_sa_t *this) +{ + return this->proposal; +} + +/** + * Implementation of child_sa_t.add_policies + */ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list, ipsec_mode_t mode, protocol_id_t proto) { - iterator_t *my_iter, *other_iter; + enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; - /* use low prio for ROUTED policies */ - bool high_prio = (this->state != CHILD_CREATED); + status_t status = SUCCESS; + bool routed = (this->state == CHILD_CREATED); if (this->protocol == PROTO_NONE) { /* update if not set yet */ this->protocol = proto; } + + /* apply traffic selectors */ + enumerator = my_ts_list->create_enumerator(my_ts_list); + while (enumerator->enumerate(enumerator, &my_ts)) + { + this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts)); + } + enumerator->destroy(enumerator); + enumerator = other_ts_list->create_enumerator(other_ts_list); + while (enumerator->enumerate(enumerator, &other_ts)) + { + this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts)); + } + enumerator->destroy(enumerator); - /* iterate over both lists */ - my_iter = my_ts_list->create_iterator(my_ts_list, TRUE); - other_iter = other_ts_list->create_iterator(other_ts_list, TRUE); - while (my_iter->iterate(my_iter, (void**)&my_ts)) + if (this->config->install_policy(this->config)) { - other_iter->reset(other_iter); - while (other_iter->iterate(other_iter, (void**)&other_ts)) + /* enumerate pairs of traffic selectors */ + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { - /* set up policies for every entry in my_ts_list to every entry in other_ts_list */ - status_t status; - sa_policy_t *policy; - - if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts)) - { - DBG2(DBG_CHD, - "CHILD_SA policy uses two different IP families - ignored"); - continue; - } - - /* only set up policies if protocol matches, or if one is zero (any) */ - if (my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts) && - my_ts->get_protocol(my_ts) && other_ts->get_protocol(other_ts)) - { - DBG2(DBG_CHD, - "CHILD_SA policy uses two different protocols - ignored"); - continue; - } - /* install 3 policies: out, in and forward */ - status = charon->kernel_interface->add_policy(charon->kernel_interface, - this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT, - this->protocol, this->reqid, high_prio, mode, this->ipcomp); - status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN, - this->protocol, this->reqid, high_prio, mode, this->ipcomp); + this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT, + this->other_spi, this->protocol, this->reqid, mode, this->ipcomp, + this->other_cpi, routed); status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD, - this->protocol, this->reqid, high_prio, mode, this->ipcomp); + this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN, + this->my_spi, this->protocol, this->reqid, mode, this->ipcomp, + this->my_cpi, routed); + if (mode != MODE_TRANSPORT) + { + status |= charon->kernel_interface->add_policy(charon->kernel_interface, + this->other_addr, this->my_addr, other_ts, my_ts, POLICY_FWD, + this->my_spi, this->protocol, this->reqid, mode, this->ipcomp, + this->my_cpi, routed); + } if (status != SUCCESS) { - my_iter->destroy(my_iter); - other_iter->destroy(other_iter); - return status; + break; } - - /* store policy to delete/update them later */ - policy = malloc_thing(sa_policy_t); - policy->my_ts = my_ts->clone(my_ts); - policy->other_ts = other_ts->clone(other_ts); - this->policies->insert_last(this->policies, policy); - /* add to separate list to query them via get_*_traffic_selectors() */ - this->my_ts->insert_last(this->my_ts, policy->my_ts); - this->other_ts->insert_last(this->other_ts, policy->other_ts); } + enumerator->destroy(enumerator); } - my_iter->destroy(my_iter); - other_iter->destroy(other_iter); - /* switch to routed state if no SAD entry set up */ - if (this->state == CHILD_CREATED) + if (status == SUCCESS) { - this->state = CHILD_ROUTED; + /* switch to routed state if no SAD entry set up */ + if (this->state == CHILD_CREATED) + { + set_state(this, CHILD_ROUTED); + } + /* needed to update hosts */ + this->mode = mode; } - /* needed to update hosts */ - this->mode = mode; - return SUCCESS; + return status; } /** @@ -763,166 +652,143 @@ static status_t add_policies(private_child_sa_t *this, */ static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local) { - if (local) - { - return this->my_ts; - } - return this->other_ts; -} - -/** - * Implementation of child_sa_t.get_use_time - */ -static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use_time) -{ - iterator_t *iterator; - sa_policy_t *policy; - status_t status = FAILED; - - *use_time = UNDEFINED_TIME; - - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) - { - if (inbound) - { - time_t in = UNDEFINED_TIME, fwd = UNDEFINED_TIME; - - status = charon->kernel_interface->query_policy( - charon->kernel_interface, - policy->other_ts, policy->my_ts, - POLICY_IN, (u_int32_t*)&in); - status |= charon->kernel_interface->query_policy( - charon->kernel_interface, - policy->other_ts, policy->my_ts, - POLICY_FWD, (u_int32_t*)&fwd); - *use_time = max(in, fwd); - } - else - { - status = charon->kernel_interface->query_policy( - charon->kernel_interface, - policy->my_ts, policy->other_ts, - POLICY_OUT, (u_int32_t*)use_time); - } - } - iterator->destroy(iterator); - return status; + return local ? this->my_ts : this->other_ts; } /** * Implementation of child_sa_t.update_hosts. */ static status_t update_hosts(private_child_sa_t *this, - host_t *me, host_t *other, bool encap) + host_t *me, host_t *other, host_t *vip, bool encap) { + child_sa_state_t old; + bool transport_proxy_mode; + /* anything changed at all? */ - if (me->equals(me, this->me.addr) && - other->equals(other, this->other.addr) && this->encap == encap) + if (me->equals(me, this->my_addr) && + other->equals(other, this->other_addr) && this->encap == encap) { return SUCCESS; } - /* run updown script to remove iptables rules */ - updown(this, FALSE); - - this->encap = encap; - - if (this->ipcomp != IPCOMP_NONE) - { - /* update our (initator) IPComp SA */ - charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->me.cpi)), - IPPROTO_COMP, this->other.addr, this->me.addr, other, me, FALSE); - /* update his (responder) IPComp SA */ - charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->other.cpi)), - IPPROTO_COMP, this->me.addr, this->other.addr, me, other, FALSE); - } - /* update our (initator) SA */ - charon->kernel_interface->update_sa(charon->kernel_interface, this->me.spi, - this->protocol, this->other.addr, this->me.addr, other, me, encap); - /* update his (responder) SA */ - charon->kernel_interface->update_sa(charon->kernel_interface, this->other.spi, - this->protocol, this->me.addr, this->other.addr, me, other, encap); + old = this->state; + set_state(this, CHILD_UPDATING); + transport_proxy_mode = this->config->use_proxy_mode(this->config) && + this->mode == MODE_TRANSPORT; - /* update policies */ - if (!me->ip_equals(me, this->me.addr) || - !other->ip_equals(other, this->other.addr)) + if (!transport_proxy_mode) { - iterator_t *iterator; - sa_policy_t *policy; - - /* always use high priorities, as hosts getting updated are INSTALLED */ - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) + /* update our (initator) SA */ + if (this->my_spi) { - /* remove old policies first */ - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->my_ts, policy->other_ts, POLICY_OUT); - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_IN); - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_FWD); - - /* check wether we have to update a "dynamic" traffic selector */ - if (!me->ip_equals(me, this->me.addr) && - policy->my_ts->is_host(policy->my_ts, this->me.addr)) + if (charon->kernel_interface->update_sa(charon->kernel_interface, + this->my_spi, this->protocol, + this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0, + this->other_addr, this->my_addr, other, me, + this->encap, encap) == NOT_SUPPORTED) { - policy->my_ts->set_address(policy->my_ts, me); + return NOT_SUPPORTED; } - if (!other->ip_equals(other, this->other.addr) && - policy->other_ts->is_host(policy->other_ts, this->other.addr)) + } + + /* update his (responder) SA */ + if (this->other_spi) + { + if (charon->kernel_interface->update_sa(charon->kernel_interface, + this->other_spi, this->protocol, + this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0, + this->my_addr, this->other_addr, me, other, + this->encap, encap) == NOT_SUPPORTED) { - policy->other_ts->set_address(policy->other_ts, other); + return NOT_SUPPORTED; } + } + } + + if (this->config->install_policy(this->config)) + { + /* update policies */ + if (!me->ip_equals(me, this->my_addr) || + !other->ip_equals(other, this->other_addr)) + { + enumerator_t *enumerator; + traffic_selector_t *my_ts, *other_ts; - /* we reinstall the virtual IP to handle interface romaing - * correctly */ - if (this->virtual_ip) + /* always use high priorities, as hosts getting updated are INSTALLED */ + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { - charon->kernel_interface->del_ip(charon->kernel_interface, - this->virtual_ip); - charon->kernel_interface->add_ip(charon->kernel_interface, - this->virtual_ip, me); + /* remove old policies first */ + charon->kernel_interface->del_policy(charon->kernel_interface, + my_ts, other_ts, POLICY_OUT, FALSE); + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_IN, FALSE); + if (this->mode != MODE_TRANSPORT) + { + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_FWD, FALSE); + } + + /* check whether we have to update a "dynamic" traffic selector */ + if (!me->ip_equals(me, this->my_addr) && + my_ts->is_host(my_ts, this->my_addr)) + { + my_ts->set_address(my_ts, me); + } + if (!other->ip_equals(other, this->other_addr) && + other_ts->is_host(other_ts, this->other_addr)) + { + other_ts->set_address(other_ts, other); + } + + /* we reinstall the virtual IP to handle interface roaming + * correctly */ + if (vip) + { + charon->kernel_interface->del_ip(charon->kernel_interface, vip); + charon->kernel_interface->add_ip(charon->kernel_interface, vip, me); + } + + /* reinstall updated policies */ + charon->kernel_interface->add_policy(charon->kernel_interface, + me, other, my_ts, other_ts, POLICY_OUT, this->other_spi, + this->protocol, this->reqid, this->mode, this->ipcomp, + this->other_cpi, FALSE); + charon->kernel_interface->add_policy(charon->kernel_interface, + other, me, other_ts, my_ts, POLICY_IN, this->my_spi, + this->protocol, this->reqid, this->mode, this->ipcomp, + this->my_cpi, FALSE); + if (this->mode != MODE_TRANSPORT) + { + charon->kernel_interface->add_policy(charon->kernel_interface, + other, me, other_ts, my_ts, POLICY_FWD, this->my_spi, + this->protocol, this->reqid, this->mode, this->ipcomp, + this->my_cpi, FALSE); + } } - - /* reinstall updated policies */ - charon->kernel_interface->add_policy(charon->kernel_interface, - me, other, policy->my_ts, policy->other_ts, POLICY_OUT, - this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); - charon->kernel_interface->add_policy(charon->kernel_interface, - other, me, policy->other_ts, policy->my_ts, POLICY_IN, - this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); - charon->kernel_interface->add_policy(charon->kernel_interface, - other, me, policy->other_ts, policy->my_ts, POLICY_FWD, - this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); + enumerator->destroy(enumerator); } - iterator->destroy(iterator); } - /* apply hosts */ - if (!me->equals(me, this->me.addr)) + if (!transport_proxy_mode) { - this->me.addr->destroy(this->me.addr); - this->me.addr = me->clone(me); - } - if (!other->equals(other, this->other.addr)) - { - this->other.addr->destroy(this->other.addr); - this->other.addr = other->clone(other); + /* apply hosts */ + if (!me->equals(me, this->my_addr)) + { + this->my_addr->destroy(this->my_addr); + this->my_addr = me->clone(me); + } + if (!other->equals(other, this->other_addr)) + { + this->other_addr->destroy(this->other_addr); + this->other_addr = other->clone(other); + } } - - /* install new iptables rules */ - updown(this, TRUE); - - return SUCCESS; -} -/** - * Implementation of child_sa_t.set_virtual_ip. - */ -static void set_virtual_ip(private_child_sa_t *this, host_t *ip) -{ - this->virtual_ip = ip->clone(ip); + this->encap = encap; + set_state(this, old); + + return SUCCESS; } /** @@ -932,7 +798,7 @@ static void activate_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp, u_int16_t other_cpi) { this->ipcomp = ipcomp; - this->other.cpi = other_cpi; + this->other_cpi = other_cpi; } /** @@ -943,10 +809,10 @@ static u_int16_t allocate_cpi(private_child_sa_t *this) if (!this->cpi_allocated) { charon->kernel_interface->get_cpi(charon->kernel_interface, - this->other.addr, this->me.addr, this->reqid, &this->me.cpi); + this->other_addr, this->my_addr, this->reqid, &this->my_cpi); this->cpi_allocated = TRUE; } - return this->me.cpi; + return this->my_cpi; } /** @@ -954,75 +820,61 @@ static u_int16_t allocate_cpi(private_child_sa_t *this) */ static void destroy(private_child_sa_t *this) { - sa_policy_t *policy; + enumerator_t *enumerator; + traffic_selector_t *my_ts, *other_ts; + bool unrouted = (this->state == CHILD_ROUTED); - if (this->state == CHILD_DELETING || this->state == CHILD_INSTALLED) - { - updown(this, FALSE); - } + set_state(this, CHILD_DESTROYING); /* delete SAs in the kernel, if they are set up */ - if (this->me.spi) - { - charon->kernel_interface->del_sa(charon->kernel_interface, - this->me.addr, this->me.spi, this->protocol); - } - if (this->alloc_esp_spi && this->alloc_esp_spi != this->me.spi) + if (this->my_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->me.addr, this->alloc_esp_spi, PROTO_ESP); + this->my_addr, this->my_spi, this->protocol, + this->my_cpi); } - if (this->alloc_ah_spi && this->alloc_ah_spi != this->me.spi) + if (this->alloc_esp_spi && this->alloc_esp_spi != this->my_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->me.addr, this->alloc_ah_spi, PROTO_AH); + this->my_addr, this->alloc_esp_spi, PROTO_ESP, 0); } - if (this->other.spi) + if (this->alloc_ah_spi && this->alloc_ah_spi != this->my_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->other.addr, this->other.spi, this->protocol); + this->my_addr, this->alloc_ah_spi, PROTO_AH, 0); } - if (this->me.cpi) + if (this->other_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->me.addr, htonl(ntohs(this->me.cpi)), IPPROTO_COMP); - } - if (this->other.cpi) - { - charon->kernel_interface->del_sa(charon->kernel_interface, - this->other.addr, htonl(ntohs(this->other.cpi)), IPPROTO_COMP); + this->other_addr, this->other_spi, this->protocol, + this->other_cpi); } - /* delete all policies in the kernel */ - while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS) + if (this->config->install_policy(this->config)) { - /* let rekeyed policies, as they are used by another child_sa */ - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->my_ts, policy->other_ts, - POLICY_OUT); - - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, - POLICY_IN); - - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, - POLICY_FWD); - policy->my_ts->destroy(policy->my_ts); - policy->other_ts->destroy(policy->other_ts); - free(policy); + /* delete all policies in the kernel */ + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + { + charon->kernel_interface->del_policy(charon->kernel_interface, + my_ts, other_ts, POLICY_OUT, unrouted); + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_IN, unrouted); + if (this->mode != MODE_TRANSPORT) + { + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_FWD, unrouted); + } + } + enumerator->destroy(enumerator); } - this->policies->destroy(this->policies); - this->my_ts->destroy(this->my_ts); - this->other_ts->destroy(this->other_ts); - this->me.addr->destroy(this->me.addr); - this->other.addr->destroy(this->other.addr); - this->me.id->destroy(this->me.id); - this->other.id->destroy(this->other.id); + this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy)); + this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy)); + this->my_addr->destroy(this->my_addr); + this->other_addr->destroy(this->other_addr); + DESTROY_IF(this->proposal); this->config->destroy(this->config); - free(this->iface); - DESTROY_IF(this->virtual_ip); free(this); } @@ -1030,7 +882,6 @@ static void destroy(private_child_sa_t *this) * Described in header. */ child_sa_t * child_sa_create(host_t *me, host_t* other, - identification_t *my_id, identification_t *other_id, child_cfg_t *config, u_int32_t rekey, bool encap) { static u_int32_t reqid = 0; @@ -1042,31 +893,33 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi; this->public.get_cpi = (u_int16_t(*)(child_sa_t*, bool))get_cpi; this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol; - this->public.get_stats = (void(*)(child_sa_t*, ipsec_mode_t*,encryption_algorithm_t*,size_t*,integrity_algorithm_t*,size_t*,u_int32_t*,u_int32_t*,u_int32_t*,u_int32_t*))get_stats; + this->public.get_mode = (ipsec_mode_t(*)(child_sa_t*))get_mode; + this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp; + this->public.has_encap = (bool(*)(child_sa_t*))has_encap; + this->public.get_lifetime = (u_int32_t(*)(child_sa_t*, bool))get_lifetime; + this->public.get_usetime = (u_int32_t(*)(child_sa_t*, bool))get_usetime; this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; - this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,prf_plus_t*))add; - this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,prf_plus_t*))update; - this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,bool))update_hosts; + this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))add; + this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))update; + this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal; + this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update_hosts; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,ipsec_mode_t,protocol_id_t))add_policies; this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors; - this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; + this->public.create_policy_enumerator = (enumerator_t*(*)(child_sa_t*))create_policy_enumerator; this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state; this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state; this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config; this->public.activate_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t,u_int16_t))activate_ipcomp; this->public.allocate_cpi = (u_int16_t(*)(child_sa_t*))allocate_cpi; - this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip; this->public.destroy = (void(*)(child_sa_t*))destroy; /* private data */ - this->me.addr = me->clone(me); - this->other.addr = other->clone(other); - this->me.id = my_id->clone(my_id); - this->other.id = other_id->clone(other_id); - this->me.spi = 0; - this->me.cpi = 0; - this->other.spi = 0; - this->other.cpi = 0; + this->my_addr = me->clone(me); + this->other_addr = other->clone(other); + this->my_spi = 0; + this->my_cpi = 0; + this->other_spi = 0; + this->other_cpi = 0; this->alloc_ah_spi = 0; this->alloc_esp_spi = 0; this->encap = encap; @@ -1075,19 +928,70 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->state = CHILD_CREATED; /* reuse old reqid if we are rekeying an existing CHILD_SA */ this->reqid = rekey ? rekey : ++reqid; - this->enc_alg = ENCR_UNDEFINED; - this->enc_size = 0; - this->int_alg = AUTH_UNDEFINED; - this->int_size = 0; - this->policies = linked_list_create(); this->my_ts = linked_list_create(); this->other_ts = linked_list_create(); this->protocol = PROTO_NONE; this->mode = MODE_TUNNEL; - this->virtual_ip = NULL; - this->iface = NULL; + this->proposal = NULL; this->config = config; config->get_ref(config); + + /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */ + if (config->get_mode(config) == MODE_TRANSPORT && + config->use_proxy_mode(config)) + { + ts_type_t type; + int family; + chunk_t addr; + host_t *host; + enumerator_t *enumerator; + linked_list_t *my_ts_list, *other_ts_list; + traffic_selector_t *my_ts, *other_ts; + + this->mode = MODE_TRANSPORT; + + my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me); + enumerator = my_ts_list->create_enumerator(my_ts_list); + if (enumerator->enumerate(enumerator, &my_ts)) + { + if (my_ts->is_host(my_ts, NULL) && + !my_ts->is_host(my_ts, this->my_addr)) + { + type = my_ts->get_type(my_ts); + family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; + addr = my_ts->get_from_address(my_ts); + host = host_create_from_chunk(family, addr, 0); + free(addr.ptr); + DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H", + this->my_addr, host); + this->my_addr->destroy(this->my_addr); + this->my_addr = host; + } + } + enumerator->destroy(enumerator); + my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy)); + + other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other); + enumerator = other_ts_list->create_enumerator(other_ts_list); + if (enumerator->enumerate(enumerator, &other_ts)) + { + if (other_ts->is_host(other_ts, NULL) && + !other_ts->is_host(other_ts, this->other_addr)) + { + type = other_ts->get_type(other_ts); + family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; + addr = other_ts->get_from_address(other_ts); + host = host_create_from_chunk(family, addr, 0); + free(addr.ptr); + DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H", + this->other_addr, host); + this->other_addr->destroy(this->other_addr); + this->other_addr = host; + } + } + enumerator->destroy(enumerator); + other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy)); + } return &this->public; } |