diff options
author | Martin Willi <martin@strongswan.org> | 2007-06-18 07:25:58 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2007-06-18 07:25:58 +0000 |
commit | 7068410b6f1bc370a6764a5c282d1240eb419aa2 (patch) | |
tree | d39a9a942c5400a14d2255ae2060d383fa924118 | |
parent | 209c2e9049d2f8ba40afa38e4837f1f8245abfe3 (diff) | |
download | strongswan-7068410b6f1bc370a6764a5c282d1240eb419aa2.tar.bz2 strongswan-7068410b6f1bc370a6764a5c282d1240eb419aa2.tar.xz |
source address lookup in kernel interface
use it for NAT detection if no source address known from config
support for %any...%any connections
-rw-r--r-- | src/charon/kernel/kernel_interface.c | 80 | ||||
-rw-r--r-- | src/charon/kernel/kernel_interface.h | 12 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 2 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_natd.c | 50 |
4 files changed, 125 insertions, 19 deletions
diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c index 919dad855..641ed837b 100644 --- a/src/charon/kernel/kernel_interface.c +++ b/src/charon/kernel/kernel_interface.c @@ -1342,6 +1342,84 @@ static status_t manage_srcroute(private_kernel_interface_t *this, int nlmsg_type return netlink_send_ack(this, this->socket_rt, hdr); } +/** + * Implementation of kernel_interface_t.get_source_addr. + */ +static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest) +{ + unsigned char request[BUFFER_SIZE]; + struct nlmsghdr *hdr, *out, *current; + struct rtmsg *msg; + chunk_t chunk; + size_t len; + host_t *source = NULL; + + memset(&request, 0, sizeof(request)); + + hdr = (struct nlmsghdr*)request; + hdr->nlmsg_flags = NLM_F_REQUEST; + hdr->nlmsg_type = RTM_GETROUTE; + hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + + msg = (struct rtmsg*)NLMSG_DATA(hdr); + msg->rtm_family = dest->get_family(dest); + msg->rtm_dst_len = msg->rtm_family == AF_INET ? 32 : 128; + msg->rtm_table = RT_TABLE_MAIN; + msg->rtm_protocol = RTPROT_STATIC; + msg->rtm_type = RTN_UNICAST; + msg->rtm_scope = RT_SCOPE_UNIVERSE; + + chunk = dest->get_address(dest); + add_attribute(hdr, RTA_DST, chunk, sizeof(request)); + + if (netlink_send(this, this->socket_rt, hdr, &out, &len) != SUCCESS) + { + DBG1(DBG_KNL, "getting source address to %H failed", dest); + return NULL; + } + current = out; + while (NLMSG_OK(current, len)) + { + switch (current->nlmsg_type) + { + case NLMSG_DONE: + break; + case RTM_NEWROUTE: + { + struct rtattr *rta; + size_t rtasize; + + msg = (struct rtmsg*)(NLMSG_DATA(current)); + rta = RTM_RTA(msg); + rtasize = RTM_PAYLOAD(current); + while(RTA_OK(rta, rtasize)) + { + switch (rta->rta_type) + { + case RTA_PREFSRC: + chunk.ptr = RTA_DATA(rta); + chunk.len = RTA_PAYLOAD(rta); + source = host_create_from_chunk(msg->rtm_family, + chunk, 0); + break; + } + rta = RTA_NEXT(rta, rtasize); + } + break; + } + default: + current = NLMSG_NEXT(current, len); + continue; + } + break; + } + if (source == NULL) + { + DBG1(DBG_KNL, "no route found to %H", dest); + } + free(out); + return source; +} /** * Implementation of kernel_interface_t.add_ip. @@ -2209,9 +2287,9 @@ kernel_interface_t *kernel_interface_create() 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,mode_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.get_interface = (char*(*)(kernel_interface_t*,host_t*))get_interface_name; this->public.create_address_iterator = (iterator_t*(*)(kernel_interface_t*))create_address_iterator; + this->public.get_source_addr = (host_t*(*)(kernel_interface_t*, host_t *dest))get_source_addr; this->public.add_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) add_ip; this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) del_ip; this->public.destroy = (void(*)(kernel_interface_t*)) destroy; diff --git a/src/charon/kernel/kernel_interface.h b/src/charon/kernel/kernel_interface.h index ef576b9ef..39eb6d475 100644 --- a/src/charon/kernel/kernel_interface.h +++ b/src/charon/kernel/kernel_interface.h @@ -268,6 +268,18 @@ struct kernel_interface_t { policy_dir_t direction); /** + * @brief Get our outgoing source address for a destination. + * + * Does a route lookup to get the source address used to reach dest. + * The returned host is allocated and must be destroyed. + * + * @param this calling object + * @param dest target destination address + * @return outgoing source address, NULL if unreachable + */ + host_t* (*get_source_addr)(kernel_interface_t *this, host_t *dest); + + /** * @brief Get the interface name of a local address. * * @param this calling object diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 46dc94c55..e4e076297 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -763,7 +763,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) } /* check if message is trustworthy, and update host information */ - if (this->state == IKE_CREATED || + if (this->state == IKE_CREATED || this->state == IKE_CONNECTING || message->get_exchange_type(message) != IKE_SA_INIT) { update_hosts(this, me, other); diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index 9b355d773..5ae3666ea 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -243,29 +243,45 @@ static status_t build_i(private_ike_natd_t *this, message_t *message) iterator_t *iterator; host_t *host; - /* include one notify if our address is defined, all addresses otherwise */ + /* destination is always set */ + host = this->ike_sa->get_other_host(this->ike_sa); + notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host); + message->add_payload(message, (payload_t*)notify); + + /* source may be any, we have 3 possibilities to get our source address: + * 1. It is defined in the config => use the one of the IKE_SA + * 2. We do a routing lookup in the kernel interface + * 3. Include all possbile addresses + */ host = this->ike_sa->get_my_host(this->ike_sa); - if (host->is_anyaddr(host)) + if (!host->is_anyaddr(host)) + { /* 1. */ + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); + message->add_payload(message, (payload_t*)notify); + } + else { - iterator = charon->kernel_interface->create_address_iterator( - charon->kernel_interface); - while (iterator->iterate(iterator, (void**)&host)) - { + host = charon->kernel_interface->get_source_addr( + charon->kernel_interface, + this->ike_sa->get_other_host(this->ike_sa)); + if (host) + { /* 2. */ notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); message->add_payload(message, (payload_t*)notify); + host->destroy(host); + } + else + { /* 3. */ + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + while (iterator->iterate(iterator, (void**)&host)) + { + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); + message->add_payload(message, (payload_t*)notify); + } + iterator->destroy(iterator); } - iterator->destroy(iterator); - } - else - { - notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); - message->add_payload(message, (payload_t*)notify); } - - host = this->ike_sa->get_other_host(this->ike_sa); - notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host); - message->add_payload(message, (payload_t*)notify); - return NEED_MORE; } |