diff --git a/src/charon/config/configuration.c b/src/charon/config/configuration.c index 9e44a0ef9..cd205867e 100755 --- a/src/charon/config/configuration.c +++ b/src/charon/config/configuration.c @@ -55,12 +55,6 @@ */ #define KEEPALIVE_INTERVAL 2000000 -/** - * Keepalive timeout in milliseconds. - * Not implemented yet. - */ -#define KEEPALIVE_TIMEOUT 30000000 - /** * DPD interval in milliseconds. */ @@ -112,14 +106,6 @@ static u_int32_t get_keepalive_interval (private_configuration_t *this) return KEEPALIVE_INTERVAL; } -/** - * Implementation of configuration_t.get_keepalive_timeout. - */ -static u_int32_t get_keepalive_timeout (private_configuration_t *this) -{ - return KEEPALIVE_TIMEOUT; -} - /** * Implementation of configuration_t.get_dpd_interval. */ @@ -148,7 +134,6 @@ configuration_t *configuration_create() this->public.get_retransmit_timeout = (status_t (*) (configuration_t *, u_int32_t retransmit_count, u_int32_t *timeout))get_retransmit_timeout; this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t *)) get_half_open_ike_sa_timeout; this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t *)) get_keepalive_interval; - this->public.get_keepalive_timeout = (u_int32_t (*) (configuration_t *)) get_keepalive_timeout; this->public.get_dpd_interval = (u_int32_t (*) (configuration_t *)) get_dpd_interval; return (&this->public); diff --git a/src/charon/config/configuration.h b/src/charon/config/configuration.h index f0696328d..813b95788 100755 --- a/src/charon/config/configuration.h +++ b/src/charon/config/configuration.h @@ -80,17 +80,6 @@ struct configuration_t { */ u_int32_t (*get_keepalive_interval) (configuration_t *this); - /** - * @brief Returns the keepalive timeout in ms. - * - * The keepalive timeout defines how long we should keep sending - * NAT keepalives after closing an IKE_SA. - * - * @param this calling object - * @return timeout in milliseconds (ms) - */ - u_int32_t (*get_keepalive_timeout) (configuration_t *this); - /** * @brief Returns the DPD interval in ms. * diff --git a/src/charon/config/connections/connection.c b/src/charon/config/connections/connection.c index 243c89633..f3c4bddfb 100644 --- a/src/charon/config/connections/connection.c +++ b/src/charon/config/connections/connection.c @@ -22,7 +22,7 @@ #include -#include "connection.h" +#include #include #include diff --git a/src/charon/daemon.h b/src/charon/daemon.h index 2c7941f5a..0a5962fca 100644 --- a/src/charon/daemon.h +++ b/src/charon/daemon.h @@ -273,6 +273,7 @@ struct daemon_t { * A socket_t instance. */ socket_t *socket; + /** * A interfaces_t instance. */ diff --git a/src/charon/network/interfaces.c b/src/charon/network/interfaces.c index a36ba4d0e..ce0141849 100644 --- a/src/charon/network/interfaces.c +++ b/src/charon/network/interfaces.c @@ -147,6 +147,7 @@ interfaces_t *interfaces_create(u_int16_t port) if (initialize(this) != SUCCESS) { destroy(this); + return NULL; } return &this->public; diff --git a/src/charon/network/socket.c b/src/charon/network/socket.c index eb61c83b3..0d5470c2a 100644 --- a/src/charon/network/socket.c +++ b/src/charon/network/socket.c @@ -395,9 +395,9 @@ static status_t initialize(private_socket_t *this) int type = UDP_ENCAP_ESPINUDP; if (setsockopt(this->natt_fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) { - this->logger->log(this->logger, ERROR, + this->logger->log(this->logger, ERROR, "unable to set UDP_ENCAP on natt send socket! NAT-T may fail! error: %s", - strerror(errno)); + strerror(errno)); } } diff --git a/src/charon/queues/jobs/send_dpd_job.c b/src/charon/queues/jobs/send_dpd_job.c index acbde70c3..3c38110b0 100644 --- a/src/charon/queues/jobs/send_dpd_job.c +++ b/src/charon/queues/jobs/send_dpd_job.c @@ -66,6 +66,9 @@ static status_t execute(private_send_dpd_job_t *this) { ike_sa_t *ike_sa; status_t status; + u_int32_t dt; + u_int32_t interval = charon->configuration->get_dpd_interval(charon->configuration); + struct timeval last_msg_tv, current_tv; this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s", this->ike_sa_id->get_initiator_spi(this->ike_sa_id), @@ -81,9 +84,26 @@ static status_t execute(private_send_dpd_job_t *this) return DESTROY_ME; } - ike_sa->send_dpd_request(ike_sa); - this->logger->log(this->logger, CONTROL|LEVEL1, - "DPD request packet scheduled"); + last_msg_tv = ike_sa->get_last_traffic_in_tv(ike_sa); + if (0 > gettimeofday(¤t_tv, NULL) ) + { + this->logger->log(this->logger, ERROR|LEVEL1, + "Warning: Failed to get time of day."); + } + dt = (current_tv.tv_sec - last_msg_tv.tv_sec) * 1000 + + (current_tv.tv_usec - last_msg_tv.tv_usec) / 1000; + + if (dt >= interval) + { + ike_sa->send_dpd_request(ike_sa); + this->logger->log(this->logger, CONTROL|LEVEL1, + "DPD request packet scheduled"); + + } + else + { + charon->event_queue->add_relative(charon->event_queue, (job_t*) this, interval - dt); + } this->logger->log(this->logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s", diff --git a/src/charon/queues/jobs/send_keepalive_job.c b/src/charon/queues/jobs/send_keepalive_job.c index 4fc7f3d56..f17296af6 100644 --- a/src/charon/queues/jobs/send_keepalive_job.c +++ b/src/charon/queues/jobs/send_keepalive_job.c @@ -68,7 +68,6 @@ static status_t execute(private_send_keepalive_job_t *this) status_t status; u_int32_t dt; u_int32_t interval = charon->configuration->get_keepalive_interval(charon->configuration); - u_int32_t timeout = charon->configuration->get_keepalive_timeout(charon->configuration); struct timeval last_msg_tv, current_tv; packet_t *packet; host_t *host; @@ -89,7 +88,7 @@ static status_t execute(private_send_keepalive_job_t *this) return DESTROY_ME; } - last_msg_tv = ike_sa->get_last_msg_tv(ike_sa); + last_msg_tv = ike_sa->get_last_traffic_out_tv(ike_sa); if (0 > gettimeofday(¤t_tv, NULL) ) { this->logger->log(this->logger, ERROR|LEVEL1, @@ -114,8 +113,7 @@ static status_t execute(private_send_keepalive_job_t *this) this->logger->log(this->logger, CONTROL|LEVEL1, "NAT keepalive packet scheduled"); } - charon->event_queue->add_relative(charon->event_queue, - (job_t*) this, interval - dt); + charon->event_queue->add_relative(charon->event_queue, (job_t*) this, interval - dt); this->logger->log(this->logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s", diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 554078cda..b7b4492f8 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -327,7 +327,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus) { - linked_list_t *list; u_int32_t outbound_spi, inbound_spi; /* backup outbound spi, as alloc overwrites it */ @@ -539,6 +538,94 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name) iterator->destroy(iterator); } +/** + * Implementation of child_sa_t.get_use_time + */ +static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use_time) +{ + iterator_t *iterator; + sa_policy_t *policy; + struct protoent *proto; + char proto_buf[8] = ""; + char *proto_name = proto_buf; + status_t status; + + *use_time = UNDEFINED_TIME; + + iterator = this->policies->create_iterator(this->policies, TRUE); + while (iterator->iterate(iterator, (void**)&policy)) + { + time_t ut; + + if (policy->upper_proto) + { + proto = getprotobynumber(policy->upper_proto); + if (proto) + { + proto_name = proto->p_name; + } + else + { + snprintf(proto_buf, sizeof(proto_buf), "<%d>", policy->upper_proto); + } + } + + this->logger->log(this->logger, CONTROL|LEVEL1, + "quering policy: %s/%d==%s==%s/%d", + policy->me.net->get_address(policy->me.net), policy->me.net_mask, + proto_name, + policy->other.net->get_address(policy->other.net), policy->other.net_mask); + + if (inbound) + { + status = charon->kernel_interface->query_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, + &ut); + + /* also check forward policy in tunnel mode */ + if (status == SUCCESS /*&& mode == TUNNEL XXX */) + { + time_t fwd; + + status = charon->kernel_interface->query_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, + &fwd); + + if (status == SUCCESS) + { + ut = max(ut, fwd); + } + } + } + else + { + status = charon->kernel_interface->query_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, + &ut); + } + + if (status != SUCCESS) + { + iterator->destroy(iterator); + return FAILED; + } + + *use_time = max(*use_time, ut); + } + iterator->destroy(iterator); + + return SUCCESS; +} + /** * Update the host adress/port of a SA */ @@ -772,6 +859,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, 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_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_rekeyed = (void (*)(child_sa_t*))set_rekeyed; this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status; this->public.destroy = (void(*)(child_sa_t*))destroy; diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index a93d81e59..6c1ca0177 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -157,6 +157,16 @@ struct child_sa_t { */ status_t (*add_policies) (child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list); + /** + * @brief Get the time of this child_sa_t's last use (i.e. last use of any of its policies) + * + * @param this calling object + * @param inbound query for in- or outbound usage + * @param use_time the time + * @return SUCCESS or FAILED + */ + status_t (*get_use_time) (child_sa_t *this, bool inbound, time_t *use_time); + /** * @brief Mark this child_sa as rekeyed. * diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 84c751454..2ba9c7432 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -67,6 +67,16 @@ struct private_ike_sa_t { */ protected_ike_sa_t protected; + /** + * Update a timestamp on ike traffic + */ + void (*update_timestamp)(private_ike_sa_t *this, bool in); + + /** + * Returns the time since last traffic on kernel policies + */ + struct timeval (*get_last_esp_traffic_tv)(private_ike_sa_t * this, bool inbound); + /** * Identifier for the current IKE_SA. */ @@ -194,9 +204,14 @@ struct private_ike_sa_t { bool nat_there; /** - * Timestamp of last IKE message sent or received on this SA + * Timestamp of last IKE message received on this SA */ - struct timeval last_msg_tv; + struct timeval last_msg_in_tv; + + /** + * Timestamp of last IKE message sent on this SA + */ + struct timeval last_msg_out_tv; /* * Message ID of last DPD message @@ -330,7 +345,7 @@ static host_t* get_my_host(private_ike_sa_t *this) */ static host_t* get_other_host(private_ike_sa_t *this) { - return this->connection->get_other_host(this->connection);; + return this->connection->get_other_host(this->connection); } /** @@ -338,7 +353,7 @@ static host_t* get_other_host(private_ike_sa_t *this) */ static identification_t* get_my_id(private_ike_sa_t *this) { - return this->policy->get_my_id(this->policy);; + return this->policy->get_my_id(this->policy); } /** @@ -346,7 +361,7 @@ static identification_t* get_my_id(private_ike_sa_t *this) */ static identification_t* get_other_id(private_ike_sa_t *this) { - return this->policy->get_other_id(this->policy);; + return this->policy->get_other_id(this->policy); } /** @@ -375,7 +390,7 @@ static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id) this->logger->log(this->logger, CONTROL | LEVEL1, "Going to retransmit message with id %d",message_id); packet = this->last_requested_message->get_packet(this->last_requested_message); charon->send_queue->add(charon->send_queue, packet); - + this->update_timestamp(this, FALSE); return SUCCESS; } @@ -606,6 +621,20 @@ static signer_t *get_signer_responder(private_ike_sa_t *this) return this->signer_responder; } +/** + * Implementation of protected_ike_sa_t.update_timestamp + */ +static void update_timestamp(private_ike_sa_t *this, bool in) +{ + /* bump last message sent timestamp */ + struct timeval *tv = in ? &this->last_msg_in_tv : &this->last_msg_out_tv; + if (0 > gettimeofday(tv, NULL)) + { + this->logger->log(this->logger, ERROR|LEVEL1, + "Warning: Failed to get time of day."); + } +} + /** * Implementation of protected_ike_sa_t.send_request. */ @@ -678,11 +707,7 @@ static status_t send_request(private_ike_sa_t *this, message_t *message) this->message_id_out); this->message_id_out++; - /* bump last message sent timestamp */ - if (gettimeofday(&this->last_msg_tv, NULL) < 0) - { - this->logger->log(this->logger, ERROR|LEVEL1, "failed to get time of day"); - } + this->update_timestamp(this, FALSE); return SUCCESS; } @@ -740,6 +765,8 @@ static status_t send_response(private_ike_sa_t *this, message_t *message) this->logger->log(this->logger, CONTROL|LEVEL3, "Increase message counter for incoming messages"); this->message_id_in++; + this->update_timestamp(this, FALSE); + return SUCCESS; } @@ -780,6 +807,8 @@ static void send_notify(private_ike_sa_t *this, exchange_type_t exchange_type, n charon->send_queue->add(charon->send_queue, packet); this->logger->log(this->logger, CONTROL|LEVEL2, "Destroy message"); response->destroy(response); + + this->update_timestamp(this, FALSE); } /** @@ -842,6 +871,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) packet_t *packet = this->last_responded_message->get_packet(this->last_responded_message); this->logger->log(this->logger, CONTROL|LEVEL1, "Resent request detected. Send stored reply."); charon->send_queue->add(charon->send_queue, packet); + this->update_timestamp(this, FALSE); return SUCCESS; } else @@ -875,6 +905,8 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) } } + this->update_timestamp(this, TRUE); + /* now the message is processed by the current state object. * The specific state object is responsible to check if a message can be received in * the state it represents. @@ -1412,14 +1444,50 @@ static void set_other_host_behind_nat (private_ike_sa_t *this, bool nat) } /** - * Implementation of ike_sa_t.get_last_msg_tv. + * Implementation of private_ike_sa_t.get_last_esp_traffic_tv */ -static struct timeval get_last_msg_tv (private_ike_sa_t *this) +static struct timeval get_last_esp_traffic_tv(private_ike_sa_t * this, bool inbound) { - /* - * XXX: query kernel for last activity time - */ - return this->last_msg_tv; + iterator_t *iterator; + child_sa_t *child_sa; + bool ret = TRUE; + time_t use_time = 0; + struct timeval tv = {0, 0}; + + iterator = this->child_sas->create_iterator(this->child_sas, TRUE); + while (iterator->iterate(iterator, (void**)&child_sa)) + { + if (child_sa->get_use_time(child_sa, inbound, &use_time) == SUCCESS + && use_time != 0) + { + tv.tv_sec = max(tv.tv_sec, use_time); + } + } + iterator->destroy(iterator); + + return tv; +} + +/** + * Implementation of ike_sa_t.get_last_traffic_in_tv. + */ +static struct timeval get_last_traffic_in_tv (private_ike_sa_t *this) +{ + struct timeval esp_tv = this->get_last_esp_traffic_tv(this, TRUE); + return this->last_msg_in_tv.tv_sec > esp_tv.tv_sec ? this->last_msg_in_tv + : this->last_msg_in_tv.tv_sec < esp_tv.tv_sec ? esp_tv + : this->last_msg_in_tv.tv_usec > esp_tv.tv_usec ? this->last_msg_in_tv : esp_tv; +} + +/** + * Implementation of ike_sa_t.get_last_traffic_out_tv. + */ +static struct timeval get_last_traffic_out_tv (private_ike_sa_t *this) +{ + struct timeval esp_tv = this->get_last_esp_traffic_tv(this, FALSE); + return this->last_msg_out_tv.tv_sec > esp_tv.tv_sec ? this->last_msg_out_tv + : this->last_msg_out_tv.tv_sec < esp_tv.tv_sec ? esp_tv + : this->last_msg_out_tv.tv_usec > esp_tv.tv_usec ? this->last_msg_out_tv : esp_tv; } /** @@ -1543,7 +1611,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->protected.public.is_my_host_behind_nat = (bool(*)(ike_sa_t*)) is_my_host_behind_nat; this->protected.public.is_other_host_behind_nat = (bool(*)(ike_sa_t*)) is_other_host_behind_nat; this->protected.public.is_any_host_behind_nat = (bool(*)(ike_sa_t*)) is_any_host_behind_nat; - this->protected.public.get_last_msg_tv = (struct timeval (*)(ike_sa_t*)) get_last_msg_tv; + this->protected.public.get_last_traffic_in_tv = (struct timeval (*)(ike_sa_t*)) get_last_traffic_in_tv; + this->protected.public.get_last_traffic_out_tv = (struct timeval (*)(ike_sa_t*)) get_last_traffic_out_tv; this->protected.public.send_dpd_request = (status_t (*)(ike_sa_t*)) send_dpd_request; /* protected functions */ @@ -1579,6 +1648,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->protected.get_last_dpd_message_id = (u_int32_t (*) (protected_ike_sa_t*)) get_last_dpd_message_id; this->protected.update_connection_hosts = (status_t (*) (protected_ike_sa_t *, host_t*, host_t*)) update_connection_hosts; + /* private functions */ + this->update_timestamp = (void (*) (private_ike_sa_t*,bool))update_timestamp; + this->get_last_esp_traffic_tv = (struct timeval (*) (private_ike_sa_t *,bool))get_last_esp_traffic_tv; + /* initialize private fields */ this->logger = logger_manager->get_logger(logger_manager, IKE_SA); @@ -1604,8 +1677,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->nat_hasher = hasher_create(HASH_SHA1); this->nat_here = FALSE; this->nat_there = FALSE; - this->last_msg_tv.tv_sec = 0; - this->last_msg_tv.tv_usec = 0; + this->last_msg_in_tv.tv_sec = 0; + this->last_msg_in_tv.tv_usec = 0; + this->last_msg_out_tv.tv_sec = 0; + this->last_msg_out_tv.tv_usec = 0; this->last_dpd_message_id = 0; /* at creation time, IKE_SA is in a initiator state */ diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index aed8ff3fe..719aa94b0 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -236,12 +236,20 @@ struct ike_sa_t { bool (*is_any_host_behind_nat) (ike_sa_t *this); /** - * @brief Query timeval of last message sent. + * @brief Query timeval of last inbound IKE or ESP traffic. * - * @param this calling object - * @return time when the last message was sent + * @param this calling object + * @return time when the last traffic was seen */ - struct timeval (*get_last_msg_tv) (ike_sa_t *this); + struct timeval (*get_last_traffic_in_tv) (ike_sa_t *this); + + /** + * @brief Query timeval of last outbound IKE or ESP traffic. + * + * @param this calling object + * @return time when the last traffic was seen + */ + struct timeval (*get_last_traffic_out_tv) (ike_sa_t *this); /** * @brief Get the state of type of associated state object. diff --git a/src/charon/sa/states/ike_sa_established.c b/src/charon/sa/states/ike_sa_established.c index c97254eee..800380680 100644 --- a/src/charon/sa/states/ike_sa_established.c +++ b/src/charon/sa/states/ike_sa_established.c @@ -554,14 +554,6 @@ static status_t process_message(private_ike_sa_established_t *this, message_t *m signer_t *signer; status_t status; - /* only requests are allowed, responses are handled in other state */ - if (!message->get_request(message)) - { - this->logger->log(this->logger, ERROR|LEVEL1, - "Response not handled in state ike_sa_established"); - return FAILED; - } - /* get signer for verification and crypter for decryption */ ike_sa_id = this->ike_sa->public.get_id(&this->ike_sa->public); if (!ike_sa_id->is_initiator(ike_sa_id)) @@ -590,6 +582,28 @@ static status_t process_message(private_ike_sa_established_t *this, message_t *m { return status; } + + /* process responses */ + if (!message->get_request(message)) + { + switch (message->get_exchange_type(message)) + { + case INFORMATIONAL: + status = process_informational_response(this, message); + break; + default: + this->logger->log(this->logger, ERROR | LEVEL1, + "Only INFORMATIONAL responses are handled in state ike_sa_established"); + status = FAILED; + break; + } + + /* we don't really reply to this message but the retransmit mechanism relies on this */ + this->ike_sa->set_last_replied_message_id(this->ike_sa, message->get_message_id(message)); + + /* return here */ + return status; + } /* prepare a reply of the same type */ this->ike_sa->build_message(this->ike_sa, message->get_exchange_type(message), FALSE, &response); @@ -609,6 +623,7 @@ static status_t process_message(private_ike_sa_established_t *this, message_t *m mapping_find(exchange_type_m, message->get_exchange_type(message))); status = NOT_SUPPORTED; } + return status; } diff --git a/src/charon/sa/states/initiator_init.c b/src/charon/sa/states/initiator_init.c index b12091851..503bfef5a 100644 --- a/src/charon/sa/states/initiator_init.c +++ b/src/charon/sa/states/initiator_init.c @@ -94,6 +94,7 @@ struct private_initiator_init_t { * @param request message_t object to add the NONCE payload */ status_t (*build_nonce_payload) (private_initiator_init_t *this,message_t *request); + /** * Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and * Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state. diff --git a/src/charon/sa/states/responder_init.c b/src/charon/sa/states/responder_init.c index 3e85ea5fa..5dad9e78e 100644 --- a/src/charon/sa/states/responder_init.c +++ b/src/charon/sa/states/responder_init.c @@ -388,6 +388,7 @@ static status_t process_message(private_responder_init_t *this, message_t *messa response->destroy(response); return status; } + /* build Notify(NAT-D) payloads */ this->build_natd_payloads(this, response); @@ -616,6 +617,7 @@ static status_t process_notify_payload(private_responder_init_t *this, notify_pa this->logger->log(this->logger, CONTROL|LEVEL1, "process notify type %s", mapping_find(notify_message_type_m, notify_message_type)); + switch (notify_message_type) { case NAT_DETECTION_DESTINATION_IP: diff --git a/src/charon/threads/kernel_interface.c b/src/charon/threads/kernel_interface.c index 5e4480313..43388897b 100644 --- a/src/charon/threads/kernel_interface.c +++ b/src/charon/threads/kernel_interface.c @@ -673,6 +673,75 @@ static status_t add_policy(private_kernel_interface_t *this, return status; } +static status_t query_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, + time_t *use_time) +{ + unsigned char request[BUFFER_SIZE]; + struct nlmsghdr *response; + + memset(&request, 0, sizeof(request)); + status_t status = SUCCESS; + + this->logger->log(this->logger, CONTROL|LEVEL2, "querying policy"); + + struct nlmsghdr *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)); + + struct xfrm_userpolicy_id *policy_id = (struct xfrm_userpolicy_id*)NLMSG_DATA(hdr); + policy_id->sel.sport = htons(src->get_port(src)); + policy_id->sel.sport_mask = (policy_id->sel.sport) ? ~0 : 0; + policy_id->sel.saddr = src->get_xfrm_addr(src); + policy_id->sel.prefixlen_s = src_hostbits; + + policy_id->sel.dport = htons(dst->get_port(dst)); + policy_id->sel.dport_mask = (policy_id->sel.dport) ? ~0 : 0; + policy_id->sel.daddr = dst->get_xfrm_addr(dst); + policy_id->sel.prefixlen_d = dst_hostbits; + + policy_id->sel.proto = upper_proto; + policy_id->sel.family = src->get_family(src); + + policy_id->dir = direction; + + if (this->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; + } + + struct xfrm_userpolicy_info *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. */ @@ -923,6 +992,7 @@ kernel_interface_t *kernel_interface_create() 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,protocol_id_t,u_int32_t))add_policy; 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.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa; + this->public.query_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int,time_t*))query_policy; this->public.del_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int))del_policy; this->public.destroy = (void(*)(kernel_interface_t*)) destroy; diff --git a/src/charon/threads/kernel_interface.h b/src/charon/threads/kernel_interface.h index 9aa2d941a..c427e2a5b 100644 --- a/src/charon/threads/kernel_interface.h +++ b/src/charon/threads/kernel_interface.h @@ -118,6 +118,7 @@ struct kernel_interface_t { prf_plus_t *prf_plus, natt_conf_t *natt, bool replace); + /** * @brief Update the hosts on an installed SA. Encapsulation ports are also updated. * @@ -190,6 +191,29 @@ struct kernel_interface_t { int direction, int upper_proto, protocol_id_t protocol, u_int32_t reqid); + /** + * @brief Query the use time of a policy + * + * @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 use_time the time of this policy's last use + * @return + * - SUCCESS + * - FAILED if kernel comm failed + */ + status_t (*query_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, + time_t *use_time); /** * @brief Remove a policy from the SPD. diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 5f495a5ad..968342d48 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -38,6 +38,7 @@ libstrongswan_la_LIBADD = -lgmp -lpthread INCLUDES = -I$(top_srcdir)/src/libstrongswan EXTRA_DIST = asn1/oid.txt asn1/oid.pl +BUILT_SOURCES = asn1/oid.c asn1/oid.h MAINTAINERCLEANFILES = asn1/oid.c asn1/oid.h if USE_LEAK_DETECTIVE diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am index 9787f4973..fb07bb89e 100644 --- a/src/pluto/Makefile.am +++ b/src/pluto/Makefile.am @@ -30,6 +30,7 @@ pluto_LDADD = $(top_srcdir)/src/libfreeswan/libfreeswan.a $(top_srcdir)/src/libc _pluto_adns_LDADD = -lresolv $(top_srcdir)/src/libfreeswan/libfreeswan.a dist_man_MANS = pluto.8 ipsec.secrets.5 EXTRA_DIST = oid.pl oid.txt +BUILT_SOURCES = oid.c oid.h MAINTAINERCLEANFILES = oid.c oid.h oid.c: oid.txt oid.pl diff --git a/src/stroke/stroke_keywords.c b/src/stroke/stroke_keywords.c deleted file mode 100644 index f622d2dee..000000000 --- a/src/stroke/stroke_keywords.c +++ /dev/null @@ -1,157 +0,0 @@ -/* C code produced by gperf version 3.0.1 */ -/* Command-line: /usr/bin/gperf -C -G -t */ -/* Computed positions: -k'2' */ - -#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ - && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ - && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ - && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ - && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ - && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ - && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ - && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ - && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ - && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ - && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ - && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ - && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ - && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ - && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ - && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ - && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ - && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ - && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ - && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ - && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ - && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ - && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) -/* The character set is not based on ISO-646. */ -error "gperf generated tables don't work with this execution character set. Please report a bug to ." -#endif - - -/* stroke keywords - * Copyright (C) 2006 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * RCSID $Id: keywords.txt,v 1.6 2006/04/17 10:30:27 as Exp $ - */ - -#include - -#include "stroke_keywords.h" - -struct stroke_token { - char *name; - stroke_keyword_t kw; -}; - -#define TOTAL_KEYWORDS 17 -#define MIN_WORD_LENGTH 2 -#define MAX_WORD_LENGTH 13 -#define MIN_HASH_VALUE 2 -#define MAX_HASH_VALUE 23 -/* maximum key range = 22, duplicates = 0 */ - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static unsigned int -hash (str, len) - register const char *str; - register unsigned int len; -{ - static const unsigned char asso_values[] = - { - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 20, 0, 24, 24, 24, 10, 24, 24, 24, 24, - 24, 0, 0, 24, 24, 24, 5, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24 - }; - return len + asso_values[(unsigned char)str[1]]; -} - -static const struct stroke_token wordlist[] = - { - {""}, {""}, - {"up", STROKE_UP}, - {"del", STROKE_DEL}, - {"down", STROKE_DOWN}, - {"route", STROKE_ROUTE}, - {"delete", STROKE_DELETE}, - {"logtype", STROKE_LOGTYPE}, - {"loglevel", STROKE_LOGLEVEL}, - {"rereadall", STROKE_REREAD_ALL}, - {"rereadcrls", STROKE_REREAD_CRLS,}, - {"status", STROKE_STATUS}, - {""}, - {"rereadcacerts", STROKE_REREAD_CACERTS,}, - {"statusall", STROKE_STATUSALL}, - {""}, {""}, - {"listall", STROKE_LIST_ALL,}, - {"listcrls", STROKE_LIST_CRLS}, - {"listcerts", STROKE_LIST_CERTS}, - {""}, - {"listcacerts", STROKE_LIST_CACERTS}, - {""}, - {"add", STROKE_ADD} - }; - -#ifdef __GNUC__ -__inline -#endif -const struct stroke_token * -in_word_set (str, len) - register const char *str; - register unsigned int len; -{ - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = hash (str, len); - - if (key <= MAX_HASH_VALUE && key >= 0) - { - register const char *s = wordlist[key].name; - - if (*str == *s && !strcmp (str + 1, s + 1)) - return &wordlist[key]; - } - } - return 0; -}