diff --git a/configure.in b/configure.in index 8dfbc40a3..5099c452b 100644 --- a/configure.in +++ b/configure.in @@ -141,7 +141,7 @@ AC_OUTPUT( src/pluto/Makefile src/whack/Makefile src/charon/Makefile - src/charon/testing/Makefile +dnl src/charon/testing/Makefile src/stroke/Makefile src/ipsec/Makefile src/starter/Makefile diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index b22c12ebf..a0f85417d 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . testing +# SUBDIRS = . testing ipsec_PROGRAMS = charon diff --git a/src/charon/config/connections/local_connection_store.c b/src/charon/config/connections/local_connection_store.c index 31d466e4d..c6e982e23 100644 --- a/src/charon/config/connections/local_connection_store.c +++ b/src/charon/config/connections/local_connection_store.c @@ -75,7 +75,7 @@ static connection_t *get_connection_by_hosts(private_local_connection_store_t *t connection_t *found = NULL; this->logger->log(this->logger, CONTROL|LEVEL1, "looking for connection for host pair %s...%s", - my_host->get_address(my_host), other_host->get_address(other_host)); + my_host->get_string(my_host), other_host->get_string(other_host)); pthread_mutex_lock(&(this->mutex)); iterator = this->connections->create_iterator(this->connections, TRUE); @@ -108,8 +108,8 @@ static connection_t *get_connection_by_hosts(private_local_connection_store_t *t this->logger->log(this->logger, CONTROL|LEVEL2, "candidate connection \"%s\": %s...%s (prio=%d)", candidate->get_name(candidate), - candidate_my_host->get_address(candidate_my_host), - candidate_other_host->get_address(candidate_other_host), + candidate_my_host->get_string(candidate_my_host), + candidate_other_host->get_string(candidate_other_host), prio); if (prio > best_prio) @@ -129,8 +129,8 @@ static connection_t *get_connection_by_hosts(private_local_connection_store_t *t this->logger->log(this->logger, CONTROL, "found matching connection \"%s\": %s...%s (prio=%d)", found->get_name(found), - found_my_host->get_address(found_my_host), - found_other_host->get_address(found_other_host), + found_my_host->get_string(found_my_host), + found_other_host->get_string(found_other_host), best_prio); found = found->clone(found); @@ -243,8 +243,8 @@ void log_connections(private_local_connection_store_t *this, logger_t *logger, c logger->log(logger, CONTROL, " \"%s\": %s...%s", current->get_name(current), - my_host->get_address(my_host), - other_host->get_address(other_host)); + my_host->get_string(my_host), + other_host->get_string(other_host)); } } iterator->destroy(iterator); diff --git a/src/charon/config/policies/policy.c b/src/charon/config/policies/policy.c index 561c28f12..152c157a8 100644 --- a/src/charon/config/policies/policy.c +++ b/src/charon/config/policies/policy.c @@ -29,7 +29,7 @@ #include #include -#include +#include typedef struct private_policy_t private_policy_t; @@ -105,9 +105,9 @@ struct private_policy_t { u_int32_t jitter; /** - * select_traffic_selectors for both + * logger */ - linked_list_t *(*select_traffic_selectors) (private_policy_t *,linked_list_t*,linked_list_t*); + logger_t *logger; }; /** @@ -201,21 +201,6 @@ static linked_list_t *get_other_traffic_selectors(private_policy_t *this, traffi return this->other_ts; } -/** - * Implementation of private_policy_t.select_my_traffic_selectors - */ -static linked_list_t *select_my_traffic_selectors(private_policy_t *this, linked_list_t *supplied) -{ - return this->select_traffic_selectors(this, this->my_ts, supplied); -} - -/** - * Implementation of private_policy_t.select_other_traffic_selectors - */ -static linked_list_t *select_other_traffic_selectors(private_policy_t *this, linked_list_t *supplied) -{ - return this->select_traffic_selectors(this, this->other_ts, supplied); -} /** * Implementation of private_policy_t.select_traffic_selectors */ @@ -225,6 +210,9 @@ static linked_list_t *select_traffic_selectors(private_policy_t *this, linked_li traffic_selector_t *supplied_ts, *stored_ts, *selected_ts; linked_list_t *selected = linked_list_create(); + this->logger->log(this->logger, CONTROL|LEVEL1, + "selecting traffic selectors for %s host", + stored == this->my_ts ? "local" : "remote"); stored_iter = stored->create_iterator(stored, TRUE); supplied_iter = supplied->create_iterator(supplied, TRUE); @@ -240,11 +228,19 @@ static linked_list_t *select_traffic_selectors(private_policy_t *this, linked_li { supplied_iter->current(supplied_iter, (void**)&supplied_ts); + this->logger->log(this->logger, CONTROL|LEVEL2, + " stored %s <=> %s received", + stored_ts->get_string(stored_ts), + supplied_ts->get_string(supplied_ts)); + selected_ts = stored_ts->get_subset(stored_ts, supplied_ts); if (selected_ts) { /* got a match, add to list */ selected->insert_last(selected, (void*)selected_ts); + + this->logger->log(this->logger, CONTROL|LEVEL1, " got a match: %s", + selected_ts->get_string(selected_ts)); } } } @@ -254,6 +250,22 @@ static linked_list_t *select_traffic_selectors(private_policy_t *this, linked_li return selected; } +/** + * Implementation of private_policy_t.select_my_traffic_selectors + */ +static linked_list_t *select_my_traffic_selectors(private_policy_t *this, linked_list_t *supplied) +{ + return select_traffic_selectors(this, this->my_ts, supplied); +} + +/** + * Implementation of private_policy_t.select_other_traffic_selectors + */ +static linked_list_t *select_other_traffic_selectors(private_policy_t *this, linked_list_t *supplied) +{ + return select_traffic_selectors(this, this->other_ts, supplied); +} + /** * Implementation of policy_t.get_proposal_iterator */ @@ -365,7 +377,7 @@ static u_int32_t get_hard_lifetime(private_policy_t *this) /** * Implements policy_t.clone. */ -static policy_t *clone(private_policy_t *this) +static policy_t *clone_(private_policy_t *this) { private_policy_t *clone = (private_policy_t*)policy_create(this->name, this->my_id->clone(this->my_id), @@ -507,7 +519,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o this->public.add_updown = (void(*)(policy_t*,char*))add_updown; this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime; this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime; - this->public.clone = (policy_t*(*)(policy_t*))clone; + this->public.clone = (policy_t*(*)(policy_t*))clone_; this->public.destroy = (void(*)(policy_t*))destroy; /* apply init values */ @@ -521,10 +533,10 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o /* initialize private members*/ this->my_ca = NULL; this->other_ca = NULL; - this->select_traffic_selectors = select_traffic_selectors; this->proposals = linked_list_create(); this->my_ts = linked_list_create(); this->other_ts = linked_list_create(); + this->logger = logger_manager->get_logger(logger_manager, CONFIG); return (&this->public); } diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c index 203efe299..b0b0a13ce 100644 --- a/src/charon/config/traffic_selector.c +++ b/src/charon/config/traffic_selector.c @@ -21,13 +21,14 @@ * for more details. */ +#include +#include +#include + #include "traffic_selector.h" #include #include -#include -#include -#include typedef struct private_traffic_selector_t private_traffic_selector_t; @@ -76,9 +77,9 @@ struct private_traffic_selector_t { u_int16_t to_port; /** - * Logger reference + * string representation of this traffic selector */ - logger_t *logger; + char *string; }; /** @@ -86,6 +87,122 @@ struct private_traffic_selector_t { */ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port); +/** + * update the string representation of this traffic selector + */ +static void update_string(private_traffic_selector_t *this) +{ + char buf[256]; + struct protoent *proto; + struct servent *serv; + char *serv_proto = NULL; + char proto_str[8] = ""; + char addr_str[INET6_ADDRSTRLEN]; + char port_str[16] = ""; + char mask_str[8] = ""; + char proto_port_str[32] = ""; + bool has_proto = FALSE, has_port = FALSE; + + if (this->type == TS_IPV4_ADDR_RANGE) + { + u_int32_t from_no, to_no, bit; + u_int8_t mask = 32; + + /* build address string */ + from_no = htonl(this->from_addr_ipv4); + to_no = htonl(this->to_addr_ipv4); + inet_ntop(AF_INET, &from_no, addr_str, sizeof(addr_str)); + + /* build network mask string */ + for (bit = 0; bit < 32; bit++) + { + if ((1<protocol) + { + proto = getprotobynumber(this->protocol); + if (proto) + { + snprintf(proto_str, sizeof(proto_str), "%s", proto->p_name); + serv_proto = proto->p_name; + } + else + { + snprintf(proto_str, sizeof(proto_str), "%d", this->protocol); + } + has_proto = TRUE; + } + + /* build port string */ + if (this->from_port == this->to_port) + { + serv = getservbyport(htons(this->from_port), serv_proto); + if (serv) + { + snprintf(port_str, sizeof(port_str), "%s", serv->s_name); + } + else + { + snprintf(port_str, sizeof(port_str), "%d", this->from_port); + } + has_port = TRUE; + } + else if (!(this->from_port == 0 && this->to_port == 0xFFFF)) + { + snprintf(port_str, sizeof(port_str), "%d-%d", + this->from_port, this->to_port); + has_port = TRUE; + } + + /* concatenate port & proto string */ + if (has_proto && has_port) + { + snprintf(proto_port_str, sizeof(proto_port_str), "[%s/%s]", + proto_str, port_str); + } + else if (has_proto) + { + snprintf(proto_port_str, sizeof(proto_port_str), "[%s]", proto_str); + } + else if (has_port) + { + snprintf(proto_port_str, sizeof(proto_port_str), "[%s]", port_str); + } + + /* concatenate it all */ + snprintf(buf, sizeof(buf), "%s%s%s", addr_str, mask_str, proto_port_str); + + if (this->string) + { + free(this->string); + } + this->string = strdup(buf); +} + +/** + * implements traffic_selector_t.get_string + */ +static char *get_string(private_traffic_selector_t *this) +{ + return this->string; +} + /** * implements traffic_selector_t.get_subset */ @@ -99,19 +216,12 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_ u_int8_t protocol; private_traffic_selector_t *new_ts; - /* TODO: make output more human readable */ - this->logger->log(this->logger, CONTROL|LEVEL2, - "matching traffic selector ranges %x:%d-%x:%d <=> %x:%d-%x:%d", - this->from_addr_ipv4, this->from_port, this->to_addr_ipv4, this->to_port, - other->from_addr_ipv4, other->from_port, other->to_addr_ipv4, other->to_port); /* calculate the maximum address range allowed for both */ from_addr = max(this->from_addr_ipv4, other->from_addr_ipv4); to_addr = min(this->to_addr_ipv4, other->to_addr_ipv4); if (from_addr > to_addr) { - this->logger->log(this->logger, CONTROL|LEVEL2, - "no match in address range"); - return NULL; + return NULL; } /* calculate the maximum port range allowed for both */ @@ -119,9 +229,7 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_ to_port = min(this->to_port, other->to_port); if (from_port > to_port) { - this->logger->log(this->logger, CONTROL|LEVEL2, - "no match in port range"); - return NULL; + return NULL; } /* select protocol, which is not zero */ @@ -132,10 +240,8 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_ new_ts->from_addr_ipv4 = from_addr; new_ts->to_addr_ipv4 = to_addr; new_ts->type = TS_IPV4_ADDR_RANGE; + update_string(new_ts); - this->logger->log(this->logger, CONTROL|LEVEL2, - "got a match: %x:%d-%x:%d", - new_ts->from_addr_ipv4, new_ts->from_port, new_ts->to_addr_ipv4, new_ts->to_port); return &(new_ts->public); } return NULL; @@ -227,35 +333,6 @@ static u_int8_t get_protocol(private_traffic_selector_t *this) return this->protocol; } -/** - * Implements traffic_selector_t.get_netmask. - */ -static u_int8_t get_netmask(private_traffic_selector_t *this) -{ - switch (this->type) - { - case TS_IPV4_ADDR_RANGE: - { - u_int32_t from, to, bit; - from = htonl(this->from_addr_ipv4); - to = htonl(this->to_addr_ipv4); - for (bit = 0; bit < 32; bit++) - { - if ((1<from_addr_ipv4 == 0) { - chunk_t from = host->get_address_as_chunk(host); + chunk_t from = host->get_address(host); this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr)); this->to_addr_ipv4 = this->from_addr_ipv4; - chunk_free(&from); } } + update_string(this); } /** @@ -281,6 +358,7 @@ static traffic_selector_t *clone_(private_traffic_selector_t *this) { private_traffic_selector_t *clone = traffic_selector_create(this->protocol, this->type, this->from_port, this->to_port); clone->type = this->type; + clone->string = strdup(this->string); switch (clone->type) { case TS_IPV4_ADDR_RANGE: @@ -302,14 +380,15 @@ static traffic_selector_t *clone_(private_traffic_selector_t *this) * Implements traffic_selector_t.destroy. */ static void destroy(private_traffic_selector_t *this) -{ +{ + free(this->string); free(this); } /* * see header */ -traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from_addr, int16_t from_port, chunk_t to_addr, u_int16_t to_port) +traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from_addr, u_int16_t from_port, chunk_t to_addr, u_int16_t to_port) { private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port); @@ -335,6 +414,9 @@ traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_typ return NULL; } } + + update_string(this); + return (&this->public); } @@ -352,7 +434,7 @@ traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t ne chunk_t from; this->type = TS_IPV4_ADDR_RANGE; - from = net->get_address_as_chunk(net); + from = net->get_address(net); this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr)); if (this->from_addr_ipv4 == 0) { @@ -363,7 +445,6 @@ traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t ne { this->to_addr_ipv4 = this->from_addr_ipv4 | ((1 << (32 - netbits)) - 1); } - chunk_free(&from); break; } case AF_INET6: @@ -379,6 +460,8 @@ traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t ne this->to_port = port; } + update_string(this); + return (&this->public); } @@ -419,7 +502,9 @@ traffic_selector_t *traffic_selector_create_from_string(u_int8_t protocol, ts_ty return NULL; } } - + + update_string(this); + return (&this->public); } @@ -432,13 +517,13 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts /* public functions */ this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset; + this->public.get_string = (char*(*)(traffic_selector_t*))get_string; this->public.get_from_address = (chunk_t(*)(traffic_selector_t*))get_from_address; this->public.get_to_address = (chunk_t(*)(traffic_selector_t*))get_to_address; 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_netmask = (u_int8_t(*)(traffic_selector_t*))get_netmask; this->public.update_address_range = (void(*)(traffic_selector_t*,host_t*))update_address_range; this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone_; this->public.destroy = (void(*)(traffic_selector_t*))destroy; @@ -447,7 +532,7 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts this->to_port = to_port; this->protocol = protocol; this->type = type; - this->logger = logger_manager->get_logger(logger_manager, CONFIG); + this->string = NULL; return this; } diff --git a/src/charon/config/traffic_selector.h b/src/charon/config/traffic_selector.h index ef0711418..420f97d0f 100644 --- a/src/charon/config/traffic_selector.h +++ b/src/charon/config/traffic_selector.h @@ -82,20 +82,21 @@ struct traffic_selector_t { /** * @brief Compare two traffic selectors, and create a new one * which is the largest subset of both (subnet & port). - * + * * Resulting traffic_selector is newly created and must be destroyed. - * + * * @param this first to compare * @param other second to compare * @return * - created subset of them * - or NULL if no match between this and other */ - traffic_selector_t *(*get_subset) (traffic_selector_t *this, traffic_selector_t *other); + traffic_selector_t *(*get_subset) (traffic_selector_t *this, + traffic_selector_t *other); /** * @brief Clone a traffic selector. - * + * * @param this traffic selector to clone * @return clone of it */ @@ -103,12 +104,9 @@ struct traffic_selector_t { /** * @brief Get starting address of this ts as a chunk. - * - * Data is in network order and represents the address. - * Size depends on protocol. - * - * Resulting chunk data is allocated and must be freed! - * + * + * Chunk is in network order gets allocated. + * * @param this calling object * @return chunk containing the address */ @@ -116,12 +114,9 @@ struct traffic_selector_t { /** * @brief Get ending address of this ts as a chunk. - * - * Data is in network order and represents the address. - * Size depends on protocol. - * - * Resulting chunk data is allocated and must be freed! - * + * + * Chunk is in network order gets allocated. + * * @param this calling object * @return chunk containing the address */ @@ -140,10 +135,10 @@ struct traffic_selector_t { /** * @brief Get ending port of this ts. - * + * * Port is in host order, since the parser converts it. * Size depends on protocol. - * + * * @param this calling object * @return port */ @@ -151,51 +146,47 @@ struct traffic_selector_t { /** * @brief Get the type of the traffic selector. - * + * * @param this calling obect * @return ts_type_t specifying the type */ ts_type_t (*get_type) (traffic_selector_t *this); - + /** * @brief Get the protocol id of this ts. - * + * * @param this calling obect * @return protocol id */ u_int8_t (*get_protocol) (traffic_selector_t *this); - - /** - * @brief Get the netmask of the address range. - * - * Returns the number of bits associated to the subnet. - * (As the "24" in "192.168.0.0/24"). This is approximated - * if the address range is not a complete subnet! Since Linux - * does not support full IP address ranges (yet), we can't do this - * (much) better. - * - * @param this calling obect - * @return netmask as "bits for subnet" - */ - u_int8_t (*get_netmask) (traffic_selector_t *this); - + /** * @brief Update the address of a traffic selector. - * + * * Update the address range of a traffic selector, * if the current address is 0.0.0.0. The new address range * starts from the supplied address and also ends there * (which means it is a one-host-address-range ;-). - * + * * @param this calling obect * @param host host_t specifying the address range */ void (*update_address_range) (traffic_selector_t *this, host_t* host); /** - * @brief Destroys the ts object + * @brief Get a string representation of the traffic selector. + * + * String points to internal data, do not free/modify. * * @param this calling object + * @return pointer to a string. + */ + char* (*get_string) (traffic_selector_t *this); + + /** + * @brief Destroys the ts object + * + * @param this calling object */ void (*destroy) (traffic_selector_t *this); }; @@ -215,7 +206,10 @@ struct traffic_selector_t { * * @ingroup config */ -traffic_selector_t *traffic_selector_create_from_string(u_int8_t protocol, ts_type_t type, char *from_addr, u_int16_t from_port, char *to_addr, u_int16_t to_port); +traffic_selector_t *traffic_selector_create_from_string( + u_int8_t protocol, ts_type_t type, + char *from_addr, u_int16_t from_port, + char *to_addr, u_int16_t to_port); /** * @brief Create a new traffic selector using data read from the net. @@ -236,7 +230,10 @@ traffic_selector_t *traffic_selector_create_from_string(u_int8_t protocol, ts_ty * * @ingroup config */ -traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from_address, int16_t from_port, chunk_t to_address, u_int16_t to_port); +traffic_selector_t *traffic_selector_create_from_bytes( + u_int8_t protocol, ts_type_t type, + chunk_t from_address, u_int16_t from_port, + chunk_t to_address, u_int16_t to_port); /** * @brief Create a new traffic selector defining a whole subnet. @@ -256,6 +253,8 @@ traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_typ * * @ingroup config */ -traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t netbits, u_int8_t protocol, u_int16_t port); +traffic_selector_t *traffic_selector_create_from_subnet( + host_t *net, u_int8_t netbits, + u_int8_t protocol, u_int16_t port); #endif /* TRAFFIC_SELECTOR_H_ */ diff --git a/src/charon/doc/Todo-list.txt b/src/charon/doc/Todo-list.txt index 8ae08fb35..b0835cda8 100644 --- a/src/charon/doc/Todo-list.txt +++ b/src/charon/doc/Todo-list.txt @@ -32,7 +32,7 @@ + doxygen cleanup (charon/lib) + new build environment (autotools?) -/ useable certificate support ++ useable certificate support + more id types (use atodn from pluto) + rewrite certificate storage the clean way + further subjectAltName support diff --git a/src/charon/encoding/payloads/traffic_selector_substructure.c b/src/charon/encoding/payloads/traffic_selector_substructure.c index 6abae042e..2ac746403 100644 --- a/src/charon/encoding/payloads/traffic_selector_substructure.c +++ b/src/charon/encoding/payloads/traffic_selector_substructure.c @@ -56,7 +56,7 @@ struct private_traffic_selector_substructure_t { /** * IP Protocol ID. */ - u_int8_t ip_protocol_id; + u_int8_t ip_protocol_id; /** * Length of this payload. @@ -82,11 +82,6 @@ struct private_traffic_selector_substructure_t { * Ending address. */ chunk_t ending_address; - - /** - * update length - */ - void (*compute_length) (private_traffic_selector_substructure_t *this); }; /** @@ -137,7 +132,6 @@ encoding_rule_t traffic_selector_substructure_encodings[] = { */ static status_t verify(private_traffic_selector_substructure_t *this) { - if (this->start_port > this->end_port) { return FAILED; @@ -161,7 +155,6 @@ static status_t verify(private_traffic_selector_substructure_t *this) return FAILED; } } - return SUCCESS; } @@ -196,6 +189,7 @@ static payload_type_t get_next_type(private_traffic_selector_substructure_t *thi */ static void set_next_type(private_traffic_selector_substructure_t *this,payload_type_t type) { + } /** @@ -206,82 +200,6 @@ static size_t get_length(private_traffic_selector_substructure_t *this) return this->payload_length; } -/** - * Implementation of traffic_selector_substructure_t.get_ts_type. - */ -static ts_type_t get_ts_type (private_traffic_selector_substructure_t *this) -{ - return this->ts_type; -} - -/** - * Implementation of traffic_selector_substructure_t.set_ts_type. - */ -static void set_ts_type (private_traffic_selector_substructure_t *this,ts_type_t ts_type) -{ - this->ts_type = ts_type; -} - -/** - * Implementation of traffic_selector_substructure_t.get_protocol_id. - */ -static u_int8_t get_protocol_id (private_traffic_selector_substructure_t *this) -{ - return this->ip_protocol_id; -} - -/** - * Implementation of traffic_selector_substructure_t.set_protocol_id. - */ -static void set_protocol_id (private_traffic_selector_substructure_t *this,u_int8_t protocol_id) -{ - this->ip_protocol_id = protocol_id; -} - -/** - * Implementation of traffic_selector_substructure_t.get_start_host. - */ -static host_t * get_start_host (private_traffic_selector_substructure_t *this) -{ - return (host_create_from_chunk(AF_INET,this->starting_address, this->start_port)); -} - -/** - * Implementation of traffic_selector_substructure_t.set_start_host. - */ -static void set_start_host (private_traffic_selector_substructure_t *this,host_t *start_host) -{ - this->start_port = start_host->get_port(start_host); - if (this->starting_address.ptr != NULL) - { - chunk_free(&(this->starting_address)); - } - this->starting_address = start_host->get_address_as_chunk(start_host); - this->compute_length(this); -} - -/** - * Implementation of traffic_selector_substructure_t.get_end_host. - */ -static host_t *get_end_host (private_traffic_selector_substructure_t *this) -{ - return (host_create_from_chunk(AF_INET,this->ending_address, this->end_port)); -} - -/** - * Implementation of traffic_selector_substructure_t.set_end_host. - */ -static void set_end_host (private_traffic_selector_substructure_t *this,host_t *end_host) -{ - this->end_port = end_host->get_port(end_host); - if (this->ending_address.ptr != NULL) - { - chunk_free(&(this->ending_address)); - } - this->ending_address = end_host->get_address_as_chunk(end_host); - this->compute_length(this); -} - /** * Implementation of traffic_selector_substructure_t.get_traffic_selector. */ @@ -295,11 +213,12 @@ static traffic_selector_t *get_traffic_selector(private_traffic_selector_substru } /** - * Implementation of private_ts_payload_t.compute_length + * recompute length field of the payload */ void compute_length(private_traffic_selector_substructure_t *this) { - this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH + this->ending_address.len + this->starting_address.len; + this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH + + this->ending_address.len + this->starting_address.len; } /** @@ -329,19 +248,8 @@ traffic_selector_substructure_t *traffic_selector_substructure_create() this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; /* public functions */ - this->public.destroy = (void (*) (traffic_selector_substructure_t *)) destroy; - this->public.get_ts_type = (ts_type_t (*) (traffic_selector_substructure_t *)) get_ts_type; - this->public.set_ts_type = (void (*) (traffic_selector_substructure_t *,ts_type_t)) set_ts_type; - this->public.get_protocol_id = (u_int8_t (*) (traffic_selector_substructure_t *)) get_protocol_id; - this->public.set_protocol_id = (void (*) (traffic_selector_substructure_t *,u_int8_t)) set_protocol_id; - this->public.get_start_host = (host_t * (*) (traffic_selector_substructure_t *))get_start_host; - this->public.set_start_host = (void (*) (traffic_selector_substructure_t *, host_t *))set_start_host; - this->public.get_end_host = (host_t * (*) (traffic_selector_substructure_t *))get_end_host; - this->public.set_end_host = (void (*) (traffic_selector_substructure_t *, host_t *))set_end_host; this->public.get_traffic_selector = (traffic_selector_t* (*)(traffic_selector_substructure_t*))get_traffic_selector; - - /* private functions */ - this->compute_length = compute_length; + this->public.destroy = (void (*) (traffic_selector_substructure_t *)) destroy; /* private variables */ this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH; @@ -368,8 +276,8 @@ traffic_selector_substructure_t *traffic_selector_substructure_create_from_traff this->end_port = traffic_selector->get_to_port(traffic_selector); this->starting_address = traffic_selector->get_from_address(traffic_selector); this->ending_address = traffic_selector->get_to_address(traffic_selector); - - this->compute_length(this); + + compute_length(this); return &(this->public); } diff --git a/src/charon/network/interfaces.c b/src/charon/network/interfaces.c index 7578d579c..b1244c97f 100644 --- a/src/charon/network/interfaces.c +++ b/src/charon/network/interfaces.c @@ -74,7 +74,7 @@ static bool is_local_address(private_interfaces_t *this, host_t *host) while (iterator->iterate(iterator, (void**)&lhost)) { if (host->get_family(host) == lhost->get_family(lhost) && - streq(host->get_address(host), lhost->get_address(lhost))) + streq(host->get_string(host), lhost->get_string(lhost))) { iterator->destroy(iterator); return TRUE; diff --git a/src/charon/network/socket.c b/src/charon/network/socket.c index 4dff479ce..c0c53ff54 100644 --- a/src/charon/network/socket.c +++ b/src/charon/network/socket.c @@ -162,8 +162,8 @@ static status_t receiver(private_socket_t *this, packet_t **packet) pkt->set_destination(pkt, dest); this->logger->log(this->logger, CONTROL|LEVEL1, "received packet: from %s:%d to %s:%d", - source->get_address(source), source->get_port(source), - dest->get_address(dest), dest->get_port(dest)); + source->get_string(source), source->get_port(source), + dest->get_string(dest), dest->get_port(dest)); data_offset = IP_LEN + UDP_LEN; @@ -200,8 +200,8 @@ status_t sender(private_socket_t *this, packet_t *packet) data = packet->get_data(packet); this->logger->log(this->logger, CONTROL|LEVEL1, "sending packet: from %s:%d to %s:%d", - src->get_address(src), src->get_port(src), - dst->get_address(dst), dst->get_port(dst)); + src->get_string(src), src->get_port(src), + dst->get_string(dst), dst->get_port(dst)); /* send data */ sport = src->get_port(src); @@ -404,7 +404,7 @@ static status_t initialize(private_socket_t *this) if (setsockopt(this->natt_fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) { this->logger->log(this->logger, ERROR, - "unable to set UDP_ENCAP on raw socket! NAT-T may fail! error: %s", + "unable to set UDP_ENCAP on NAT-T socket: %s; NAT-T may fail", strerror(errno)); } diff --git a/src/charon/queues/jobs/incoming_packet_job.c b/src/charon/queues/jobs/incoming_packet_job.c index 541d4c1af..e24f625a1 100644 --- a/src/charon/queues/jobs/incoming_packet_job.c +++ b/src/charon/queues/jobs/incoming_packet_job.c @@ -113,8 +113,8 @@ static status_t execute(private_incoming_packet_job_t *this) src = message->get_source(message); dst = message->get_destination(message); this->logger->log(this->logger, CONTROL, "received packet: from %s:%d to %s:%d", - src->get_address(src), src->get_port(src), - dst->get_address(dst), dst->get_port(dst)); + src->get_string(src), src->get_port(src), + dst->get_string(dst), dst->get_port(dst)); status = message->parse_header(message); if (status != SUCCESS) diff --git a/src/charon/queues/send_queue.c b/src/charon/queues/send_queue.c index e92f63043..a24308b69 100644 --- a/src/charon/queues/send_queue.c +++ b/src/charon/queues/send_queue.c @@ -112,8 +112,8 @@ static void add(private_send_queue_t *this, packet_t *packet) src = packet->get_source(packet); dst = packet->get_destination(packet); this->logger->log(this->logger, CONTROL, "sending packet: from %s:%d to %s:%d", - src->get_address(src), src->get_port(src), - dst->get_address(dst), dst->get_port(dst)); + src->get_string(src), src->get_port(src), + dst->get_string(dst), dst->get_port(dst)); pthread_mutex_lock(&this->mutex); this->list->insert_last(this->list, packet); diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 5bffc2578..c9c6794b2 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -22,8 +22,6 @@ * for more details. */ -#include - #include "child_sa.h" #include @@ -48,18 +46,15 @@ typedef struct sa_policy_t sa_policy_t; * for deleting a policy... */ struct sa_policy_t { - - struct { - /** subnet address behind peer peer */ - host_t *net; - /** netmask used for net */ - u_int8_t net_mask; - } me, other; + /** + * Traffic selector for us + */ + traffic_selector_t *my_ts; /** - * Protocol for this policy, such as TCP/UDP/ICMP... + * Traffic selector for other */ - int upper_proto; + traffic_selector_t *other_ts; }; typedef struct private_child_sa_t private_child_sa_t; @@ -343,7 +338,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus /* send SA down to the kernel */ this->logger->log(this->logger, CONTROL|LEVEL2, " SPI 0x%.8x, src %s dst %s", - ntohl(spi), src->get_address(src), dst->get_address(dst)); + ntohl(spi), src->get_string(src), dst->get_string(dst)); status = charon->kernel_interface->add_sa(charon->kernel_interface, src, dst, spi, this->protocol, @@ -432,79 +427,52 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list while (other_iter->has_next(other_iter)) { /* set up policies for every entry in my_ts_list to every entry in other_ts_list */ - int family; - chunk_t from_addr; - u_int16_t from_port, to_port; - sa_policy_t *policy; status_t status; + sa_policy_t *policy; other_iter->current(other_iter, (void**)&other_ts); + if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts)) + { + this->logger->log(this->logger, CONTROL|LEVEL1, + "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)) { - this->logger->log(this->logger, ERROR, + this->logger->log(this->logger, CONTROL|LEVEL1, "CHILD_SA policy uses two different protocols, ignored"); continue; } - policy = malloc_thing(sa_policy_t); - policy->upper_proto = max(my_ts->get_protocol(my_ts), other_ts->get_protocol(other_ts)); - - /* calculate net and ports for local side */ - family = my_ts->get_type(my_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6; - from_addr = my_ts->get_from_address(my_ts); - from_port = my_ts->get_from_port(my_ts); - to_port = my_ts->get_to_port(my_ts); - from_port = (from_port != to_port) ? 0 : from_port; - policy->me.net = host_create_from_chunk(family, from_addr, from_port); - policy->me.net_mask = my_ts->get_netmask(my_ts); - chunk_free(&from_addr); - /* calculate net and ports for remote side */ - family = other_ts->get_type(other_ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6; - from_addr = other_ts->get_from_address(other_ts); - from_port = other_ts->get_from_port(other_ts); - to_port = other_ts->get_to_port(other_ts); - from_port = (from_port != to_port) ? 0 : from_port; - policy->other.net = host_create_from_chunk(family, from_addr, from_port); - policy->other.net_mask = other_ts->get_netmask(other_ts); - chunk_free(&from_addr); - /* install 3 policies: out, in and forward */ status = charon->kernel_interface->add_policy(charon->kernel_interface, - this->me.addr, this->other.addr, - policy->me.net, policy->other.net, - policy->me.net_mask, policy->other.net_mask, - XFRM_POLICY_OUT, policy->upper_proto, - this->protocol, this->reqid, FALSE); - + this->me.addr, this->other.addr, my_ts, other_ts, + POLICY_OUT, this->protocol, this->reqid, FALSE); + status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->other.addr, this->me.addr, - policy->other.net, policy->me.net, - policy->other.net_mask, policy->me.net_mask, - XFRM_POLICY_IN, policy->upper_proto, - this->protocol, this->reqid, FALSE); - + this->other.addr, this->me.addr, other_ts, my_ts, + POLICY_IN, this->protocol, this->reqid, FALSE); + status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->other.addr, this->me.addr, - policy->other.net, policy->me.net, - policy->other.net_mask, policy->me.net_mask, - XFRM_POLICY_FWD, policy->upper_proto, - this->protocol, this->reqid, FALSE); + this->other.addr, this->me.addr, other_ts, my_ts, + POLICY_FWD, this->protocol, this->reqid, FALSE); if (status != SUCCESS) { my_iter->destroy(my_iter); other_iter->destroy(other_iter); - policy->me.net->destroy(policy->me.net); - policy->other.net->destroy(policy->other.net); - free(policy); return status; } - /* add it to the policy list, since we want to know which policies we own */ - this->policies->insert_last(this->policies, policy); + /* 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, (void*)policy); } } my_iter->destroy(my_iter); @@ -533,22 +501,38 @@ static void* get_rekeying_transaction(private_child_sa_t *this) */ 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; *use_time = UNDEFINED_TIME; - - if (inbound) + + iterator = this->policies->create_iterator(this->policies, TRUE); + while (iterator->iterate(iterator, (void**)&policy)) { - status = charon->kernel_interface->query_sa(charon->kernel_interface, - this->me.addr, this->me.spi, - this->protocol, use_time); - } - else - { - status = charon->kernel_interface->query_sa(charon->kernel_interface, - this->other.addr, this->other.spi, - this->protocol, use_time); + 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; } @@ -561,38 +545,44 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name) char use_in_str[12] = "unused"; char use_out_str[12] = "unused"; char rekey_str[12] = "disabled"; - time_t use_in, use_out, now, rekeying; + u_int32_t use_in, use_out, use_fwd, now, rekeying; + status_t status; if (logger == NULL) { logger = this->logger; } - now = time(NULL); - get_use_time(this, TRUE, &use_in); - if (use_in) + now = (u_int32_t)time(NULL); + + /* query SA times */ + status = charon->kernel_interface->query_sa(charon->kernel_interface, + this->me.addr, this->me.spi, this->protocol, &use_in); + if (status == SUCCESS && use_in) { - snprintf(use_in_str, sizeof(use_in_str), "%ds", (int)(now - use_in)); + snprintf(use_in_str, sizeof(use_in_str), "%ds", now - use_in); } - get_use_time(this, FALSE, &use_out); - if (use_out) + status = charon->kernel_interface->query_sa(charon->kernel_interface, + this->other.addr, this->other.spi, this->protocol, &use_out); + if (status == SUCCESS && use_out) { - snprintf(use_out_str, sizeof(use_out_str), "%ds", (int)(now - use_out)); + snprintf(use_out_str, sizeof(use_out_str), "%ds", now - use_out); } + + /* calculate rekey times */ if (this->soft_lifetime) { rekeying = this->soft_lifetime - (now - this->install_time); snprintf(rekey_str, sizeof(rekey_str), "%ds", (int)rekeying); } - logger->log(logger, CONTROL|LEVEL1, + logger->log(logger, CONTROL|LEVEL1, " \"%s\": using %s, SPIs (in/out): 0x%x/0x%x, reqid: %d", name, this->protocol == PROTO_ESP ? "ESP" : "AH", htonl(this->me.spi), htonl(this->other.spi), this->reqid); - - logger->log(logger, CONTROL|LEVEL1, - " \"%s\": state: %s, rekeying: %s, last traffic (in/out): %s/%s", + logger->log(logger, CONTROL|LEVEL1, + " \"%s\": state: %s, rekeying: %s, key age (in/out): %s/%s", name, mapping_find(child_sa_state_m, this->state), rekey_str, use_in_str, use_out_str); @@ -600,55 +590,40 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name) while (iterator->has_next(iterator)) { sa_policy_t *policy; - struct protoent *proto; - char proto_str[8] = ""; - char *proto_name = proto_str; - char my_net_str[8] = ""; - char other_net_str[8] = ""; - char my_port_str[8] = ""; - char other_port_str[8] = ""; - u_int16_t my_port, other_port; + char *my_str; + char *other_str; + char pol_in_str[12] = "unused"; + char pol_out_str[12] = "unused"; + char pol_fwd_str[12] = "unused"; + /* get ts strings */ iterator->current(iterator, (void**)&policy); + my_str = policy->my_ts->get_string(policy->my_ts); + other_str = policy->other_ts->get_string(policy->other_ts); - if (policy->upper_proto) + /* query policy times */ + status = charon->kernel_interface->query_policy(charon->kernel_interface, + policy->other_ts, policy->my_ts, POLICY_IN, &use_in); + if (status == SUCCESS && use_in) { - proto = getprotobynumber(policy->upper_proto); - if (proto) - { - proto_name = proto->p_name; - } - else - { - snprintf(proto_str, sizeof(proto_str), "%d", policy->upper_proto); - } + snprintf(pol_in_str, sizeof(pol_in_str), "%ds", now - use_in); } - if (policy->me.net_mask != 32) + status = charon->kernel_interface->query_policy(charon->kernel_interface, + policy->my_ts, policy->other_ts, POLICY_OUT, &use_out); + if (status == SUCCESS && use_out) { - snprintf(my_net_str, sizeof(my_net_str), "/%d", policy->me.net_mask); + snprintf(pol_out_str, sizeof(pol_out_str), "%ds", now - use_out); } - if (policy->other.net_mask != 32) + status = charon->kernel_interface->query_policy(charon->kernel_interface, + policy->other_ts, policy->my_ts, POLICY_FWD, &use_fwd); + if (status == SUCCESS && use_fwd) { - snprintf(other_net_str, sizeof(other_net_str), "/%d", policy->other.net_mask); - } - my_port = policy->me.net->get_port(policy->me.net); - other_port = policy->other.net->get_port(policy->other.net); - if (my_port) - { - snprintf(my_port_str, sizeof(my_port_str), ":%d", my_port); - } - if (other_port) - { - snprintf(other_port_str, sizeof(other_port_str), ":%d", other_port); + snprintf(pol_fwd_str, sizeof(pol_fwd_str), "%ds", now - use_fwd); } - logger->log(logger, CONTROL, " \"%s\": %s%s%s==%s==%s%s%s", - name, - policy->me.net->get_address(policy->me.net), - my_port_str, my_net_str, - proto_name, - policy->other.net->get_address(policy->other.net), - other_port_str, other_net_str); + logger->log(logger, CONTROL, + " \"%s\": %s====%s, last use (in/out/fwd): %s/%s/%s", + name, my_str, other_str, pol_in_str, pol_out_str, pol_fwd_str); } iterator->destroy(iterator); } @@ -688,16 +663,15 @@ static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t this->logger->log(this->logger, CONTROL|LEVEL1, "updating %s SA 0x%x, from %s:%d..%s:%d to %s:%d..%s:%d", mapping_find(protocol_id_m, this->protocol), ntohl(spi), - src->get_address(src), src->get_port(src), - dst->get_address(dst), dst->get_port(dst), - new_src->get_address(new_src), new_src->get_port(new_src), - new_dst->get_address(new_dst), new_dst->get_port(new_dst)); + src->get_string(src), src->get_port(src), + dst->get_string(dst), dst->get_port(dst), + new_src->get_string(new_src), new_src->get_port(new_src), + new_dst->get_string(new_dst), new_dst->get_port(new_dst)); - status = charon->kernel_interface->update_sa_hosts( - charon->kernel_interface, - src, dst, new_src, new_dst, - src_changes, dst_changes, - spi, this->protocol); + status = charon->kernel_interface->update_sa(charon->kernel_interface, + dst, spi, this->protocol, + new_src, new_dst, + src_changes, dst_changes); if (status != SUCCESS) { @@ -721,26 +695,20 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho status = charon->kernel_interface->add_policy( charon->kernel_interface, new_me, new_other, - policy->me.net, policy->other.net, - policy->me.net_mask, policy->other.net_mask, - XFRM_POLICY_OUT, policy->upper_proto, - this->protocol, this->reqid, TRUE); + policy->my_ts, policy->other_ts, + POLICY_OUT, this->protocol, this->reqid, TRUE); status |= charon->kernel_interface->add_policy( charon->kernel_interface, new_other, new_me, - policy->other.net, policy->me.net, - policy->other.net_mask, policy->me.net_mask, - XFRM_POLICY_IN, policy->upper_proto, - this->protocol, this->reqid, TRUE); + policy->other_ts, policy->my_ts, + POLICY_IN, this->protocol, this->reqid, TRUE); status |= charon->kernel_interface->add_policy( charon->kernel_interface, new_other, new_me, - policy->other.net, policy->me.net, - policy->other.net_mask, policy->me.net_mask, - XFRM_POLICY_FWD, policy->upper_proto, - this->protocol, this->reqid, TRUE); + policy->other_ts, policy->my_ts, + POLICY_FWD, this->protocol, this->reqid, TRUE); if (status != SUCCESS) { @@ -749,7 +717,7 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho } } iterator->destroy(iterator); - + return SUCCESS; } @@ -757,7 +725,7 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho * Implementation of child_sa_t.update_hosts. */ static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other, - int my_changes, int other_changes) + host_diff_t my_changes, host_diff_t other_changes) { if (!my_changes && !other_changes) { @@ -835,21 +803,18 @@ static void destroy(private_child_sa_t *this) { /* let rekeyed policies, as they are used by another child_sa */ charon->kernel_interface->del_policy(charon->kernel_interface, - policy->me.net, policy->other.net, - policy->me.net_mask, policy->other.net_mask, - XFRM_POLICY_OUT, policy->upper_proto); + policy->my_ts, policy->other_ts, + POLICY_OUT); charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other.net, policy->me.net, - policy->other.net_mask, policy->me.net_mask, - XFRM_POLICY_IN, policy->upper_proto); + policy->other_ts, policy->my_ts, + POLICY_IN); charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other.net, policy->me.net, - policy->other.net_mask, policy->me.net_mask, - XFRM_POLICY_FWD, policy->upper_proto); - policy->me.net->destroy(policy->me.net); - policy->other.net->destroy(policy->other.net); + policy->other_ts, policy->my_ts, + POLICY_FWD); + policy->my_ts->destroy(policy->my_ts); + policy->other_ts->destroy(policy->other_ts); free(policy); } this->policies->destroy(this->policies); @@ -876,7 +841,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, 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.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,int,int))update_hosts; + this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies; this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; this->public.set_rekeying_transaction = (void (*)(child_sa_t*,void*))set_rekeying_transaction; diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 01f51c101..33d06a70b 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -169,13 +169,15 @@ struct child_sa_t { * * @warning only call this after update() has been called. * - * @param this calling object - * @param new_me the new local host - * @param new_other the new remote host - * @return SUCCESS or FAILED + * @param this calling object + * @param new_me the new local host + * @param new_other the new remote host + * @param my_diff differences to apply for me + * @param other_diff differences to apply for other + * @return SUCCESS or FAILED */ status_t (*update_hosts) (child_sa_t *this, host_t *new_me, host_t *new_other, - int my_changes, int other_changes); + host_diff_t my_diff, host_diff_t other_diff); /** * @brief Install the policies using some traffic selectors. diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index fc176fa51..c233afc37 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -366,6 +366,8 @@ static status_t transmit_request(private_ike_sa_t *this) status = request->generate(request, this->crypter_out, this->signer_out, &packet); if (status != SUCCESS) { + this->logger->log(this->logger, ERROR, + "request generation failed. transaction discarded"); return FAILED; } } @@ -848,9 +850,9 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) my_id = this->policy->get_my_id(this->policy); other_id = this->policy->get_other_id(this->policy); this->logger->log(this->logger, AUDIT, "IKE_SA established: %s[%s]...%s[%s]", - my_host->get_address(my_host), + my_host->get_string(my_host), my_id->get_string(my_id), - other_host->get_address(other_host), + other_host->get_string(other_host), other_id->get_string(other_id)); send_dpd(this); @@ -1236,9 +1238,9 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name) this->ike_sa_id->get_responder_spi(this->ike_sa_id)); logger->log(logger, CONTROL, " \"%s\": %s[%s]...%s[%s]", name, - my_host->get_address(my_host), + my_host->get_string(my_host), my_id ? my_id->get_string(my_id) : "(unknown)", - other_host->get_address(other_host), + other_host->get_string(other_host), other_id ? other_id->get_string(other_id) : "(unknown)"); iterator = this->child_sas->create_iterator(this->child_sas, TRUE); @@ -1391,9 +1393,9 @@ static void destroy(private_ike_sa_t *this) } this->logger->log(this->logger, AUDIT, "IKE_SA deleted between %s[%s]...%s[%s]", - my_host->get_address(my_host), + my_host->get_string(my_host), my_id ? my_id->get_string(my_id) : "(unknown)", - other_host->get_address(other_host), + other_host->get_string(other_host), other_id ? other_id->get_string(other_id) : "(unknown)"); this->connection->destroy(this->connection); } diff --git a/src/charon/sa/transactions/ike_auth.c b/src/charon/sa/transactions/ike_auth.c index a16379c06..53ba6205c 100644 --- a/src/charon/sa/transactions/ike_auth.c +++ b/src/charon/sa/transactions/ike_auth.c @@ -391,7 +391,7 @@ static void import_certificate(private_ike_auth_t *this, cert_payload_t *cert_pa encoding = cert_payload->get_cert_encoding(cert_payload); if (encoding != CERT_X509_SIGNATURE) { - this->logger->log(this->logger, CONTROL, + this->logger->log(this->logger, ERROR, "certificate payload %s not supported, ignored", enum_name(&cert_encoding_names, encoding)); return; @@ -401,7 +401,7 @@ static void import_certificate(private_ike_auth_t *this, cert_payload_t *cert_pa if (charon->credentials->verify(charon->credentials, cert, &found)) { this->logger->log(this->logger, CONTROL|LEVEL1, - "end entity certificate is trusted"); + "received end entity certificate is trusted, added to store"); if (found) { cert->destroy(cert); @@ -413,8 +413,8 @@ static void import_certificate(private_ike_auth_t *this, cert_payload_t *cert_pa } else { - this->logger->log(this->logger, ERROR, - "end entity certificate is not trusted"); + this->logger->log(this->logger, CONTROL, + "received end entity certificate is not trusted, discarded"); } } diff --git a/src/charon/sa/transactions/ike_sa_init.c b/src/charon/sa/transactions/ike_sa_init.c index 987a5bca4..d66ba8474 100644 --- a/src/charon/sa/transactions/ike_sa_init.c +++ b/src/charon/sa/transactions/ike_sa_init.c @@ -219,7 +219,7 @@ static chunk_t generate_natd_hash(private_ike_sa_init_t *this, this->nat_hasher->allocate_hash(this->nat_hasher, natd_string, &natd_hash); sprintf(buf, "natd_hash(%016llx %016llx %s:%d) == SHA1(", spi_i, spi_r, - host->get_address(host), host->get_port(host)); + host->get_string(host), host->get_port(host)); chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_string); strcat(buf, ") == "); chunk_to_hex(buf + strlen(buf), sizeof(buf) - strlen(buf), natd_hash); @@ -520,7 +520,7 @@ static status_t get_response(private_ike_sa_init_t *this, this->logger->log(this->logger, AUDIT, "no connection for hosts %s...%s found, deleting IKE_SA", - me->get_address(me), other->get_address(other)); + me->get_string(me), other->get_string(other)); return DESTROY_ME; } this->ike_sa->set_connection(this->ike_sa, this->connection); diff --git a/src/charon/threads/kernel_interface.c b/src/charon/threads/kernel_interface.c index c4966f4d3..4bb9a6cea 100644 --- a/src/charon/threads/kernel_interface.c +++ b/src/charon/threads/kernel_interface.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -389,8 +390,8 @@ static void receive_messages(private_kernel_interface_t *this) * list these responses for the sender */ else if (hdr->nlmsg_type == NLMSG_ERROR || - hdr->nlmsg_type == XFRM_MSG_NEWSA || - hdr->nlmsg_type == XFRM_MSG_NEWPOLICY) + hdr->nlmsg_type == XFRM_MSG_NEWSA || + hdr->nlmsg_type == XFRM_MSG_NEWPOLICY) { /* add response to queue */ listed_response = malloc(hdr->nlmsg_len); @@ -408,11 +409,20 @@ static void receive_messages(private_kernel_interface_t *this) } } +/** + * convert a host_t to a struct xfrm_address + */ +static void host2xfrm(host_t *host, xfrm_address_t *xfrm) +{ + chunk_t chunk = host->get_address(host); + memcpy(xfrm, chunk.ptr, max(chunk.len, sizeof(xfrm_address_t))); +} + /** * Implementation of kernel_interface_t.get_spi. */ static status_t get_spi(private_kernel_interface_t *this, - host_t *src, host_t *dest, + host_t *src, host_t *dst, protocol_id_t protocol, u_int32_t reqid, u_int32_t *spi) { @@ -432,8 +442,8 @@ static status_t get_spi(private_kernel_interface_t *this, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userspi_info)); userspi = (struct xfrm_userspi_info*)NLMSG_DATA(hdr); - userspi->info.saddr = src->get_xfrm_addr(src); - userspi->info.id.daddr = dest->get_xfrm_addr(dest); + host2xfrm(src, &userspi->info.saddr); + host2xfrm(dst, &userspi->info.id.daddr); userspi->info.id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; userspi->info.mode = TRUE; /* tunnel mode */ userspi->info.reqid = reqid; @@ -476,9 +486,8 @@ static status_t get_spi(private_kernel_interface_t *this, * Implementation of kernel_interface_t.add_sa. */ static status_t add_sa(private_kernel_interface_t *this, - host_t *me, host_t *other, - u_int32_t spi, protocol_id_t protocol, - u_int32_t reqid, + host_t *src, host_t *dst, u_int32_t spi, + protocol_id_t protocol, u_int32_t reqid, u_int64_t expire_soft, u_int64_t expire_hard, algorithm_t *enc_alg, algorithm_t *int_alg, prf_plus_t *prf_plus, natt_conf_t *natt, @@ -502,12 +511,11 @@ static status_t add_sa(private_kernel_interface_t *this, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); sa = (struct xfrm_usersa_info*)NLMSG_DATA(hdr); - sa->saddr = me->get_xfrm_addr(me); - sa->id.daddr = other->get_xfrm_addr(other); - + host2xfrm(src, &sa->saddr); + host2xfrm(dst, &sa->id.daddr); sa->id.spi = spi; sa->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; - sa->family = me->get_family(me); + sa->family = src->get_family(src); sa->mode = TRUE; /* tunnel mode */ sa->replay_window = 32; sa->reqid = reqid; @@ -595,8 +603,8 @@ static status_t add_sa(private_kernel_interface_t *this, struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); encap->encap_type = UDP_ENCAP_ESPINUDP; - encap->encap_sport = ntohs(natt->sport); - encap->encap_dport = ntohs(natt->dport); + encap->encap_sport = htons(natt->sport); + encap->encap_dport = htons(natt->dport); memset(&encap->encap_oa, 0, sizeof (xfrm_address_t)); /* encap_oa could probably be derived from the * traffic selectors [rfc4306, p39]. In the netlink kernel implementation @@ -633,13 +641,13 @@ static status_t add_sa(private_kernel_interface_t *this, } /** - * Implementation of kernel_interface_t.update_sa_hosts. + * Implementation of kernel_interface_t.update_sa. */ -static status_t update_sa_hosts( +static status_t update_sa( private_kernel_interface_t *this, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, - int src_changes, int dst_changes, + host_diff_t src_changes, host_diff_t dst_changes, u_int32_t spi, protocol_id_t protocol) { unsigned char request[BUFFER_SIZE]; @@ -658,11 +666,11 @@ static status_t update_sa_hosts( hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); - sa_id->daddr = dst->get_xfrm_addr(dst); + host2xfrm(dst, &sa_id->daddr); sa_id->spi = spi; sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; sa_id->family = dst->get_family(dst); - + POS; if (send_message(this, hdr, &update) != SUCCESS) { this->logger->log(this->logger, ERROR, "netlink communication failed"); @@ -687,6 +695,7 @@ static status_t update_sa_hosts( free(update); return FAILED; } + POS; this->logger->log(this->logger, CONTROL|LEVEL2, "updating SA"); update->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; @@ -695,7 +704,7 @@ static status_t update_sa_hosts( struct xfrm_usersa_info *sa = (struct xfrm_usersa_info*)NLMSG_DATA(update); if (src_changes & HOST_DIFF_ADDR) { - sa->saddr = new_src->get_xfrm_addr(new_src); + host2xfrm(new_src, &sa->saddr); } if (dst_changes & HOST_DIFF_ADDR) @@ -703,7 +712,7 @@ static status_t update_sa_hosts( this->logger->log(this->logger, CONTROL|LEVEL2, "destination address changed! replacing SA"); update->nlmsg_type = XFRM_MSG_NEWSA; - sa->id.daddr = new_dst->get_xfrm_addr(new_dst); + host2xfrm(new_dst, &sa->id.daddr); } if (src_changes & HOST_DIFF_PORT || dst_changes & HOST_DIFF_PORT) @@ -722,7 +731,7 @@ static status_t update_sa_hosts( rthdr = RTA_NEXT(rthdr, rtsize); } } - + POS; if (send_message(this, update, &response) != SUCCESS) { this->logger->log(this->logger, ERROR, "netlink communication failed"); @@ -745,6 +754,7 @@ static status_t update_sa_hosts( this->logger->log(this->logger, CONTROL|LEVEL2, "deleting old SA"); status = this->public.del_sa(&this->public, dst, spi, protocol); } + POS; free(update); free(response); @@ -755,7 +765,7 @@ static status_t update_sa_hosts( * Implementation of kernel_interface_t.query_sa. */ static status_t query_sa(private_kernel_interface_t *this, host_t *dst, - u_int32_t spi, protocol_id_t protocol, time_t *use_time) + u_int32_t spi, protocol_id_t protocol, u_int32_t *use_time) { unsigned char request[BUFFER_SIZE]; struct nlmsghdr *response; @@ -772,7 +782,7 @@ static status_t query_sa(private_kernel_interface_t *this, host_t *dst, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); - sa_id->daddr = dst->get_xfrm_addr(dst); + host2xfrm(dst, &sa_id->daddr); sa_id->spi = spi; sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; sa_id->family = dst->get_family(dst); @@ -796,7 +806,7 @@ static status_t query_sa(private_kernel_interface_t *this, host_t *dst, } sa_info = (struct xfrm_usersa_info*)NLMSG_DATA(response); - *use_time = (time_t)sa_info->curlft.use_time; + *use_time = sa_info->curlft.use_time; free(response); return SUCCESS; @@ -824,7 +834,7 @@ static status_t del_sa(private_kernel_interface_t *this, host_t *dst, hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)); sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr); - sa_id->daddr = dst->get_xfrm_addr(dst); + host2xfrm(dst, &sa_id->daddr); sa_id->spi = spi; sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; sa_id->family = dst->get_family(dst); @@ -850,16 +860,111 @@ static status_t del_sa(private_kernel_interface_t *this, host_t *dst, return status; } +/** + * convert a traffic selector address range to subnet and its mask. + */ +static void ts2subnet(traffic_selector_t* ts, + xfrm_address_t *net, u_int8_t *mask) +{ + /* there is no way to do this cleanly, as the address range may + * be anything else but a subnet. We use from_addr as subnet + * and try to calculate a usable subnet mask. + */ + chunk_t chunk; + + chunk = ts->get_from_address(ts); + memcpy(net, chunk.ptr, chunk.len); + + switch (ts->get_type(ts)) + { + case TS_IPV4_ADDR_RANGE: + { + u_int32_t from, to, bit; + + from = *(u_int32_t*)chunk.ptr; + chunk_free(&chunk); + chunk = ts->get_to_address(ts); + to = *(u_int32_t*)chunk.ptr; + chunk_free(&chunk); + for (bit = 0; bit < 32; bit++) + { + if ((1<get_from_port(ts); + to = ts->get_to_port(ts); + + if (from == to) + { + *port = htons(from); + *mask = ~0; + } + else + { + *port = 0; + *mask = 0; + } +} + +/** + * convert a pair of traffic_selectors to a xfrm_selector + */ +static struct xfrm_selector ts2selector(traffic_selector_t *src, + traffic_selector_t *dst) +{ + struct xfrm_selector sel; + + memset(&sel, 0, sizeof(sel)); + sel.family = src->get_type(src) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6; + /* src or dest proto may be "any" (0), use more restrictive one */ + sel.proto = max(src->get_protocol(src), dst->get_protocol(dst)); + ts2subnet(dst, &sel.daddr, &sel.prefixlen_d); + ts2subnet(src, &sel.saddr, &sel.prefixlen_s); + ts2ports(dst, &sel.dport, &sel.dport_mask); + ts2ports(src, &sel.sport, &sel.sport_mask); + sel.ifindex = 0; + sel.user = 0; + + return sel; +} + /** * Implementation of kernel_interface_t.add_policy. */ 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, - u_int8_t direction, u_int8_t upper_proto, - protocol_id_t protocol, - u_int32_t reqid, bool update) + host_t *src, host_t *dst, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, protocol_id_t protocol, + u_int32_t reqid, bool update) { iterator_t *iterator; kernel_policy_t *current, *policy; @@ -873,16 +978,7 @@ static status_t add_policy(private_kernel_interface_t *this, /* create a policy */ policy = malloc_thing(kernel_policy_t); memset(policy, 0, sizeof(kernel_policy_t)); - policy->sel.saddr = src->get_xfrm_addr(src); - policy->sel.prefixlen_s = src_hostbits; - policy->sel.sport = htons(src->get_port(src)); - policy->sel.sport_mask = (policy->sel.sport) ? ~0 : 0; - policy->sel.daddr = dst->get_xfrm_addr(dst); - policy->sel.prefixlen_d = dst_hostbits; - policy->sel.dport = htons(dst->get_port(dst)); - policy->sel.dport_mask = (policy->sel.dport) ? ~0 : 0; - policy->sel.proto = upper_proto; - policy->sel.family = src->get_family(src); + policy->sel = ts2selector(src_ts, dst_ts); policy->direction = direction; /* find the policy, which matches EXACTLY */ @@ -893,12 +989,17 @@ static status_t add_policy(private_kernel_interface_t *this, if (memcmp(current, policy, sizeof(struct xfrm_selector)) == 0 && policy->direction == current->direction) { + free(policy); /* use existing policy */ if (!update) { current->refcount++; + iterator->destroy(iterator); + pthread_mutex_unlock(&this->pol_mutex); + this->logger->log(this->logger, CONTROL|LEVEL1, + "policy already exists, increasing refcount"); + return SUCCESS; } - free(policy); policy = current; found = TRUE; break; @@ -921,7 +1022,7 @@ static status_t add_policy(private_kernel_interface_t *this, policy_info = (struct xfrm_userpolicy_info*)NLMSG_DATA(hdr); policy_info->sel = policy->sel; - policy_info->dir = direction; + policy_info->dir = policy->direction; policy_info->priority = SPD_PRIORITY; policy_info->action = XFRM_POLICY_ALLOW; policy_info->share = XFRM_SHARE_ANY; @@ -955,8 +1056,8 @@ static status_t add_policy(private_kernel_interface_t *this, tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; tmpl->mode = TRUE; - tmpl->saddr = me->get_xfrm_addr(me); - tmpl->id.daddr = other->get_xfrm_addr(other); + host2xfrm(src, &tmpl->saddr); + host2xfrm(dst, &tmpl->id.daddr); if (send_message(this, hdr, &response) != SUCCESS) { @@ -981,13 +1082,74 @@ static status_t add_policy(private_kernel_interface_t *this, return status; } +/** + * Implementation of kernel_interface_t.query_policy. + */ +static status_t query_policy(private_kernel_interface_t *this, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, u_int32_t *use_time) +{ + unsigned char request[BUFFER_SIZE]; + struct nlmsghdr *response; + struct nlmsghdr *hdr; + struct xfrm_userpolicy_id *policy_id; + struct xfrm_userpolicy_info *policy; + + memset(&request, 0, sizeof(request)); + status_t status = SUCCESS; + + this->logger->log(this->logger, CONTROL|LEVEL2, "querying policy"); + + hdr = (struct nlmsghdr*)request; + hdr->nlmsg_flags = NLM_F_REQUEST; + hdr->nlmsg_type = XFRM_MSG_GETPOLICY; + hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)); + + policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr); + policy_id->sel = ts2selector(src_ts, dst_ts); + policy_id->dir = direction; + + if (send_message(this, hdr, &response) != SUCCESS) + { + this->logger->log(this->logger, ERROR, "netlink communication failed"); + return FAILED; + } + else if (response->nlmsg_type == NLMSG_ERROR) + { + this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_GETPOLICY got an error: %s", + strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error)); + free(response); + return FAILED; + } + else if (response->nlmsg_type != XFRM_MSG_NEWPOLICY) + { + this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_GETPOLICY got an unknown reply"); + free(response); + return FAILED; + } + else if (response->nlmsg_len < NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info))) + { + this->logger->log(this->logger, ERROR, "netlink request XFRM_MSG_GETPOLICY got an invalid reply"); + free(response); + return FAILED; + } + + policy = (struct xfrm_userpolicy_info*)NLMSG_DATA(response); + + *use_time = (time_t)policy->curlft.use_time; + + free(response); + return status; +} + /** * Implementation of kernel_interface_t.del_policy. */ static status_t del_policy(private_kernel_interface_t *this, - host_t *src, host_t *dst, - u_int8_t src_hostbits, u_int8_t dst_hostbits, - u_int8_t direction, u_int8_t upper_proto) + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction) { kernel_policy_t *current, policy, *to_delete = NULL; unsigned char request[BUFFER_SIZE]; @@ -1001,16 +1163,7 @@ static status_t del_policy(private_kernel_interface_t *this, /* create a policy */ memset(&policy, 0, sizeof(kernel_policy_t)); - policy.sel.saddr = src->get_xfrm_addr(src); - policy.sel.prefixlen_s = src_hostbits; - policy.sel.sport = htons(src->get_port(src)); - policy.sel.sport_mask = (policy.sel.sport) ? ~0 : 0; - policy.sel.daddr = dst->get_xfrm_addr(dst); - policy.sel.prefixlen_d = dst_hostbits; - policy.sel.dport = htons(dst->get_port(dst)); - policy.sel.dport_mask = (policy.sel.dport) ? ~0 : 0; - policy.sel.proto = upper_proto; - policy.sel.family = src->get_family(src); + policy.sel = ts2selector(src_ts, dst_ts); policy.direction = direction; /* find the policy */ @@ -1025,7 +1178,7 @@ static status_t del_policy(private_kernel_interface_t *this, if (--to_delete->refcount > 0) { /* is used by more SAs, keep in kernel */ - this->logger->log(this->logger, CONTROL|LEVEL2, + this->logger->log(this->logger, CONTROL|LEVEL1, "is used by other SAs, not removed"); iterator->destroy(iterator); pthread_mutex_unlock(&this->pol_mutex); @@ -1103,11 +1256,12 @@ kernel_interface_t *kernel_interface_create() /* public functions */ 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,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,bool))add_sa; - this->public.update_sa_hosts = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,int,int,u_int32_t,protocol_id_t))update_sa_hosts; - this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,time_t*))query_sa; + this->public.update_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_diff_t,host_diff_t))update_sa; + this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa; this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa; - this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,u_int8_t,u_int8_t,u_int8_t,u_int8_t,protocol_id_t,u_int32_t,bool))add_policy; - this->public.del_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,u_int8_t,u_int8_t,u_int8_t,u_int8_t))del_policy; + this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool))add_policy; + this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy; + this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy; this->public.destroy = (void(*)(kernel_interface_t*)) destroy; /* private members */ diff --git a/src/charon/threads/kernel_interface.h b/src/charon/threads/kernel_interface.h index 5d385caeb..bafb1a6d1 100644 --- a/src/charon/threads/kernel_interface.h +++ b/src/charon/threads/kernel_interface.h @@ -25,8 +25,6 @@ #ifndef KERNEL_INTERFACE_H_ #define KERNEL_INTERFACE_H_ -#include - #include #include #include @@ -34,10 +32,29 @@ typedef struct natt_conf_t natt_conf_t; /** - * @brief Configuration for NAT-T + * Configuration for NAT-T */ struct natt_conf_t { - u_int16_t sport, dport; + /** source port to use for UDP-encapsulated packets */ + u_int16_t sport; + /** dest port to use for UDP-encapsulated packets */ + u_int16_t dport; +}; + +typedef enum policy_dir_t policy_dir_t; + +/** + * Direction of a policy. These are equal to those + * defined in xfrm.h, but we want to stay implementation + * neutral here. + */ +enum policy_dir_t { + /** Policy for inbound traffic */ + POLICY_IN = 0, + /** Policy for outbound traffic */ + POLICY_OUT = 1, + /** Policy for forwarded traffic */ + POLICY_FWD = 2, }; typedef struct kernel_interface_t kernel_interface_t; @@ -52,10 +69,10 @@ typedef struct kernel_interface_t kernel_interface_t; * reference counting. The Linux kernel does not allow the same policy * installed twice, but we need this as CHILD_SA exist multiple times * when rekeying. Thats why we do reference counting of policies. - * + * * @b Constructors: * - kernel_interface_create() - * + * * @ingroup threads */ struct kernel_interface_t { @@ -101,8 +118,8 @@ struct kernel_interface_t { * @param expire_hard lieftime in seconds before delete * @param enc_alg Algorithm to use for encryption (ESP only) * @param int_alg Algorithm to use for integrity protection - * @param prf_plus PRF to derive keys - * @param natt NAT-T Configuration + * @param prf_plus PRF to derive keys from + * @param natt NAT-T Configuration, or NULL of no NAT-T used * @param replace Should an already installed SA be updated? * @return * - SUCCESS @@ -113,35 +130,38 @@ struct kernel_interface_t { protocol_id_t protocol, u_int32_t reqid, u_int64_t expire_soft, u_int64_t expire_hard, algorithm_t *enc_alg, algorithm_t *int_alg, - prf_plus_t *prf_plus, natt_conf_t *natt, bool replace); + prf_plus_t *prf_plus, natt_conf_t *natt, bool update); /** - * @brief Update the hosts on an installed SA. Encapsulation ports are also updated. + * @brief Update the hosts on an installed SA. * - * @note We cannot directly update the destination address as the kernel requires the spi, - * the protocol AND the destination address (and family) to identify SAs. Therefore if the - * destination address changed we create a new SA and delete the old one. + * We cannot directly update the destination address as the kernel + * requires the spi, the protocol AND the destination address (and family) + * to identify SAs. Therefore if the destination address changed we + * create a new SA and delete the old one. * * @param this calling object - * @param src source address for this SA * @param dst destination address for this SA + * @param spi SPI of the SA + * @param protocol protocol for this SA (ESP/AH) * @param new_src new source address for this SA * @param new_dst new destination address for this SA * @param src_changes changes in src * @param dst_changes changes in dst - * @param spi SPI allocated by us or remote peer - * @param protocol protocol for this SA (ESP/AH) * @return * - SUCCESS * - FAILED if kernel comm failed */ - status_t (*update_sa_hosts)(kernel_interface_t *this, - host_t *src, host_t *dst, - host_t *new_src, host_t *new_dst, - int src_changes, int dst_changes, - u_int32_t spi, protocol_id_t protocol); + status_t (*update_sa)(kernel_interface_t *this, host_t *dst, u_int32_t spi, + protocol_id_t protocol, + host_t *new_src, host_t *new_dst, + host_diff_t src_changes, host_diff_t dst_changes); + /** * @brief Query the use time of an SA. + * + * The use time of an SA is not the time of the last usage, but + * the time of the first usage of the SA. * * @param this calling object * @param dst destination address for this SA @@ -153,7 +173,7 @@ struct kernel_interface_t { * - FAILED if kernel comm failed */ status_t (*query_sa) (kernel_interface_t *this, host_t *dst, u_int32_t spi, - protocol_id_t protocol, time_t *use_time); + protocol_id_t protocol, u_int32_t *use_time); /** * @brief Delete a previusly installed SA from the SAD. @@ -172,20 +192,19 @@ struct kernel_interface_t { /** * @brief Add a policy to the SPD. * - * A policy is always associated to an SA, so - * traffic applied to a policy. Traffic which - * matches a policy is handled by the SA with the same - * reqid. + * A policy is always associated to an SA. Traffic which matches a + * policy is handled by the SA with the same reqid. + * If the update flag is set, the policy is updated with the new + * src/dst addresses. + * If the update flag is not set, but a such policy is already in the + * kernel, the reference count to this policy is increased. * * @param this calling object - * @param me address of local peer - * @param other address of remote peer - * @param src src address of traffic this policy applies - * @param dst dest address of traffic this policy applies - * @param src_hostbits subnetmask to use for src address - * @param dst_hostbits subnetmask to use for dst address - * @param direction direction of traffic, XFRM_POLICY_OUT, XFRM_POLICY_IN, XFRM_POLICY_FWD - * @param upper_proto upper layer protocol of traffic for this policy (TCP, UDP, ICMP, ...) + * @param src source address of SA + * @param dst dest address of SA + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD * @param protocol protocol to use to protect traffic (AH/ESP) * @param reqid uniqe ID of an SA to use to enforce policy * @param update update an existing policy, if TRUE @@ -193,32 +212,53 @@ struct kernel_interface_t { * - SUCCESS * - FAILED if kernel comm failed */ - status_t (*add_policy) (kernel_interface_t *this, - host_t *me, host_t *other, + status_t (*add_policy) (kernel_interface_t *this, host_t *src, host_t *dst, - u_int8_t src_hostbits, u_int8_t dst_hostbits, - u_int8_t direction, u_int8_t upper_proto, - protocol_id_t protocol, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, protocol_id_t protocol, u_int32_t reqid, bool update); + /** + * @brief Query the use time of a policy. + * + * The use time of a policy is the time the policy was used + * for the last time. + * + * @param this calling object + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD + * @param[out] use_time the time of this SA's last use + * @return + * - SUCCESS + * - FAILED if kernel comm failed + */ + status_t (*query_policy) (kernel_interface_t *this, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, u_int32_t *use_time); + /** * @brief Remove a policy from the SPD. * + * The kernel interface implements reference counting for policies. + * If the same policy is installed multiple times (in the case of rekeying), + * the reference counter is increased. del_policy() decreases the ref counter + * and removes the policy only when no more references are available. + * * @param this calling object - * @param src src address of traffic this policy applies - * @param dst dest address of traffic this policy applies - * @param src_hostbits subnetmask to use for src address - * @param dst_hostbits subnetmask to use for dst address - * @param direction direction of traffic, XFRM_POLICY_OUT, XFRM_POLICY_IN, XFRM_POLICY_FWD - * @param upper_proto upper layer protocol of traffic for this policy (TCP, UDP, ICMP, ...) + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD * @return * - SUCCESS * - FAILED if kernel comm failed */ status_t (*del_policy) (kernel_interface_t *this, - host_t *src, host_t *dst, - u_int8_t src_hostbits, u_int8_t dst_hostbits, - u_int8_t direction, u_int8_t upper_proto); + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction); /** * @brief Destroys a kernel_interface object. diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index ae037666c..f4d7accfb 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -428,9 +428,9 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) charon->connections->add_connection(charon->connections, connection); this->logger->log(this->logger, CONTROL, "added connection \"%s\": %s[%s]...%s[%s]", msg->add_conn.name, - my_host->get_address(my_host), + my_host->get_string(my_host), my_id->get_string(my_id), - other_host->get_address(other_host), + other_host->get_string(other_host), other_id->get_string(other_id)); /* add to global policy list */ charon->policies->add_policy(charon->policies, policy); diff --git a/src/libstrongswan/utils/host.c b/src/libstrongswan/utils/host.c index 1f928f5aa..763358e5c 100644 --- a/src/libstrongswan/utils/host.c +++ b/src/libstrongswan/utils/host.c @@ -100,9 +100,9 @@ static bool is_anyaddr(private_host_t *this) } /** - * implements host_t.get_address + * implements host_t.get_string */ -static char *get_address(private_host_t *this) +static char *get_string(private_host_t *this) { switch (this->family) { @@ -128,9 +128,9 @@ static char *get_address(private_host_t *this) } /** - * Implementation of host_t.get_address_as_chunk. + * Implementation of host_t.get_address. */ -static chunk_t get_address_as_chunk(private_host_t *this) +static chunk_t get_address(private_host_t *this) { chunk_t address = CHUNK_INITIALIZER; @@ -139,9 +139,8 @@ static chunk_t get_address_as_chunk(private_host_t *this) case AF_INET: { /* allocate 4 bytes for IPv4 address*/ - address.ptr = malloc(4); + address.ptr = (char*)&(this->address4.sin_addr.s_addr); address.len = 4; - memcpy(address.ptr,&(this->address4.sin_addr.s_addr),4); } default: { @@ -151,22 +150,9 @@ static chunk_t get_address_as_chunk(private_host_t *this) } } -static xfrm_address_t get_xfrm_addr(private_host_t *this) -{ - switch (this->family) - { - case AF_INET: - { - return (xfrm_address_t)(this->address4.sin_addr.s_addr); - } - default: - { - /* todo */ - return (xfrm_address_t)(this->address4.sin_addr.s_addr); - } - } -} - +/** + * implements host_t.get_family + */ static int get_family(private_host_t *this) { return this->family; @@ -203,12 +189,11 @@ static void set_port(private_host_t *this, u_int16_t port) } default: { - /**/ + /*TODO*/ } } } - /** * Implements host_t.clone. */ @@ -249,9 +234,9 @@ static bool ip_equals(private_host_t *this, private_host_t *other) /** * Implements host_t.get_differences */ -static int get_differences(private_host_t *this, private_host_t *other) +static host_diff_t get_differences(private_host_t *this, private_host_t *other) { - int ret = HOST_DIFF_NONE; + host_diff_t ret = HOST_DIFF_NONE; if (!this->public.ip_equals(&this->public, &other->public)) { @@ -307,12 +292,11 @@ static private_host_t *host_create_empty(void) this->public.get_sockaddr_len = (socklen_t*(*) (host_t*))get_sockaddr_len; this->public.clone = (host_t* (*) (host_t*))clone; this->public.get_family = (int (*) (host_t*))get_family; - this->public.get_xfrm_addr = (xfrm_address_t (*) (host_t *))get_xfrm_addr; - this->public.get_address = (char* (*) (host_t *))get_address; - this->public.get_address_as_chunk = (chunk_t (*) (host_t *)) get_address_as_chunk; + this->public.get_string = (char* (*) (host_t *))get_string; + this->public.get_address = (chunk_t (*) (host_t *)) get_address; this->public.get_port = (u_int16_t (*) (host_t *))get_port; this->public.set_port = (void (*) (host_t *,u_int16_t))set_port; - this->public.get_differences = (int (*) (host_t *,host_t *)) get_differences; + this->public.get_differences = (host_diff_t (*) (host_t *,host_t *)) get_differences; this->public.ip_equals = (bool (*) (host_t *,host_t *)) ip_equals; this->public.equals = (bool (*) (host_t *,host_t *)) equals; this->public.is_anyaddr = (bool (*) (host_t *)) is_anyaddr; diff --git a/src/libstrongswan/utils/host.h b/src/libstrongswan/utils/host.h index 6a72f52e4..54f3b55bb 100644 --- a/src/libstrongswan/utils/host.h +++ b/src/libstrongswan/utils/host.h @@ -35,10 +35,17 @@ #include +typedef enum host_diff_t host_diff_t; -#define HOST_DIFF_NONE 0 -#define HOST_DIFF_ADDR 1 -#define HOST_DIFF_PORT 2 +/** + * Differences between two hosts. They differ in + * address, port, or both. + */ +enum host_diff_t { + HOST_DIFF_NONE = 0, + HOST_DIFF_ADDR = 1, + HOST_DIFF_PORT = 2, +}; typedef struct host_t host_t; @@ -80,7 +87,7 @@ struct host_t { /** * @brief Get the length of the sockaddr struct. * - * Sepending on the family, the length of the sockaddr struct + * Depending on the family, the length of the sockaddr struct * is different. Use this function to get the length of the sockaddr * struct returned by get_sock_addr. * @@ -91,20 +98,6 @@ struct host_t { */ socklen_t *(*get_sockaddr_len) (host_t *this); - /** - * @brief Gets the address as xfrm_address_t. - * - * This function allows the conversion to an - * xfrm_address_t, used for netlink communication - * with the kernel. - * - * @see kernel_interface_t. - * - * @param this calling object - * @return address in xfrm_address_t format - */ - xfrm_address_t (*get_xfrm_addr) (host_t *this); - /** * @brief Gets the family of the address * @@ -114,15 +107,15 @@ struct host_t { int (*get_family) (host_t *this); /** - * @brief get the address of this host + * @brief Get the address of this host as a string * - * Mostly used for debugging purposes. - * @warning string must NOT be freed + * Mostly used for debugging purposes. String + * points to internal data. * * @param this object * @return address string, */ - char* (*get_address) (host_t *this); + char* (*get_string) (host_t *this); /** * @brief Checks if the ip address of host is set to default route. @@ -137,12 +130,12 @@ struct host_t { /** * @brief get the address of this host as chunk_t * - * @warning returned chunk has to get destroyed by caller. + * Returned chunk points to internal data. * * @param this object * @return address string, */ - chunk_t (*get_address_as_chunk) (host_t *this); + chunk_t (*get_address) (host_t *this); /** * @brief get the port of this host @@ -183,10 +176,9 @@ struct host_t { * * @param this object to compare * @param other the other to compare - * @return a combination of HOST_DIFF_NONE, - * HOST_DIFF_ADDR and HOST_DIFF_PORT + * @return differences in a combination of host_diff_t's */ - int (*get_differences) (host_t *this, host_t *other); + host_diff_t (*get_differences) (host_t *this, host_t *other); /** * @brief Destroy this host object diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 3a5f48f3f..fbcd7d933 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -174,6 +174,7 @@ whitelist_t whitelist[] = { {inet_ntoa, 0xFF}, {strerror, 0xFF}, {getprotobynumber, 0xFF}, + {getservbyport, 0xFF}, }; /**