diff options
Diffstat (limited to 'Source/charon')
-rw-r--r-- | Source/charon/config/configuration_manager.c | 47 | ||||
-rw-r--r-- | Source/charon/config/proposal.h | 14 | ||||
-rw-r--r-- | Source/charon/config/sa_config.c | 145 | ||||
-rw-r--r-- | Source/charon/config/sa_config.h | 72 | ||||
-rw-r--r-- | Source/charon/config/traffic_selector.c | 14 | ||||
-rw-r--r-- | Source/charon/config/traffic_selector.h | 9 | ||||
-rw-r--r-- | Source/charon/encoding/payloads/ts_payload.c | 31 | ||||
-rw-r--r-- | Source/charon/encoding/payloads/ts_payload.h | 20 | ||||
-rw-r--r-- | Source/charon/sa/child_sa.c | 90 | ||||
-rw-r--r-- | Source/charon/sa/child_sa.h | 84 | ||||
-rw-r--r-- | Source/charon/sa/states/ike_auth_requested.c | 160 | ||||
-rw-r--r-- | Source/charon/sa/states/ike_sa_init_requested.c | 30 | ||||
-rw-r--r-- | Source/charon/sa/states/ike_sa_init_responded.c | 162 | ||||
-rw-r--r-- | Source/charon/testcases/kernel_interface_test.c | 27 | ||||
-rw-r--r-- | Source/charon/testcases/sa_config_test.c | 10 | ||||
-rw-r--r-- | Source/charon/testcases/testcases.c | 2 | ||||
-rw-r--r-- | Source/charon/threads/kernel_interface.c | 227 | ||||
-rw-r--r-- | Source/charon/threads/kernel_interface.h | 22 |
18 files changed, 739 insertions, 427 deletions
diff --git a/Source/charon/config/configuration_manager.c b/Source/charon/config/configuration_manager.c index 9028a5c47..c5c6ec6ae 100644 --- a/Source/charon/config/configuration_manager.c +++ b/Source/charon/config/configuration_manager.c @@ -279,8 +279,8 @@ static void load_default_config (private_configuration_manager_t *this) sa_config_t *sa_config_a, *sa_config_b; traffic_selector_t *ts; - init_config_a = init_config_create("192.168.0.2","192.168.0.3",IKEV2_UDP_PORT,IKEV2_UDP_PORT); - init_config_b = init_config_create("192.168.0.3","192.168.0.2",IKEV2_UDP_PORT,IKEV2_UDP_PORT); + init_config_a = init_config_create("192.168.0.1","192.168.0.2",IKEV2_UDP_PORT,IKEV2_UDP_PORT); + init_config_b = init_config_create("192.168.0.2","192.168.0.1",IKEV2_UDP_PORT,IKEV2_UDP_PORT); /* IKE proposals for alice */ proposal = proposal_create(1); @@ -301,23 +301,26 @@ static void load_default_config (private_configuration_manager_t *this) proposal->add_algorithm(proposal, IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); init_config_b->add_proposal(init_config_b, proposal); - sa_config_a = sa_config_create(ID_IPV4_ADDR, "192.168.0.2", - ID_IPV4_ADDR, "192.168.0.3", + sa_config_a = sa_config_create(ID_IPV4_ADDR, "192.168.0.1", + ID_IPV4_ADDR, "192.168.0.2", RSA_DIGITAL_SIGNATURE, 30000); - sa_config_b = sa_config_create(ID_IPV4_ADDR, "192.168.0.3", - ID_IPV4_ADDR, "192.168.0.2", + sa_config_b = sa_config_create(ID_IPV4_ADDR, "192.168.0.2", + ID_IPV4_ADDR, "192.168.0.1", RSA_DIGITAL_SIGNATURE, 30000); /* traffic selectors */ - ts = traffic_selector_create_from_string(1, TS_IPV4_ADDR_RANGE, "0.0.0.0", 0, "255.255.255.255", 65535); - sa_config_a->add_traffic_selector_initiator(sa_config_a,ts); - sa_config_a->add_traffic_selector_responder(sa_config_a,ts); - sa_config_b->add_traffic_selector_initiator(sa_config_b,ts); - sa_config_b->add_traffic_selector_responder(sa_config_b,ts); - ts->destroy(ts); + ts = traffic_selector_create_from_string(1, TS_IPV4_ADDR_RANGE, "10.1.0.0", 0, "10.1.255.255", 65535); + sa_config_a->add_my_traffic_selector(sa_config_a,ts); + ts = traffic_selector_create_from_string(1, TS_IPV4_ADDR_RANGE, "10.2.0.0", 0, "10.2.255.255", 65535); + sa_config_a->add_other_traffic_selector(sa_config_a,ts); + + ts = traffic_selector_create_from_string(1, TS_IPV4_ADDR_RANGE, "10.2.0.0", 0, "10.2.255.255", 65535); + sa_config_b->add_my_traffic_selector(sa_config_b,ts); + ts = traffic_selector_create_from_string(1, TS_IPV4_ADDR_RANGE, "10.1.0.0", 0, "10.1.255.255", 65535); + sa_config_b->add_other_traffic_selector(sa_config_b,ts); /* child proposal for alice */ proposal = proposal_create(1); @@ -329,12 +332,11 @@ static void load_default_config (private_configuration_manager_t *this) // proposal->add_algorithm(proposal, AH, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); proposal->add_algorithm(proposal, ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); - proposal->add_algorithm(proposal, ESP, ENCRYPTION_ALGORITHM, ENCR_3DES, 0); proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); - proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); - proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); - proposal->add_algorithm(proposal, ESP, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); +// proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); +// proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); +// proposal->add_algorithm(proposal, ESP, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); sa_config_a->add_proposal(sa_config_a, proposal); @@ -347,10 +349,11 @@ static void load_default_config (private_configuration_manager_t *this) // proposal->add_algorithm(proposal, AH, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); // proposal->add_algorithm(proposal, AH, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); + proposal->add_algorithm(proposal, ESP, ENCRYPTION_ALGORITHM, ENCR_3DES, 0); proposal->add_algorithm(proposal, ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); - proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); - proposal->add_algorithm(proposal, ESP, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); +// proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); +// proposal->add_algorithm(proposal, ESP, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); sa_config_b->add_proposal(sa_config_b, proposal); @@ -363,10 +366,10 @@ static void load_default_config (private_configuration_manager_t *this) //this->add_new_preshared_secret(this,ID_IPV4_ADDR, "192.168.1.2","verschluesselt"); - this->add_new_rsa_public_key(this,ID_IPV4_ADDR, "192.168.0.2", public_key_1, 256); - this->add_new_rsa_public_key(this,ID_IPV4_ADDR, "192.168.0.3", public_key_2, 256); - this->add_new_rsa_private_key(this,ID_IPV4_ADDR, "192.168.0.2", private_key_1, 1024); - this->add_new_rsa_private_key(this,ID_IPV4_ADDR, "192.168.0.3", private_key_2, 1024); + this->add_new_rsa_public_key(this,ID_IPV4_ADDR, "192.168.0.1", public_key_1, 256); + this->add_new_rsa_public_key(this,ID_IPV4_ADDR, "192.168.0.2", public_key_2, 256); + this->add_new_rsa_private_key(this,ID_IPV4_ADDR, "192.168.0.1", private_key_1, 1024); + this->add_new_rsa_private_key(this,ID_IPV4_ADDR, "192.168.0.2", private_key_2, 1024); } /** diff --git a/Source/charon/config/proposal.h b/Source/charon/config/proposal.h index 53d417bb1..047d653d3 100644 --- a/Source/charon/config/proposal.h +++ b/Source/charon/config/proposal.h @@ -120,8 +120,12 @@ struct algorithm_t { typedef struct proposal_t proposal_t; /** - * @brief Stores a proposal for a child SA. + * @brief Stores a set of algorithms used for an SA. * + * A proposal stores algorithms for a specific + * protocol. It can store algorithms for more than + * one protocol (e.g. AH and ESP). Then the proposal + * means both protocols must be used. * A proposal may contain more than one algorithm * of the same kind. ONE of them can be selected. * @@ -140,8 +144,8 @@ struct proposal_t { * The algorithms are stored by priority, first added * is the most preferred. * Key size is only needed for encryption algorithms - * with variable key size (such as AES), or integrity - * algorithms. + * with variable key size (such as AES). Must be set + * to zero if key size is not specified. * The alg parameter accepts encryption_algorithm_t, * integrity_algorithm_t, dh_group_number_t and * extended_sequence_numbers_t. @@ -243,6 +247,10 @@ struct proposal_t { /** * @brief Create a child proposal for AH and/or ESP. * + * Since the order of multiple proposals is important for + * key derivation, we must assign them numbers as they + * appear in the raw payload. Numbering starts at 1. + * * @param number number of the proposal, as in the payload * @return proposal_t object * diff --git a/Source/charon/config/sa_config.c b/Source/charon/config/sa_config.c index 6e7f8ee03..672ac955c 100644 --- a/Source/charon/config/sa_config.c +++ b/Source/charon/config/sa_config.c @@ -65,24 +65,19 @@ struct private_sa_config_t { linked_list_t *proposals; /** - * list for traffic selectors for initiator site + * list for traffic selectors for my site */ - linked_list_t *ts_initiator; + linked_list_t *my_ts; /** - * list for traffic selectors for responder site + * list for traffic selectors for others site */ - linked_list_t *ts_responder; - - /** - * get_traffic_selectors for both - */ - size_t (*get_traffic_selectors) (private_sa_config_t *,linked_list_t*,traffic_selector_t**[]); + linked_list_t *other_ts; /** * select_traffic_selectors for both */ - size_t (*select_traffic_selectors) (private_sa_config_t *,linked_list_t*,traffic_selector_t*[],size_t,traffic_selector_t**[]); + linked_list_t *(*select_traffic_selectors) (private_sa_config_t *,linked_list_t*,linked_list_t*); }; /** @@ -118,91 +113,72 @@ static u_int32_t get_ike_sa_lifetime (private_sa_config_t *this) } /** - * Implementation of sa_config_t.get_traffic_selectors_initiator + * Implementation of sa_config_t.get_my_traffic_selectors */ -static size_t get_traffic_selectors_initiator(private_sa_config_t *this, traffic_selector_t **traffic_selectors[]) +static linked_list_t *get_my_traffic_selectors(private_sa_config_t *this) { - return this->get_traffic_selectors(this, this->ts_initiator, traffic_selectors); + return this->my_ts; } /** - * Implementation of sa_config_t.get_traffic_selectors_responder + * Implementation of sa_config_t.get_other_traffic_selectors */ -static size_t get_traffic_selectors_responder(private_sa_config_t *this, traffic_selector_t **traffic_selectors[]) +static linked_list_t *get_other_traffic_selectors(private_sa_config_t *this, traffic_selector_t **traffic_selectors[]) { - return this->get_traffic_selectors(this, this->ts_responder, traffic_selectors); -} - -/** - * Implementation of private_sa_config_t.get_traffic_selectors - */ -static size_t get_traffic_selectors(private_sa_config_t *this, linked_list_t *ts_list, traffic_selector_t **traffic_selectors[]) -{ - iterator_t *iterator; - traffic_selector_t *current_ts; - int counter = 0; - *traffic_selectors = allocator_alloc(sizeof(traffic_selector_t*) * ts_list->get_count(ts_list)); - - /* copy all ts from the list in an array */ - iterator = ts_list->create_iterator(ts_list, TRUE); - while (iterator->has_next(iterator)) - { - iterator->current(iterator, (void**)¤t_ts); - *((*traffic_selectors) + counter) = current_ts->clone(current_ts); - counter++; - } - iterator->destroy(iterator); - return counter; + return this->other_ts; } /** - * Implementation of private_sa_config_t.select_traffic_selectors_initiator + * Implementation of private_sa_config_t.select_my_traffic_selectors */ -static size_t select_traffic_selectors_initiator(private_sa_config_t *this,traffic_selector_t *supplied[], size_t count, traffic_selector_t **selected[]) +static linked_list_t *select_my_traffic_selectors(private_sa_config_t *this, linked_list_t *supplied) { - return this->select_traffic_selectors(this, this->ts_initiator, supplied, count, selected); + return this->select_traffic_selectors(this, this->my_ts, supplied); } /** - * Implementation of private_sa_config_t.select_traffic_selectors_responder + * Implementation of private_sa_config_t.select_other_traffic_selectors */ -static size_t select_traffic_selectors_responder(private_sa_config_t *this,traffic_selector_t *supplied[], size_t count, traffic_selector_t **selected[]) +static linked_list_t *select_other_traffic_selectors(private_sa_config_t *this, linked_list_t *supplied) { - return this->select_traffic_selectors(this, this->ts_responder, supplied, count, selected); + return this->select_traffic_selectors(this, this->other_ts, supplied); } /** * Implementation of private_sa_config_t.select_traffic_selectors */ -static size_t select_traffic_selectors(private_sa_config_t *this, linked_list_t *ts_list, traffic_selector_t *supplied[], size_t count, traffic_selector_t **selected[]) +static linked_list_t *select_traffic_selectors(private_sa_config_t *this, linked_list_t *stored, linked_list_t *supplied) { - iterator_t *iterator; - traffic_selector_t *current_ts; - int i, counter = 0; - *selected = allocator_alloc(sizeof(traffic_selector_t*) * ts_list->get_count(ts_list)); + iterator_t *supplied_iter, *stored_iter; + traffic_selector_t *supplied_ts, *stored_ts, *selected_ts; + linked_list_t *selected = linked_list_create(); + - /* iterate over all stored proposals */ - iterator = ts_list->create_iterator(ts_list, TRUE); - while (iterator->has_next(iterator)) + stored_iter = stored->create_iterator(stored, TRUE); + supplied_iter = supplied->create_iterator(supplied, TRUE); + + /* iterate over all stored selectors */ + while (stored_iter->has_next(stored_iter)) { - iterator->current(iterator, (void**)¤t_ts); - for (i = 0; i < count; i++) + stored_iter->current(stored_iter, (void**)&stored_ts); + + supplied_iter->reset(supplied_iter); + /* iterate over all supplied traffic selectors */ + while (supplied_iter->has_next(supplied_iter)) { - traffic_selector_t *new_ts; - /* compare it */ - new_ts = current_ts->get_subset(current_ts, supplied[i]); - /* match ? */ - if (new_ts) + supplied_iter->current(supplied_iter, (void**)&supplied_ts); + + selected_ts = stored_ts->get_subset(stored_ts, supplied_ts); + if (selected_ts) { - *((*selected) + counter) = new_ts; - counter++; + /* got a match, add to list */ + selected->insert_last(selected, (void*)selected_ts); } } } - iterator->destroy(iterator); + stored_iter->destroy(stored_iter); + supplied_iter->destroy(supplied_iter); - /* free unused space */ - *selected = allocator_realloc(*selected, sizeof(traffic_selector_t) * counter); - return counter; + return selected; } /** @@ -252,21 +228,19 @@ static proposal_t *select_proposal(private_sa_config_t *this, linked_list_t *pro } /** - * Implementation of sa_config_t.add_traffic_selector_initiator + * Implementation of sa_config_t.add_my_traffic_selector */ -static void add_traffic_selector_initiator(private_sa_config_t *this, traffic_selector_t *traffic_selector) +static void add_my_traffic_selector(private_sa_config_t *this, traffic_selector_t *traffic_selector) { - /* clone ts, and add*/ - this->ts_initiator->insert_last(this->ts_initiator, (void*)traffic_selector->clone(traffic_selector)); + this->my_ts->insert_last(this->my_ts, (void*)traffic_selector); } /** - * Implementation of sa_config_t.add_traffic_selector_responder + * Implementation of sa_config_t.add_other_traffic_selector */ -static void add_traffic_selector_responder(private_sa_config_t *this, traffic_selector_t *traffic_selector) +static void add_other_traffic_selector(private_sa_config_t *this, traffic_selector_t *traffic_selector) { - /* clone ts, and add*/ - this->ts_responder->insert_last(this->ts_responder, (void*)traffic_selector->clone(traffic_selector)); + this->other_ts->insert_last(this->other_ts, (void*)traffic_selector); } /** @@ -294,18 +268,18 @@ static status_t destroy(private_sa_config_t *this) this->proposals->destroy(this->proposals); /* delete traffic selectors */ - while(this->ts_initiator->remove_last(this->ts_initiator, (void**)&traffic_selector) == SUCCESS) + while(this->my_ts->remove_last(this->my_ts, (void**)&traffic_selector) == SUCCESS) { traffic_selector->destroy(traffic_selector); } - this->ts_initiator->destroy(this->ts_initiator); + this->my_ts->destroy(this->my_ts); /* delete traffic selectors */ - while(this->ts_responder->remove_last(this->ts_responder, (void**)&traffic_selector) == SUCCESS) + while(this->other_ts->remove_last(this->other_ts, (void**)&traffic_selector) == SUCCESS) { traffic_selector->destroy(traffic_selector); } - this->ts_responder->destroy(this->ts_responder); + this->other_ts->destroy(this->other_ts); /* delete ids */ this->my_id->destroy(this->my_id); @@ -327,14 +301,14 @@ sa_config_t *sa_config_create(id_type_t my_id_type, char *my_id, id_type_t other this->public.get_other_id = (identification_t*(*)(sa_config_t*))get_other_id; this->public.get_auth_method = (auth_method_t(*)(sa_config_t*))get_auth_method; this->public.get_ike_sa_lifetime = (u_int32_t(*)(sa_config_t*))get_ike_sa_lifetime; - this->public.get_traffic_selectors_initiator = (size_t(*)(sa_config_t*,traffic_selector_t**[]))get_traffic_selectors_initiator; - this->public.select_traffic_selectors_initiator = (size_t(*)(sa_config_t*,traffic_selector_t*[],size_t,traffic_selector_t**[]))select_traffic_selectors_initiator; - this->public.get_traffic_selectors_responder = (size_t(*)(sa_config_t*,traffic_selector_t**[]))get_traffic_selectors_responder; - this->public.select_traffic_selectors_responder = (size_t(*)(sa_config_t*,traffic_selector_t*[],size_t,traffic_selector_t**[]))select_traffic_selectors_responder; + this->public.get_my_traffic_selectors = (linked_list_t*(*)(sa_config_t*))get_my_traffic_selectors; + this->public.select_my_traffic_selectors = (linked_list_t*(*)(sa_config_t*,linked_list_t*))select_my_traffic_selectors; + this->public.get_other_traffic_selectors = (linked_list_t*(*)(sa_config_t*))get_other_traffic_selectors; + this->public.select_other_traffic_selectors = (linked_list_t*(*)(sa_config_t*,linked_list_t*))select_other_traffic_selectors; this->public.get_proposals = (linked_list_t*(*)(sa_config_t*))get_proposals; this->public.select_proposal = (proposal_t*(*)(sa_config_t*,linked_list_t*))select_proposal; - this->public.add_traffic_selector_initiator = (void(*)(sa_config_t*,traffic_selector_t*))add_traffic_selector_initiator; - this->public.add_traffic_selector_responder = (void(*)(sa_config_t*,traffic_selector_t*))add_traffic_selector_responder; + this->public.add_my_traffic_selector = (void(*)(sa_config_t*,traffic_selector_t*))add_my_traffic_selector; + this->public.add_other_traffic_selector = (void(*)(sa_config_t*,traffic_selector_t*))add_other_traffic_selector; this->public.add_proposal = (void(*)(sa_config_t*,proposal_t*))add_proposal; this->public.destroy = (void(*)(sa_config_t*))destroy; @@ -355,10 +329,9 @@ sa_config_t *sa_config_create(id_type_t my_id_type, char *my_id, id_type_t other /* init private members*/ this->select_traffic_selectors = select_traffic_selectors; - this->get_traffic_selectors = get_traffic_selectors; this->proposals = linked_list_create(); - this->ts_initiator = linked_list_create(); - this->ts_responder = linked_list_create(); + this->my_ts = linked_list_create(); + this->other_ts = linked_list_create(); this->auth_method = auth_method; this->ike_sa_lifetime = ike_sa_lifetime; diff --git a/Source/charon/config/sa_config.h b/Source/charon/config/sa_config.h index 4fd7305f6..6ecf71d32 100644 --- a/Source/charon/config/sa_config.h +++ b/Source/charon/config/sa_config.h @@ -89,69 +89,49 @@ struct sa_config_t { u_int32_t (*get_ike_sa_lifetime) (sa_config_t *this); /** - * @brief Get configured traffic selectors for initiator site. + * @brief Get configured traffic selectors for our site. * - * Returns a pointer to an allocated array, in which - * pointers to traffic selectors are stored. - * - * @warning Resulting pointer array must be freed! - * @warning Traffic selectors in array must be destroyed! + * Returns a list with all traffic selectors for the local + * site. List and items MUST NOT be freed nor modified. * * @param this calling object - * @param[out] traffic_selectors pointer where traffic selectors will be allocated - * @return number of returned traffic selectors + * @return list with traffic selectors */ - size_t (*get_traffic_selectors_initiator) (sa_config_t *this, traffic_selector_t **traffic_selectors[]); + linked_list_t *(*get_my_traffic_selectors) (sa_config_t *this); /** - * @brief Get configured traffic selectors for responder site. - * - * Returns a pointer to an allocated array, in which - * pointers to traffic selectors are stored. + * @brief Get configured traffic selectors for others site. * - * @warning Resulting pointer array must be freed! - * @warning Traffic selectors in array must be destroyed! + * Returns a list with all traffic selectors for the remote + * site. List and items MUST NOT be freed nor modified. * * @param this calling object - * @param[out] traffic_selectors pointer where traffic selectors will be allocated - * @return number of returned traffic selectors + * @return list with traffic selectors */ - size_t (*get_traffic_selectors_responder) (sa_config_t *this, traffic_selector_t **traffic_selectors[]); + linked_list_t *(*get_other_traffic_selectors) (sa_config_t *this); /** - * @brief Select traffic selectors from a supplied list for initiator. + * @brief Select traffic selectors from a supplied list for local site. * - * Returns a pointer to an allocated array, in which - * pointers to traffic selectors are stored. - * - * @warning Resulting pointer array must be freed! - * @warning Traffic selectors in array must be destroyed! + * Resulted list and traffic selectors must be destroyed after usage. * * @param this calling object - * @param supplied pointer to an array of ts to select from. - * @param count number of ts stored at supplied - * @param[out] traffic_selectors pointer where selected traffic selectors will be allocated - * @return number of selected traffic selectors + * @param supplied linked list with traffic selectors + * @return list containing the selected traffic selectors */ - size_t (*select_traffic_selectors_initiator) (sa_config_t *this, traffic_selector_t *supplied[], size_t count, traffic_selector_t **selected[]); + linked_list_t *(*select_my_traffic_selectors) (sa_config_t *this, linked_list_t *supplied); /** - * @brief Select traffic selectors from a supplied list for responder. - * - * Returns a pointer to an allocated array, in which - * pointers to traffic selectors are stored. + * @brief Select traffic selectors from a supplied list for remote site. * - * @warning Resulting pointer array must be freed! - * @warning Traffic selectors in array must be destroyed! + * Resulted list and traffic selectors must be destroyed after usage. * * @param this calling object - * @param supplied pointer to an array of ts to select from. - * @param count number of ts stored at supplied - * @param[out] traffic_selectors pointer where selected traffic selectors will be allocated - * @return number of selected traffic selectors + * @param supplied linked list with traffic selectors + * @return list containing the selected traffic selectors */ - size_t (*select_traffic_selectors_responder) (sa_config_t *this, traffic_selector_t *supplied[], size_t count, traffic_selector_t **selected[]); + linked_list_t *(*select_other_traffic_selectors) (sa_config_t *this, linked_list_t *supplied); /** * @brief Get the list of internally stored proposals. @@ -177,28 +157,28 @@ struct sa_config_t { proposal_t *(*select_proposal) (sa_config_t *this, linked_list_t *proposals); /** - * @brief Add a traffic selector to the list for initiator. + * @brief Add a traffic selector to the list for local site. * - * Added proposal will be cloned. + * After add, proposal is owned by sa_config. * * @warning Do not add while other threads are reading. * * @param this calling object * @param traffic_selector traffic_selector to add */ - void (*add_traffic_selector_initiator) (sa_config_t *this, traffic_selector_t *traffic_selector); + void (*add_my_traffic_selector) (sa_config_t *this, traffic_selector_t *traffic_selector); /** - * @brief Add a traffic selector to the list for responder. + * @brief Add a traffic selector to the list for remote site. * - * Added proposal will be cloned. + * After add, proposal is owned by sa_config. * * @warning Do not add while other threads are reading. * * @param this calling object * @param traffic_selector traffic_selector to add */ - void (*add_traffic_selector_responder) (sa_config_t *this, traffic_selector_t *traffic_selector); + void (*add_other_traffic_selector) (sa_config_t *this, traffic_selector_t *traffic_selector); /** * @brief Add a proposal to the list. diff --git a/Source/charon/config/traffic_selector.c b/Source/charon/config/traffic_selector.c index e0744899b..33b176414 100644 --- a/Source/charon/config/traffic_selector.c +++ b/Source/charon/config/traffic_selector.c @@ -53,22 +53,14 @@ struct private_traffic_selector_t { * begin of address range */ union { - struct { - u_int32_t from_addr_ipv4; - }; - struct { - }; + u_int32_t from_addr_ipv4; }; /** * end of address range */ union { - struct { - u_int32_t to_addr_ipv4; - }; - struct { - }; + u_int32_t to_addr_ipv4; }; /** @@ -334,7 +326,7 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts this->public.get_from_port = (u_int16_t(*)(traffic_selector_t*))get_from_port; this->public.get_to_port = (u_int16_t(*)(traffic_selector_t*))get_to_port; this->public.get_type = (ts_type_t(*)(traffic_selector_t*))get_type; - this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol; + this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol; this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone; this->public.destroy = (void(*)(traffic_selector_t*))destroy; diff --git a/Source/charon/config/traffic_selector.h b/Source/charon/config/traffic_selector.h index 662795352..553a73e66 100644 --- a/Source/charon/config/traffic_selector.h +++ b/Source/charon/config/traffic_selector.h @@ -24,6 +24,7 @@ #define _TRAFFIC_SELECTOR_H_ #include <types.h> +#include <network/host.h> typedef enum ts_type_t ts_type_t; @@ -33,7 +34,8 @@ typedef enum ts_type_t ts_type_t; * @ingroup config */ enum ts_type_t { - /* + + /** * A range of IPv4 addresses, represented by two four (4) octet * values. The first value is the beginning IPv4 address * (inclusive) and the second value is the ending IPv4 address @@ -41,7 +43,8 @@ enum ts_type_t { * addresses are considered to be within the list. */ TS_IPV4_ADDR_RANGE = 7, - /* + + /** * A range of IPv6 addresses, represented by two sixteen (16) * octet values. The first value is the beginning IPv6 address * (inclusive) and the second value is the ending IPv6 address @@ -75,7 +78,7 @@ struct traffic_selector_t { /** * @brief Compare two traffic selectors, and create a new one - * which is the largest subset of bouth (subnet & port). + * which is the largest subset of both (subnet & port). * * Resulting traffic_selector is newly created and must be destroyed. * diff --git a/Source/charon/encoding/payloads/ts_payload.c b/Source/charon/encoding/payloads/ts_payload.c index 59b732245..4bc6ccbc8 100644 --- a/Source/charon/encoding/payloads/ts_payload.c +++ b/Source/charon/encoding/payloads/ts_payload.c @@ -243,26 +243,23 @@ static iterator_t * create_traffic_selector_substructure_iterator (private_ts_pa /** * Implementation of ts_payload_t.get_traffic_selectors. */ -static size_t get_traffic_selectors(private_ts_payload_t *this, traffic_selector_t **traffic_selectors[]) +static linked_list_t *get_traffic_selectors(private_ts_payload_t *this) { - traffic_selector_t **ts; + traffic_selector_t *ts; iterator_t *iterator; - int i = 0; + linked_list_t *ts_list = linked_list_create(); - ts = allocator_alloc(sizeof(traffic_selector_t*) * this->number_of_traffic_selectors); iterator = this->traffic_selectors->create_iterator(this->traffic_selectors, TRUE); while (iterator->has_next(iterator)) { traffic_selector_substructure_t *ts_substructure; iterator->current(iterator, (void**)&ts_substructure); - ts[i] = ts_substructure->get_traffic_selector(ts_substructure); - i++; + ts = ts_substructure->get_traffic_selector(ts_substructure); + ts_list->insert_last(ts_list, (void*)ts); } iterator->destroy(iterator); - /* return values */ - *traffic_selectors = ts; - return this->number_of_traffic_selectors; + return ts_list; } /** @@ -330,7 +327,7 @@ ts_payload_t *ts_payload_create(bool is_initiator) this->public.set_initiator = (void (*) (ts_payload_t *,bool)) set_initiator; this->public.add_traffic_selector_substructure = (void (*) (ts_payload_t *,traffic_selector_substructure_t *)) add_traffic_selector_substructure; this->public.create_traffic_selector_substructure_iterator = (iterator_t* (*) (ts_payload_t *,bool)) create_traffic_selector_substructure_iterator; - this->public.get_traffic_selectors = (size_t (*) (ts_payload_t *, traffic_selector_t**[])) get_traffic_selectors; + this->public.get_traffic_selectors = (linked_list_t *(*) (ts_payload_t *)) get_traffic_selectors; /* private functions */ this->compute_length = compute_length; @@ -349,19 +346,23 @@ ts_payload_t *ts_payload_create(bool is_initiator) /* * Described in header */ -ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, traffic_selector_t *traffic_selectors[], size_t count) +ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, linked_list_t *traffic_selectors) { - int i; + iterator_t *iterator; + traffic_selector_t *ts; + traffic_selector_substructure_t *ts_substructure; private_ts_payload_t *this; this = (private_ts_payload_t*)ts_payload_create(is_initiator); - for (i = 0; i < count; i++) + iterator = traffic_selectors->create_iterator(traffic_selectors, TRUE); + while (iterator->has_next(iterator)) { - traffic_selector_substructure_t *ts_substructure; - ts_substructure = traffic_selector_substructure_create_from_traffic_selector(traffic_selectors[i]); + iterator->current(iterator, (void**)&ts); + ts_substructure = traffic_selector_substructure_create_from_traffic_selector(ts); this->public.add_traffic_selector_substructure(&(this->public), ts_substructure); } + iterator->destroy(iterator); return &(this->public); } diff --git a/Source/charon/encoding/payloads/ts_payload.h b/Source/charon/encoding/payloads/ts_payload.h index f285612f7..b7e3b80fb 100644 --- a/Source/charon/encoding/payloads/ts_payload.h +++ b/Source/charon/encoding/payloads/ts_payload.h @@ -25,7 +25,7 @@ #define TS_PAYLOAD_H_ #include <types.h> -#include <utils/iterator.h> +#include <utils/linked_list.h> #include <config/traffic_selector.h> #include <encoding/payloads/payload.h> #include <encoding/payloads/traffic_selector_substructure.h> @@ -104,17 +104,14 @@ struct ts_payload_t { iterator_t *(*create_traffic_selector_substructure_iterator) (ts_payload_t *this, bool forward); /** - * @brief Create an array of the nested traffic_selector_t's. + * @brief Get a list of nested traffic selectors as traffic_selector_t. * - * @warning Array must be freed after usage. - * - * @warning traffic selector must be destroyed after usage. + * Resulting list and its traffic selectors must be destroyed after usage * * @param this calling ts_payload_t object - * @param[out] address of the array of traffic_selectors will be written here. - * @return number of ts in the allocated array + * @return list of traffic selectors */ - size_t (*get_traffic_selectors) (ts_payload_t *this, traffic_selector_t **traffic_selectors[]); + linked_list_t *(*get_traffic_selectors) (ts_payload_t *this); /** * @brief Destroys an ts_payload_t object. @@ -138,19 +135,18 @@ struct ts_payload_t { ts_payload_t *ts_payload_create(bool is_initiator); /** - * @brief Creates ts_payload with the specified traffic_selectors. + * @brief Creates ts_payload with a list of traffic_selector_t * * * @param is_initiator * - TRUE if this payload is of type TSi * - FALSE if this payload is of type TSr - * @param traffic_selectors an array of traffic_selector_t-pointers - * @param count number of pointers in the array + * @param traffic_selectors list of traffic selectors to include * @return ts_payload_t object * * @ingroup payloads */ -ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, traffic_selector_t *traffic_selectors[], size_t count); +ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, linked_list_t *traffic_selectors); #endif //TS_PAYLOAD_H_ diff --git a/Source/charon/sa/child_sa.c b/Source/charon/sa/child_sa.c index 6754e8022..d6e6ce60d 100644 --- a/Source/charon/sa/child_sa.c +++ b/Source/charon/sa/child_sa.c @@ -59,20 +59,16 @@ struct private_child_sa_t { u_int32_t esp_spi; /** + * reqid used for this child_sa + */ + u_int32_t reqid; + + /** * CHILD_SAs own logger */ logger_t *logger; }; - -/** - * Implementation of child_sa_t.get_spi. - */ -static u_int32_t get_spi(private_child_sa_t *this) -{ - return 0; -} - /** * Implements child_sa_t.alloc */ @@ -244,7 +240,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus src->get_address(src), dst->get_address(dst)); status = charon->kernel_interface->add_sa(charon->kernel_interface, src, dst, - spi, protocols[i], FALSE, + spi, protocols[i], + this->reqid, enc_algo, enc_key, int_algo, int_key, mine); /* clean up for next round */ @@ -262,6 +259,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus return FAILED; } + } } return SUCCESS; @@ -292,6 +290,7 @@ static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t * { return FAILED; } + return SUCCESS; } @@ -307,6 +306,73 @@ static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_ { return FAILED; } + + return SUCCESS; +} + +static status_t add_policy(private_child_sa_t *this, linked_list_t *my_ts, linked_list_t *other_ts) +{ + traffic_selector_t *local_ts, *remote_ts; + host_t *my_net, *other_net; + u_int8_t my_mask, other_mask; + int family; + chunk_t from_addr, to_addr; + u_int16_t from_port, to_port; + + my_ts->get_first(my_ts, (void**)&local_ts); + other_ts->get_first(other_ts, (void**)&remote_ts); + + + family = local_ts->get_type(local_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6; + from_addr = local_ts->get_from_address(local_ts); + //to_addr = local_ts->get_to_address(local_ts); + from_port = local_ts->get_from_port(local_ts); + to_port = local_ts->get_to_port(local_ts); + if (from_port != to_port) + { + from_port = 0; + } + my_net = host_create_from_chunk(family, from_addr, from_port); + allocator_free_chunk(&from_addr); + my_mask = 16; + + family = remote_ts->get_type(remote_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6; + from_addr = remote_ts->get_from_address(remote_ts); + //to_addr = remote_ts->get_to_address(remote_ts); + from_port = remote_ts->get_from_port(remote_ts); + to_port = remote_ts->get_to_port(remote_ts); + if (from_port != to_port) + { + from_port = 0; + } + other_net = host_create_from_chunk(family, from_addr, from_port); + allocator_free_chunk(&from_addr); + other_mask = 16; + + charon->kernel_interface->add_policy(charon->kernel_interface, + this->me, this->other, + my_net, other_net, + my_mask, other_mask, + XFRM_POLICY_OUT, + 0, this->ah_spi, this->esp_spi, + this->reqid); + + charon->kernel_interface->add_policy(charon->kernel_interface, + this->me, this->other, + other_net, my_net, + other_mask, my_mask, + XFRM_POLICY_IN, + 0, this->ah_spi, this->esp_spi, + this->reqid); + + charon->kernel_interface->add_policy(charon->kernel_interface, + this->me, this->other, + other_net, my_net, + other_mask, my_mask, + XFRM_POLICY_FWD, + 0, this->ah_spi, this->esp_spi, + this->reqid); + return SUCCESS; } @@ -324,13 +390,14 @@ static void destroy(private_child_sa_t *this) */ child_sa_t * child_sa_create(host_t *me, host_t* other) { + static u_int32_t reqid = 123; private_child_sa_t *this = allocator_alloc_thing(private_child_sa_t); /* public functions */ - this->public.get_spi = (u_int32_t(*)(child_sa_t*))get_spi; this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add; this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update; + this->public.add_policy = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policy; this->public.destroy = (void(*)(child_sa_t*))destroy; /* private data */ @@ -339,6 +406,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other) this->other = other; this->ah_spi = 0; this->esp_spi = 0; + this->reqid = reqid++; return (&this->public); } diff --git a/Source/charon/sa/child_sa.h b/Source/charon/sa/child_sa.h index 260c4f29c..4316f262a 100644 --- a/Source/charon/sa/child_sa.h +++ b/Source/charon/sa/child_sa.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2005 Jan Hutter, Martin Willi + * Copyright (C) 2005 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -31,31 +31,84 @@ typedef struct child_sa_t child_sa_t; /** - * @brief Represents a CHILD_SA between to hosts. + * @brief Represents multiple IPsec SAs between two hosts. + * + * A child_sa_t contains multiple SAs. SAs for both + * directions are managed in one child_sa_t object, and + * if both AH and ESP is set up, both protocols are managed + * by one child_sa_t. This means we can have two or + * in the AH+ESP case four IPsec-SAs in one child_sa_t. + * + * The procedure for child sa setup is as follows: + * - A gets SPIs for a proposal via child_sa_t.alloc + * - A send the updated proposal to B + * - B selects a suitable proposal + * - B calls child_sa_t.add to add and update the selected proposal + * - B sends the updated proposal to A + * - A calls child_sa_t.update to update the already allocated SPIs with the chosen proposal * * * @b Constructors: - * - child_sa_create + * - child_sa_create() * * @ingroup sa */ struct child_sa_t { /** - * @brief Returns the SPI value of this CHILD_SA. + * @brief Allocate SPIs for a given proposals. * - * AH and ESP are using 4 byte SPI values. - * - * @param this calling object - * @return 4 Byte SPI value + * Since the kernel manages SPIs for us, we need + * to allocate them. If the proposal contains more + * than one protocol, for each protocol an SPI is + * allocated. SPIs are stored internally and written + * back to the proposal. + * + * @param this calling object + * @param proposal proposal for which SPIs are allocated */ - u_int32_t (*get_spi) (child_sa_t *this); - - status_t (*alloc)(child_sa_t *this, linked_list_t* proposals); + + /** + * @brief Install the kernel SAs for a proposal. + * + * Since the kernel manages SPIs for us, we need + * to allocate them. If the proposal contains more + * than one protocol, for each protocol an SPI is + * allocated. SPIs are stored internally and written + * back to the proposal. + * + * @param this calling object + * @param proposal proposal for which SPIs are allocated + * @param prf_plus key material to use for key derivation + */ status_t (*add)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus); + + /** + * @brief Install the kernel SAs for a proposal, if SPIs already allocated. + * + * This one updates the SAs in the kernel, which are + * allocated via alloc, with a selected proposals. + * + * @param this calling object + * @param proposal proposal for which SPIs are allocated + * @param prf_plus key material to use for key derivation + */ status_t (*update)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus); - + + /** + * @brief Install the policies using some traffic selectors. + * + * Spplied lists of traffic_selector_t's specify the policies + * to use for this child sa. + * + * @param this calling object + * @param my_ts traffic selectors for local site + * @param other_ts traffic selectors for remote site + * @return SUCCESS or FAILED + */ + status_t (*add_policy) (child_sa_t *this, linked_list_t *my_ts, linked_list_t *other_ts); + /** * @brief Destroys a child_sa. * @@ -65,11 +118,12 @@ struct child_sa_t { }; /** - * @brief Constructor to create a new CHILD_SA. + * @brief Constructor to create a new child_sa_t. * - * @param protocol_id protocol id (AH or ESP) of CHILD_SA - * @param prf_plus prf_plus_t object use to derive shared secrets + * @param me own address + * @param other remote address * @return child_sa_t object + * * @ingroup sa */ child_sa_t * child_sa_create(host_t *me, host_t *other); diff --git a/Source/charon/sa/states/ike_auth_requested.c b/Source/charon/sa/states/ike_auth_requested.c index 328971579..41dfb2ce8 100644 --- a/Source/charon/sa/states/ike_auth_requested.c +++ b/Source/charon/sa/states/ike_auth_requested.c @@ -73,6 +73,21 @@ struct private_ike_auth_requested_t { chunk_t ike_sa_init_reply_data; /** + * Proposal to setup CHILD_SA + */ + proposal_t *proposal; + + /** + * Traffic selectors applicable at our site + */ + linked_list_t *my_ts; + + /** + * Traffic selectors applicable at remote site + */ + linked_list_t *other_ts; + + /** * Child sa created in ike_sa_init_requested */ child_sa_t *child_sa; @@ -168,6 +183,8 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i signer_t *signer = NULL; status_t status; host_t *my_host, *other_host; + chunk_t seed; + prf_plus_t *prf_plus; if (ike_auth_reply->get_exchange_type(ike_auth_reply) != IKE_AUTH) { @@ -291,10 +308,46 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i { return status; } - + + /* install child SAs for AH and esp */ + if (!this->child_sa) + { + this->logger->log(this->logger, CONTROL, "No CHILD_SA requested, no CHILD_SA built"); + } + if (!this->proposal) + { + this->logger->log(this->logger, CONTROL, "Proposal negotiation failed, no CHILD_SA built"); + } + else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0) + { + this->logger->log(this->logger, CONTROL, "Traffic selector negotiation failed, no CHILD_SA built"); + } + else + { + seed = allocator_alloc_as_chunk(this->sent_nonce.len + this->received_nonce.len); + memcpy(seed.ptr, this->sent_nonce.ptr, this->sent_nonce.len); + memcpy(seed.ptr + this->sent_nonce.len, this->received_nonce.ptr, this->received_nonce.len); + prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); + allocator_free_chunk(&seed); + + status = this->child_sa->update(this->child_sa, this->proposal, prf_plus); + prf_plus->destroy(prf_plus); + if (status != SUCCESS) + { + this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); + return DELETE_ME; + } + status = this->child_sa->add_policy(this->child_sa, this->my_ts, this->other_ts); + if (status != SUCCESS) + { + this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA"); + return DELETE_ME; + } + this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); + } + this->ike_sa->set_last_replied_message_id(this->ike_sa,ike_auth_reply->get_message_id(ike_auth_reply)); /* create new state */ - my_host = this->ike_sa->get_my_host(this->ike_sa); other_host = this->ike_sa->get_other_host(this->ike_sa); this->logger->log(this->logger, AUDIT, "IKE_SA established between %s - %s, authenticated peer with %s", @@ -343,8 +396,6 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa { proposal_t *proposal, *proposal_tmp; linked_list_t *proposal_list; - chunk_t seed; - prf_plus_t *prf_plus; /* get his selected proposal */ proposal_list = sa_payload->get_proposals(sa_payload); @@ -383,28 +434,9 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained a not offered proposal. Deleting IKE_SA"); return DELETE_ME; } - - /* install child SAs for AH and esp */ - seed = allocator_alloc_as_chunk(this->sent_nonce.len + this->received_nonce.len); - memcpy(seed.ptr, this->sent_nonce.ptr, this->sent_nonce.len); - memcpy(seed.ptr + this->sent_nonce.len, this->received_nonce.ptr, this->received_nonce.len); - prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); - allocator_free_chunk(&seed); - if (this->child_sa) - { - if (this->child_sa->update(this->child_sa, proposal, prf_plus) != SUCCESS) - { - this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); - prf_plus->destroy(prf_plus); - proposal->destroy(proposal); - return DELETE_ME; - } - this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); - } - - prf_plus->destroy(prf_plus); - proposal->destroy(proposal); + /* apply proposal */ + this->proposal = proposal; return SUCCESS; } @@ -435,41 +467,36 @@ static status_t process_auth_payload(private_ike_auth_requested_t *this, auth_pa */ static status_t process_ts_payload(private_ike_auth_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload) { - traffic_selector_t **ts_received, **ts_selected; - size_t ts_received_count, ts_selected_count; - status_t status = SUCCESS; + linked_list_t *ts_received, *ts_selected; + traffic_selector_t *ts; /* get ts form payload */ - ts_received_count = ts_payload->get_traffic_selectors(ts_payload, &ts_received); + ts_received = ts_payload->get_traffic_selectors(ts_payload); /* select ts depending on payload type */ if (ts_initiator) { - ts_selected_count = this->sa_config->select_traffic_selectors_initiator(this->sa_config, ts_received, ts_received_count, &ts_selected); + ts_selected = this->sa_config->select_my_traffic_selectors(this->sa_config, ts_received); + this->my_ts = ts_selected; } else { - ts_selected_count = this->sa_config->select_traffic_selectors_responder(this->sa_config, ts_received, ts_received_count, &ts_selected); + ts_selected = this->sa_config->select_other_traffic_selectors(this->sa_config, ts_received); + this->other_ts = ts_selected; } /* check if the responder selected valid proposals */ - if (ts_selected_count != ts_received_count) + if (ts_selected->get_count(ts_selected) != ts_received->get_count(ts_received)) { this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained not offered traffic selectors."); } /* cleanup */ - while(ts_received_count--) + while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS) { - traffic_selector_t *ts = *ts_received + ts_received_count; ts->destroy(ts); } - allocator_free(ts_received); - while(ts_selected_count--) - { - traffic_selector_t *ts = *ts_selected + ts_selected_count; - ts->destroy(ts); - } - allocator_free(ts_selected); - return status; + ts_received->destroy(ts_received); + + return SUCCESS; } /** @@ -552,6 +579,28 @@ static void destroy(private_ike_auth_requested_t *this) { this->child_sa->destroy(this->child_sa); } + if (this->my_ts) + { + traffic_selector_t *ts; + while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + this->my_ts->destroy(this->my_ts); + } + if (this->other_ts) + { + traffic_selector_t *ts; + while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + this->other_ts->destroy(this->other_ts); + } + if (this->proposal) + { + this->proposal->destroy(this->proposal); + } allocator_free(this); } /** @@ -561,7 +610,29 @@ static void destroy_after_state_change(private_ike_auth_requested_t *this) { allocator_free_chunk(&(this->received_nonce)); allocator_free_chunk(&(this->sent_nonce)); - allocator_free_chunk(&(this->ike_sa_init_reply_data)); + allocator_free_chunk(&(this->ike_sa_init_reply_data)); + if (this->my_ts) + { + traffic_selector_t *ts; + while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + this->my_ts->destroy(this->my_ts); + } + if (this->other_ts) + { + traffic_selector_t *ts; + while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + this->other_ts->destroy(this->other_ts); + } + if (this->proposal) + { + this->proposal->destroy(this->proposal); + } allocator_free(this); } @@ -591,6 +662,9 @@ ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk this->sent_nonce = sent_nonce; this->ike_sa_init_reply_data = ike_sa_init_reply_data; this->logger = this->ike_sa->get_logger(this->ike_sa); + this->my_ts = NULL; + this->other_ts = NULL; + this->proposal = NULL; this->child_sa = child_sa; return &(this->public); diff --git a/Source/charon/sa/states/ike_sa_init_requested.c b/Source/charon/sa/states/ike_sa_init_requested.c index 55f38883f..7f80c3477 100644 --- a/Source/charon/sa/states/ike_sa_init_requested.c +++ b/Source/charon/sa/states/ike_sa_init_requested.c @@ -543,22 +543,13 @@ static status_t build_sa_payload (private_ike_sa_init_requested_t *this, message */ static status_t build_tsi_payload (private_ike_sa_init_requested_t *this, message_t *request) { - traffic_selector_t **traffic_selectors; - size_t traffic_selectors_count; + linked_list_t *ts_list; ts_payload_t *ts_payload; sa_config_t *sa_config; sa_config = this->ike_sa->get_sa_config(this->ike_sa); - traffic_selectors_count = sa_config->get_traffic_selectors_initiator(sa_config,&traffic_selectors); - ts_payload = ts_payload_create_from_traffic_selectors(TRUE,traffic_selectors, traffic_selectors_count); - - /* cleanup traffic selectors */ - while(traffic_selectors_count--) - { - traffic_selector_t *ts = *traffic_selectors + traffic_selectors_count; - ts->destroy(ts); - } - allocator_free(traffic_selectors); + ts_list = sa_config->get_my_traffic_selectors(sa_config); + ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_list); this->logger->log(this->logger, CONTROL|LEVEL2, "Add TSi payload to message"); request->add_payload(request,(payload_t *) ts_payload); @@ -571,22 +562,13 @@ static status_t build_tsi_payload (private_ike_sa_init_requested_t *this, messag */ static status_t build_tsr_payload (private_ike_sa_init_requested_t *this, message_t *request) { - traffic_selector_t **traffic_selectors; - size_t traffic_selectors_count; + linked_list_t *ts_list; ts_payload_t *ts_payload; sa_config_t *sa_config; sa_config = this->ike_sa->get_sa_config(this->ike_sa); - traffic_selectors_count = sa_config->get_traffic_selectors_responder(sa_config,&traffic_selectors); - ts_payload = ts_payload_create_from_traffic_selectors(FALSE,traffic_selectors, traffic_selectors_count); - - /* cleanup traffic selectors */ - while(traffic_selectors_count--) - { - traffic_selector_t *ts = *traffic_selectors + traffic_selectors_count; - ts->destroy(ts); - } - allocator_free(traffic_selectors); + ts_list = sa_config->get_other_traffic_selectors(sa_config); + ts_payload = ts_payload_create_from_traffic_selectors(FALSE, ts_list); this->logger->log(this->logger, CONTROL|LEVEL2, "Add TSr payload to message"); request->add_payload(request,(payload_t *) ts_payload); diff --git a/Source/charon/sa/states/ike_sa_init_responded.c b/Source/charon/sa/states/ike_sa_init_responded.c index 70baa5143..87e1318f2 100644 --- a/Source/charon/sa/states/ike_sa_init_responded.c +++ b/Source/charon/sa/states/ike_sa_init_responded.c @@ -79,6 +79,21 @@ struct private_ike_sa_init_responded_t { sa_config_t *sa_config; /** + * Proposal selected for CHILD_SA + */ + proposal_t *proposal; + + /** + * Traffic selectors applicable at our site + */ + linked_list_t *my_ts; + + /** + * Traffic selectors applicable at remote site + */ + linked_list_t *other_ts; + + /** * Assigned logger. * * Is logger of ike_sa! @@ -157,8 +172,11 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t signer_t *signer; status_t status; host_t *my_host, *other_host; - - + chunk_t seed; + prf_plus_t *prf_plus; + child_sa_t *child_sa; + + if (request->get_exchange_type(request) != IKE_AUTH) { this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state ike_sa_init_responded", @@ -313,7 +331,44 @@ static status_t process_message(private_ike_sa_init_responded_t *this, message_t return DELETE_ME; } - /* create new state */my_host = this->ike_sa->get_my_host(this->ike_sa); + /* install child SAs for AH and esp */ + if (!this->proposal) + { + this->logger->log(this->logger, CONTROL, "Proposal negotiation failed, no CHILD_SA built"); + } + else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0) + { + this->logger->log(this->logger, CONTROL, "Traffic selector negotiation failed, no CHILD_SA built"); + } + else + { + seed = allocator_alloc_as_chunk(this->received_nonce.len + this->sent_nonce.len); + memcpy(seed.ptr, this->received_nonce.ptr, this->received_nonce.len); + memcpy(seed.ptr + this->received_nonce.len, this->sent_nonce.ptr, this->sent_nonce.len); + prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); + allocator_free_chunk(&seed); + + child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); + + status = child_sa->add(child_sa, this->proposal, prf_plus); + prf_plus->destroy(prf_plus); + if (status != SUCCESS) + { + this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); + return DELETE_ME; + } + status = child_sa->add_policy(child_sa, this->my_ts, this->other_ts); + if (status != SUCCESS) + { + this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA"); + return DELETE_ME; + } + this->ike_sa->add_child_sa(this->ike_sa, child_sa); + } + + /* create new state */ + my_host = this->ike_sa->get_my_host(this->ike_sa); other_host = this->ike_sa->get_other_host(this->ike_sa); this->logger->log(this->logger, AUDIT, "IKE_SA established between %s - %s, authenticated peer with %s", my_host->get_address(my_host), other_host->get_address(other_host), @@ -390,11 +445,6 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo proposal_t *proposal, *proposal_tmp; linked_list_t *proposal_list; sa_payload_t *sa_response; - child_sa_t *child_sa; - prf_plus_t *prf_plus; - chunk_t seed; - - /* TODO: child sa stuff */ /* get proposals from request */ proposal_list = request->get_proposals(request); @@ -425,30 +475,12 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo return DELETE_ME; } - /* install child SAs for AH and esp */ - seed = allocator_alloc_as_chunk(this->received_nonce.len + this->sent_nonce.len); - memcpy(seed.ptr, this->received_nonce.ptr, this->received_nonce.len); - memcpy(seed.ptr + this->received_nonce.len, this->sent_nonce.ptr, this->sent_nonce.len); - prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); - allocator_free_chunk(&seed); - - child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); - if (child_sa->add(child_sa, proposal, prf_plus) != SUCCESS) - { - this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); - prf_plus->destroy(prf_plus); - proposal->destroy(proposal); - return DELETE_ME; - } - this->ike_sa->add_child_sa(this->ike_sa, child_sa); + /* apply proposal */ + this->proposal = proposal; /* create payload with selected propsal */ sa_response = sa_payload_create_from_proposal(proposal); response->add_payload(response, (payload_t*)sa_response); - - prf_plus->destroy(prf_plus); - proposal->destroy(proposal); return SUCCESS; } @@ -462,8 +494,6 @@ static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_p status_t status; authenticator = authenticator_create(this->ike_sa); - - status = authenticator->verify_auth_data(authenticator,auth_request, this->ike_sa_init_request_data,this->sent_nonce,other_id_payload,TRUE); if (status != SUCCESS) @@ -474,7 +504,6 @@ static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_p return DELETE_ME; } - status = authenticator->compute_auth_data(authenticator,&auth_reply, this->ike_sa_init_response_data,this->received_nonce,my_id_payload,FALSE); authenticator->destroy(authenticator); if (status != SUCCESS) @@ -483,7 +512,7 @@ static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_p return DELETE_ME; } - + response->add_payload(response, (payload_t *)auth_reply); return SUCCESS; } @@ -493,47 +522,35 @@ static status_t build_auth_payload(private_ike_sa_init_responded_t *this, auth_p */ static status_t build_ts_payload(private_ike_sa_init_responded_t *this, bool ts_initiator, ts_payload_t *request, message_t* response) { - traffic_selector_t **ts_received, **ts_selected; - size_t ts_received_count, ts_selected_count; + linked_list_t *ts_received, *ts_selected; + traffic_selector_t *ts; status_t status = SUCCESS; ts_payload_t *ts_response; /* build a reply payload with selected traffic selectors */ - ts_received_count = request->get_traffic_selectors(request, &ts_received); + ts_received = request->get_traffic_selectors(request); /* select ts depending on payload type */ if (ts_initiator) { - ts_selected_count = this->sa_config->select_traffic_selectors_initiator(this->sa_config, ts_received, ts_received_count, &ts_selected); + ts_selected = this->sa_config->select_other_traffic_selectors(this->sa_config, ts_received); + this->other_ts = ts_selected; } else { - ts_selected_count = this->sa_config->select_traffic_selectors_responder(this->sa_config, ts_received, ts_received_count, &ts_selected); - } - if(ts_selected_count == 0) - { - this->logger->log(this->logger, AUDIT, "IKE_AUH request did not contain any traffic selectors."); - ts_response = ts_payload_create(ts_initiator); - response->add_payload(response, (payload_t*)ts_response); - } - else - { - ts_response = ts_payload_create_from_traffic_selectors(ts_initiator, ts_selected, ts_selected_count); - response->add_payload(response, (payload_t*)ts_response); + ts_selected = this->sa_config->select_my_traffic_selectors(this->sa_config, ts_received); + this->my_ts = ts_selected; } + ts_response = ts_payload_create_from_traffic_selectors(ts_initiator, ts_selected); + response->add_payload(response, (payload_t*)ts_response); + /* cleanup */ - while(ts_received_count--) - { - traffic_selector_t *ts = *ts_received + ts_received_count; - ts->destroy(ts); - } - allocator_free(ts_received); - while(ts_selected_count--) + while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS) { - traffic_selector_t *ts = *ts_selected + ts_selected_count; ts->destroy(ts); } - allocator_free(ts_selected); + ts_received->destroy(ts_received); + return status; } @@ -577,16 +594,32 @@ static ike_sa_state_t get_state(private_ike_sa_init_responded_t *this) */ static void destroy(private_ike_sa_init_responded_t *this) { - this->logger->log(this->logger, CONTROL | LEVEL3, "Going to destroy ike_sa_init_responded_t state object"); - - this->logger->log(this->logger, CONTROL | LEVEL3, "Destroy received nonce"); allocator_free_chunk(&(this->received_nonce)); - this->logger->log(this->logger, CONTROL | LEVEL3, "Destroy sent nonce"); allocator_free_chunk(&(this->sent_nonce)); - this->logger->log(this->logger, CONTROL | LEVEL3, "Destroy IKE_SA_INIT response octets"); allocator_free_chunk(&(this->ike_sa_init_response_data)); - this->logger->log(this->logger, CONTROL | LEVEL3, "Destroy IKE_SA_INIT request octets"); allocator_free_chunk(&(this->ike_sa_init_request_data)); + if (this->my_ts) + { + traffic_selector_t *ts; + while (this->my_ts->remove_last(this->my_ts, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + this->my_ts->destroy(this->my_ts); + } + if (this->other_ts) + { + traffic_selector_t *ts; + while (this->other_ts->remove_last(this->other_ts, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + this->other_ts->destroy(this->other_ts); + } + if (this->proposal) + { + this->proposal->destroy(this->proposal); + } allocator_free(this); } @@ -616,6 +649,9 @@ ike_sa_init_responded_t *ike_sa_init_responded_create(protected_ike_sa_t *ike_sa this->sent_nonce = sent_nonce; this->ike_sa_init_response_data = ike_sa_init_response_data; this->ike_sa_init_request_data = ike_sa_init_request_data; + this->my_ts = NULL; + this->other_ts = NULL; + this->proposal = NULL; this->logger = this->ike_sa->get_logger(this->ike_sa); return &(this->public); diff --git a/Source/charon/testcases/kernel_interface_test.c b/Source/charon/testcases/kernel_interface_test.c index 8eb2d5f52..400531072 100644 --- a/Source/charon/testcases/kernel_interface_test.c +++ b/Source/charon/testcases/kernel_interface_test.c @@ -37,7 +37,7 @@ void test_kernel_interface(protected_tester_t *tester) { kernel_interface_t *kernel_interface; u_int32_t spi; - host_t *me, *other; + host_t *me, *other, *left, *right; status_t status; u_int8_t enc_key_bytes[] = { @@ -60,20 +60,25 @@ void test_kernel_interface(protected_tester_t *tester) kernel_interface = kernel_interface_create(); - me = host_create(AF_INET, "127.0.0.1", 0); - other = host_create(AF_INET, "127.0.0.1", 0); - - - - status = kernel_interface->get_spi(kernel_interface, me, other, 50, FALSE, &spi); + me = host_create(AF_INET, "192.168.0.2", 0); + other = host_create(AF_INET, "192.168.0.3", 0); + + status = kernel_interface->get_spi(kernel_interface, me, other, 50, 1234, &spi); tester->assert_true(tester, status == SUCCESS, "spi get"); - - status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, FALSE, ENCR_AES_CBC, enc_key,AUTH_UNDEFINED,inc_key,TRUE); - tester->assert_true(tester, status == SUCCESS, "build sa"); - + status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, 1234, ENCR_AES_CBC, enc_key,AUTH_UNDEFINED,inc_key,TRUE); + tester->assert_true(tester, status == SUCCESS, "add sa"); + + left = host_create(AF_INET, "10.1.0.0", 0); + right = host_create(AF_INET, "10.2.0.0", 0); + + status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_OUT, 0, TRUE, FALSE, 1234); + tester->assert_true(tester, status == SUCCESS, "add policy"); + me->destroy(me); other->destroy(other); + left->destroy(left); + right->destroy(right); kernel_interface->destroy(kernel_interface); diff --git a/Source/charon/testcases/sa_config_test.c b/Source/charon/testcases/sa_config_test.c index 2dfb1118b..162e39ec3 100644 --- a/Source/charon/testcases/sa_config_test.c +++ b/Source/charon/testcases/sa_config_test.c @@ -163,18 +163,18 @@ void test_sa_config(protected_tester_t *tester) /* icmp request, should be discarded */ ts_request[3] = traffic_selector_create_from_string(1, TS_IPV4_ADDR_RANGE, "0.0.0.0", 0, "255.255.255.255", 65535); - sa_config->add_traffic_selector_initiator(sa_config, ts_policy[0]); - sa_config->add_traffic_selector_initiator(sa_config, ts_policy[1]); - sa_config->add_traffic_selector_initiator(sa_config, ts_policy[2]); + sa_config->add_my_traffic_selector(sa_config, ts_policy[0]); + sa_config->add_my_traffic_selector(sa_config, ts_policy[1]); + sa_config->add_my_traffic_selector(sa_config, ts_policy[2]); - count = sa_config->get_traffic_selectors_initiator(sa_config, &ts_result); + count = sa_config->get_my_traffic_selectors(sa_config, &ts_result); tester->assert_true(tester, (count == 3), "ts get count"); ts_result[0]->destroy(ts_result[0]); ts_result[0]->destroy(ts_result[1]); ts_result[0]->destroy(ts_result[2]); allocator_free(ts_result); - count = sa_config->select_traffic_selectors_initiator(sa_config, &ts_request[0], 4, &ts_result); + count = sa_config->select_my_traffic_selectors(sa_config, &ts_request[0], 4, &ts_result); tester->assert_true(tester, (count == 3), "ts select count"); diff --git a/Source/charon/testcases/testcases.c b/Source/charon/testcases/testcases.c index 8c391ca33..b4eadef91 100644 --- a/Source/charon/testcases/testcases.c +++ b/Source/charon/testcases/testcases.c @@ -257,7 +257,7 @@ int main() //tester->perform_tests(tester,all_tests); - tester->perform_test(tester,&child_sa_test); + tester->perform_test(tester,&kernel_interface_test); tester->destroy(tester); diff --git a/Source/charon/threads/kernel_interface.c b/Source/charon/threads/kernel_interface.c index f5273e100..efb058c29 100644 --- a/Source/charon/threads/kernel_interface.c +++ b/Source/charon/threads/kernel_interface.c @@ -26,7 +26,6 @@ #include <sys/types.h> #include <sys/socket.h> #include <linux/netlink.h> -#include <linux/xfrm.h> #include <pthread.h> #include <unistd.h> #include <fcntl.h> @@ -43,6 +42,34 @@ #define KERNEL_ESP 50 #define KERNEL_AH 51 +#define SPD_PRIORITY 1024 + + +typedef struct xfrm_data_t xfrm_data_t; + +/** + * Lenght/Type/data struct for userdata in xfrm + */ +struct xfrm_data_t { + /** + * length of the data + */ + u_int16_t length; + /** + * type of data + */ + u_int16_t type; + /** + * and the data itself, for different purposes + */ + union { + /* algorithm */ + struct xfrm_algo algo; + /* policy tmpl */ + struct xfrm_user_tmpl tmpl[2]; + }; +}; + typedef struct netlink_message_t netlink_message_t; @@ -57,25 +84,24 @@ struct netlink_message_t { struct nlmsghdr hdr; union { + /* error message */ struct nlmsgerr e; - struct xfrm_userspi_info spi; + /* message for spi allocation */ + struct xfrm_userspi_info spi; + /* message for SA installation */ struct { struct xfrm_usersa_info sa; - u_int8_t data[512]; + }; + /* message for policy manipulation */ + struct xfrm_userpolicy_id id; + /* message for policy installation */ + struct { + struct xfrm_userpolicy_info policy; }; }; + u_int8_t data[512]; }; -typedef struct netlink_algo_t netlink_algo_t; - -/** - * Add length and type to xfrm_algo - */ -struct netlink_algo_t { - u_int16_t length; - u_int16_t type; - struct xfrm_algo algo; -}; typedef struct private_kernel_interface_t private_kernel_interface_t; @@ -157,9 +183,13 @@ mapping_t kernel_integrity_algs_m[] = { }; -static status_t get_spi(private_kernel_interface_t *this, host_t *src, host_t *dest, protocol_id_t protocol, bool tunnel_mode, u_int32_t *spi) +static status_t get_spi(private_kernel_interface_t *this, + host_t *src, host_t *dest, + protocol_id_t protocol, u_int32_t reqid, + u_int32_t *spi) { netlink_message_t request, *response; + status_t status = SUCCESS; memset(&request, 0, sizeof(request)); request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.spi))); @@ -167,8 +197,8 @@ static status_t get_spi(private_kernel_interface_t *this, host_t *src, host_t *d request.hdr.nlmsg_type = XFRM_MSG_ALLOCSPI; request.spi.info.saddr = src->get_xfrm_addr(src); request.spi.info.id.daddr = dest->get_xfrm_addr(dest); - request.spi.info.mode = tunnel_mode; - /* TODO: this should be done with getprotobyname() */ + request.spi.info.mode = TRUE; /* tunnel mode */ + request.spi.info.reqid = reqid; request.spi.info.id.proto = (protocol == ESP) ? KERNEL_ESP : KERNEL_AH; request.spi.info.family = PF_INET; request.spi.min = 100; @@ -176,27 +206,25 @@ static status_t get_spi(private_kernel_interface_t *this, host_t *src, host_t *d if (this->send_message(this, &request, &response) != SUCCESS) { - return FAILED; + status = FAILED; } - - if (response->hdr.nlmsg_type == NLMSG_ERROR) + else if (response->hdr.nlmsg_type == NLMSG_ERROR) { - return FAILED; + status = FAILED; } - - if (response->hdr.nlmsg_type != XFRM_MSG_NEWSA) + else if (response->hdr.nlmsg_type != XFRM_MSG_NEWSA) { - return FAILED; + status = FAILED; } else if (response->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(response->sa))) { - return FAILED; + status = FAILED; } *spi = response->sa.id.spi; allocator_free(response); - return SUCCESS; + return status; } static status_t add_sa( private_kernel_interface_t *this, @@ -204,7 +232,7 @@ static status_t add_sa( private_kernel_interface_t *this, host_t *other, u_int32_t spi, int protocol, - bool tunnel_mode, + u_int32_t reqid, encryption_algorithm_t enc_alg, chunk_t encryption_key, integrity_algorithm_t int_alg, @@ -213,7 +241,7 @@ static status_t add_sa( private_kernel_interface_t *this, { netlink_message_t request, *response; memset(&request, 0, sizeof(request)); - + status_t status; request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; request.hdr.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; @@ -222,12 +250,11 @@ static status_t add_sa( private_kernel_interface_t *this, request.sa.id.daddr = other->get_xfrm_addr(other); request.sa.id.spi = spi; - /* TODO: this should be done with getprotobyname() */ request.sa.id.proto = (protocol == ESP) ? KERNEL_ESP : KERNEL_AH; request.sa.family = me->get_family(me); - request.sa.mode = tunnel_mode; + request.sa.mode = TRUE; /* tunnel mode */ request.sa.replay_window = 0; //sa->replay_window; ??? - request.sa.reqid = 0; //sa->reqid; ??? + request.sa.reqid = reqid; request.sa.lft.soft_byte_limit = XFRM_INF; request.sa.lft.soft_packet_limit = XFRM_INF; request.sa.lft.hard_byte_limit = XFRM_INF; @@ -237,43 +264,139 @@ static status_t add_sa( private_kernel_interface_t *this, if (enc_alg != ENCR_UNDEFINED) { - netlink_algo_t *nla = (netlink_algo_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len); + xfrm_data_t *data = (xfrm_data_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len); - nla->type = XFRMA_ALG_CRYPT; - nla->length = sizeof(netlink_algo_t) + encryption_key.len; - nla->algo.alg_key_len = encryption_key.len * 8; + data->type = XFRMA_ALG_CRYPT; + data->length = 4 + sizeof(data->algo) + encryption_key.len; + data->algo.alg_key_len = encryption_key.len * 8; - strcpy(nla->algo.alg_name, mapping_find(kernel_encryption_algs_m, enc_alg)); - memcpy(nla->algo.alg_key, encryption_key.ptr, encryption_key.len); + strcpy(data->algo.alg_name, mapping_find(kernel_encryption_algs_m, enc_alg)); + memcpy(data->algo.alg_key, encryption_key.ptr, encryption_key.len); - request.hdr.nlmsg_len += nla->length; + request.hdr.nlmsg_len += data->length; } if (int_alg != AUTH_UNDEFINED) { - netlink_algo_t *nla = (netlink_algo_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len); + xfrm_data_t *data = (xfrm_data_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len); - nla->type = XFRMA_ALG_AUTH; - nla->length = sizeof(netlink_algo_t) + integrity_key.len; - nla->algo.alg_key_len = integrity_key.len * 8; - strcpy(nla->algo.alg_name, mapping_find(kernel_integrity_algs_m, int_alg)); - memcpy(nla->algo.alg_key, integrity_key.ptr, integrity_key.len); + data->type = XFRMA_ALG_AUTH; + data->length = 4 + sizeof(data->algo) + integrity_key.len; + data->algo.alg_key_len = integrity_key.len * 8; + strcpy(data->algo.alg_name, mapping_find(kernel_integrity_algs_m, int_alg)); + memcpy(data->algo.alg_key, integrity_key.ptr, integrity_key.len); - request.hdr.nlmsg_len += nla->length; + request.hdr.nlmsg_len += data->length; } /* add IPComp here*/ if (this->send_message(this, &request, &response) != SUCCESS) { - allocator_free(response); - return FAILED; + status = FAILED; + } + else if (response->hdr.nlmsg_type != NLMSG_ERROR) + { + status = FAILED; + } + else if (response->e.error) + { + status = FAILED; } allocator_free(response); return SUCCESS; } +static status_t add_policy(private_kernel_interface_t *this, + host_t *me, host_t *other, + host_t *src, host_t *dst, + u_int8_t src_hostbits, u_int8_t dst_hostbits, + int direction, int upper_proto, + bool ah, bool esp, + u_int32_t reqid) +{ + netlink_message_t request, *response; + status_t status = SUCCESS; + + memset(&request, 0, sizeof(request)); + request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + + request.policy.sel.sport = htons(src->get_port(src)); + request.policy.sel.dport = htons(dst->get_port(dst)); + request.policy.sel.sport_mask = (request.policy.sel.sport) ? ~0 : 0; + request.policy.sel.dport_mask = (request.policy.sel.dport) ? ~0 : 0; + request.policy.sel.saddr = src->get_xfrm_addr(src); + request.policy.sel.daddr = dst->get_xfrm_addr(dst); + request.policy.sel.prefixlen_s = src_hostbits; + request.policy.sel.prefixlen_d = dst_hostbits; + request.policy.sel.proto = upper_proto; + request.policy.sel.family = src->get_family(src); + + request.policy.dir = direction; + request.policy.priority = SPD_PRIORITY; + request.policy.action = XFRM_POLICY_ALLOW; + request.policy.share = XFRM_SHARE_ANY; + + request.policy.lft.soft_byte_limit = XFRM_INF; + request.policy.lft.soft_packet_limit = XFRM_INF; + request.policy.lft.hard_byte_limit = XFRM_INF; + request.policy.lft.hard_packet_limit = XFRM_INF; + + request.hdr.nlmsg_type = XFRM_MSG_NEWPOLICY; + request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.policy))); + + if (esp || ah) + { + xfrm_data_t *data; + int tmpl_pos = 0; + data = (xfrm_data_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len); + data->type = XFRMA_TMPL; + if (esp) + { + data->tmpl[tmpl_pos].reqid = reqid; + data->tmpl[tmpl_pos].id.proto = KERNEL_ESP; + data->tmpl[tmpl_pos].aalgos = data->tmpl[tmpl_pos].ealgos = data->tmpl[tmpl_pos].calgos = ~0; + data->tmpl[tmpl_pos].mode = TRUE; + + data->tmpl[tmpl_pos].saddr = me->get_xfrm_addr(me); + data->tmpl[tmpl_pos].id.daddr = me->get_xfrm_addr(other); + + tmpl_pos++; + } + if (ah) + { + data->tmpl[tmpl_pos].reqid = reqid; + data->tmpl[tmpl_pos].id.proto = KERNEL_AH; + data->tmpl[tmpl_pos].aalgos = data->tmpl[tmpl_pos].ealgos = data->tmpl[tmpl_pos].calgos = ~0; + data->tmpl[tmpl_pos].mode = TRUE; + + data->tmpl[tmpl_pos].saddr = me->get_xfrm_addr(me); + data->tmpl[tmpl_pos].id.daddr = other->get_xfrm_addr(other); + + tmpl_pos++; + } + data->length = 4 + sizeof(struct xfrm_user_tmpl) * tmpl_pos; + request.hdr.nlmsg_len += data->length; + } + + if (this->send_message(this, &request, &response) != SUCCESS) + { + status = FAILED; + } + else if (response->hdr.nlmsg_type != NLMSG_ERROR) + { + status = FAILED; + } + else if (response->e.error) + { + status = FAILED; + } + + allocator_free(response); + return status; +} + static status_t send_message(private_kernel_interface_t *this, netlink_message_t *request, netlink_message_t **response) { @@ -418,11 +541,9 @@ kernel_interface_t *kernel_interface_create() private_kernel_interface_t *this = allocator_alloc_thing(private_kernel_interface_t); /* public functions */ - this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,bool,u_int32_t*))get_spi; - - this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,int,bool,encryption_algorithm_t,chunk_t,integrity_algorithm_t,chunk_t,bool))add_sa; - - + this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi; + this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,encryption_algorithm_t,chunk_t,integrity_algorithm_t,chunk_t,bool))add_sa; + this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*, host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int,bool,bool,u_int32_t))add_policy; this->public.destroy = (void(*)(kernel_interface_t*)) destroy; /* private members */ @@ -447,6 +568,10 @@ kernel_interface_t *kernel_interface_create() charon->kill(charon, "Unable to create netlink thread"); } + //host_t *all = host_create(AF_INET, "0.0.0.0", 500); + //add_policy(this, all, all, all, all, 0, 0, XFRM_POLICY_OUT, 17, FALSE, FALSE, 0); + + charon->logger_manager->enable_logger_level(charon->logger_manager, TESTER, FULL); return (&this->public); } diff --git a/Source/charon/threads/kernel_interface.h b/Source/charon/threads/kernel_interface.h index 7f57a04d6..17b636dd1 100644 --- a/Source/charon/threads/kernel_interface.h +++ b/Source/charon/threads/kernel_interface.h @@ -23,6 +23,7 @@ #ifndef KERNEL_INTERFACE_H_ #define KERNEL_INTERFACE_H_ +#include <linux/xfrm.h> #include <network/host.h> #include <encoding/payloads/proposal_substructure.h> @@ -44,7 +45,11 @@ struct kernel_interface_t { * * @todo Fix spi range */ - status_t (*get_spi) (kernel_interface_t *this, host_t *src, host_t *dest, protocol_id_t protocol, bool tunnel_mode, u_int32_t *spi); + status_t (*get_spi) (kernel_interface_t *this, + host_t *src, host_t *dest, + protocol_id_t protocol, + u_int32_t reqid, + u_int32_t *spi); /** * @brief Create an SA. @@ -54,17 +59,24 @@ struct kernel_interface_t { * @todo Cleanup method params */ status_t (*add_sa)(kernel_interface_t *this, - host_t *src, - host_t *dst, + host_t *src, host_t *dst, u_int32_t spi, - int protocol, - bool tunnel_mode, + protocol_id_t protocol, + u_int32_t reqid, encryption_algorithm_t enc_alg, chunk_t encryption_key, integrity_algorithm_t int_alg, chunk_t integrity_key, bool replace); + status_t (*add_policy) (kernel_interface_t *this, + host_t *me, host_t *other, + host_t *src, host_t *dst, + u_int8_t src_hostbits, u_int8_t dst_hostbits, + int direction, int upper_proto, + bool ah, bool esp, + u_int32_t reqid); + /** * @brief Destroys a kernel_interface object. * |