source address lookup in kernel interface
use it for NAT detection if no source address known from config support for %any...%any connections
This commit is contained in:
parent
209c2e9049
commit
7068410b6f
|
@ -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;
|
||||
|
|
|
@ -267,6 +267,18 @@ struct kernel_interface_t {
|
|||
traffic_selector_t *dst_ts,
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
host = this->ike_sa->get_my_host(this->ike_sa);
|
||||
if (host->is_anyaddr(host))
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{ /* 1. */
|
||||
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
|
||||
message->add_payload(message, (payload_t*)notify);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue