2 * Copyright (C) 2012-2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 #include "kernel_libipsec_ipsec.h"
16 #include "kernel_libipsec_router.h"
21 #include <networking/tun_device.h>
22 #include <threading/mutex.h>
23 #include <utils/debug.h>
25 typedef struct private_kernel_libipsec_ipsec_t private_kernel_libipsec_ipsec_t
;
27 struct private_kernel_libipsec_ipsec_t
{
30 * Public libipsec_ipsec interface
32 kernel_libipsec_ipsec_t
public;
35 * Listener for lifetime expire events
37 ipsec_event_listener_t ipsec_listener
;
40 * Mutex to lock access to various lists
45 * List of installed policies (policy_entry_t)
47 linked_list_t
*policies
;
50 * List of exclude routes (exclude_route_t)
52 linked_list_t
*excludes
;
55 * Whether the remote TS may equal the IKE peer
60 typedef struct exclude_route_t exclude_route_t
;
63 * Exclude route definition
65 struct exclude_route_t
{
66 /** Destination address to exclude */
68 /** Source address for route */
70 /** Nexthop exclude has been installed */
72 /** References to this route */
77 * Clean up an exclude route entry
79 static void exclude_route_destroy(exclude_route_t
*this)
81 this->dst
->destroy(this->dst
);
82 this->src
->destroy(this->src
);
83 this->gtw
->destroy(this->gtw
);
88 * Find an exclude route entry by destination address
90 static bool exclude_route_match(exclude_route_t
*current
,
93 return dst
->ip_equals(dst
, current
->dst
);
96 typedef struct route_entry_t route_entry_t
;
99 * Installed routing entry
101 struct route_entry_t
{
102 /** Name of the interface the route is bound to */
104 /** Source IP of the route */
106 /** Gateway of the route */
108 /** Destination net */
110 /** Destination net prefixlen */
112 /** Reference to exclude route, if any */
113 exclude_route_t
*exclude
;
117 * Destroy a route_entry_t object
119 static void route_entry_destroy(route_entry_t
*this)
122 DESTROY_IF(this->src_ip
);
123 DESTROY_IF(this->gateway
);
124 chunk_free(&this->dst_net
);
129 * Compare two route_entry_t objects
131 static bool route_entry_equals(route_entry_t
*a
, route_entry_t
*b
)
133 if ((!a
->src_ip
&& !b
->src_ip
) || (a
->src_ip
&& b
->src_ip
&&
134 a
->src_ip
->ip_equals(a
->src_ip
, b
->src_ip
)))
136 if ((!a
->gateway
&& !b
->gateway
) || (a
->gateway
&& b
->gateway
&&
137 a
->gateway
->ip_equals(a
->gateway
, b
->gateway
)))
139 return a
->if_name
&& b
->if_name
&& streq(a
->if_name
, b
->if_name
) &&
140 chunk_equals(a
->dst_net
, b
->dst_net
) &&
141 a
->prefixlen
== b
->prefixlen
;
147 typedef struct policy_entry_t policy_entry_t
;
152 struct policy_entry_t
{
153 /** Direction of this policy: in, out, forward */
155 /** Parameters of installed policy */
157 /** Subnet and port */
164 /** Associated route installed for this policy */
165 route_entry_t
*route
;
166 /** References to this policy */
171 * Create a policy_entry_t object
173 static policy_entry_t
*create_policy_entry(traffic_selector_t
*src_ts
,
174 traffic_selector_t
*dst_ts
,
177 policy_entry_t
*this;
182 src_ts
->to_subnet(src_ts
, &this->src
.net
, &this->src
.mask
);
183 dst_ts
->to_subnet(dst_ts
, &this->dst
.net
, &this->dst
.mask
);
185 /* src or dest proto may be "any" (0), use more restrictive one */
186 this->src
.proto
= max(src_ts
->get_protocol(src_ts
),
187 dst_ts
->get_protocol(dst_ts
));
188 this->src
.proto
= this->src
.proto ?
this->src
.proto
: 0;
189 this->dst
.proto
= this->src
.proto
;
194 * Destroy a policy_entry_t object
196 static void policy_entry_destroy(policy_entry_t
*this)
200 route_entry_destroy(this->route
);
202 DESTROY_IF(this->src
.net
);
203 DESTROY_IF(this->dst
.net
);
208 * Compare two policy_entry_t objects
210 static inline bool policy_entry_equals(policy_entry_t
*a
,
213 return a
->direction
== b
->direction
&&
214 a
->src
.proto
== b
->src
.proto
&&
215 a
->dst
.proto
== b
->dst
.proto
&&
216 a
->src
.mask
== b
->src
.mask
&&
217 a
->dst
.mask
== b
->dst
.mask
&&
218 a
->src
.net
->equals(a
->src
.net
, b
->src
.net
) &&
219 a
->dst
.net
->equals(a
->dst
.net
, b
->dst
.net
);
223 * Expiration callback
225 static void expire(u_int8_t protocol
, u_int32_t spi
, host_t
*dst
, bool hard
)
227 hydra
->kernel_interface
->expire(hydra
->kernel_interface
, protocol
,
231 METHOD(kernel_ipsec_t
, get_features
, kernel_feature_t
,
232 private_kernel_libipsec_ipsec_t
*this)
234 return KERNEL_REQUIRE_UDP_ENCAPSULATION
| KERNEL_ESP_V3_TFC
;
237 METHOD(kernel_ipsec_t
, get_spi
, status_t
,
238 private_kernel_libipsec_ipsec_t
*this, host_t
*src
, host_t
*dst
,
239 u_int8_t protocol
, u_int32_t
*spi
)
241 return ipsec
->sas
->get_spi(ipsec
->sas
, src
, dst
, protocol
, spi
);
244 METHOD(kernel_ipsec_t
, get_cpi
, status_t
,
245 private_kernel_libipsec_ipsec_t
*this, host_t
*src
, host_t
*dst
,
248 return NOT_SUPPORTED
;
251 METHOD(kernel_ipsec_t
, add_sa
, status_t
,
252 private_kernel_libipsec_ipsec_t
*this, host_t
*src
, host_t
*dst
,
253 u_int32_t spi
, u_int8_t protocol
, u_int32_t reqid
, mark_t mark
,
254 u_int32_t tfc
, lifetime_cfg_t
*lifetime
, u_int16_t enc_alg
, chunk_t enc_key
,
255 u_int16_t int_alg
, chunk_t int_key
, ipsec_mode_t mode
,
256 u_int16_t ipcomp
, u_int16_t cpi
, u_int32_t replay_window
,
257 bool initiator
, bool encap
, bool esn
, bool inbound
, bool update
,
258 linked_list_t
*src_ts
, linked_list_t
*dst_ts
)
260 return ipsec
->sas
->add_sa(ipsec
->sas
, src
, dst
, spi
, protocol
, reqid
, mark
,
261 tfc
, lifetime
, enc_alg
, enc_key
, int_alg
, int_key
,
262 mode
, ipcomp
, cpi
, initiator
, encap
, esn
,
266 METHOD(kernel_ipsec_t
, update_sa
, status_t
,
267 private_kernel_libipsec_ipsec_t
*this, u_int32_t spi
, u_int8_t protocol
,
268 u_int16_t cpi
, host_t
*src
, host_t
*dst
, host_t
*new_src
, host_t
*new_dst
,
269 bool encap
, bool new_encap
, mark_t mark
)
271 return NOT_SUPPORTED
;
274 METHOD(kernel_ipsec_t
, query_sa
, status_t
,
275 private_kernel_libipsec_ipsec_t
*this, host_t
*src
, host_t
*dst
,
276 u_int32_t spi
, u_int8_t protocol
, mark_t mark
, u_int64_t
*bytes
,
277 u_int64_t
*packets
, time_t *time
)
279 return ipsec
->sas
->query_sa(ipsec
->sas
, src
, dst
, spi
, protocol
, mark
,
280 bytes
, packets
, time
);
283 METHOD(kernel_ipsec_t
, del_sa
, status_t
,
284 private_kernel_libipsec_ipsec_t
*this, host_t
*src
, host_t
*dst
,
285 u_int32_t spi
, u_int8_t protocol
, u_int16_t cpi
, mark_t mark
)
287 return ipsec
->sas
->del_sa(ipsec
->sas
, src
, dst
, spi
, protocol
, cpi
, mark
);
290 METHOD(kernel_ipsec_t
, flush_sas
, status_t
,
291 private_kernel_libipsec_ipsec_t
*this)
293 return ipsec
->sas
->flush_sas(ipsec
->sas
);
297 * Add an explicit exclude route to a routing entry
299 static void add_exclude_route(private_kernel_libipsec_ipsec_t
*this,
300 route_entry_t
*route
, host_t
*src
, host_t
*dst
)
302 exclude_route_t
*exclude
;
305 if (this->excludes
->find_first(this->excludes
,
306 (linked_list_match_t
)exclude_route_match
,
307 (void**)&exclude
, dst
) == SUCCESS
)
309 route
->exclude
= exclude
;
315 DBG2(DBG_KNL
, "installing new exclude route for %H src %H", dst
, src
);
316 gtw
= hydra
->kernel_interface
->get_nexthop(hydra
->kernel_interface
,
320 char *if_name
= NULL
;
322 if (hydra
->kernel_interface
->get_interface(
323 hydra
->kernel_interface
, src
, &if_name
) &&
324 hydra
->kernel_interface
->add_route(hydra
->kernel_interface
,
325 dst
->get_address(dst
),
326 dst
->get_family(dst
) == AF_INET ?
32 : 128,
327 gtw
, src
, if_name
) == SUCCESS
)
330 .dst
= dst
->clone(dst
),
331 .src
= src
->clone(src
),
332 .gtw
= gtw
->clone(gtw
),
335 route
->exclude
= exclude
;
336 this->excludes
->insert_last(this->excludes
, exclude
);
340 DBG1(DBG_KNL
, "installing exclude route for %H failed", dst
);
347 DBG1(DBG_KNL
, "gateway lookup for %H failed", dst
);
353 * Remove an exclude route attached to a routing entry
355 static void remove_exclude_route(private_kernel_libipsec_ipsec_t
*this,
356 route_entry_t
*route
)
358 char *if_name
= NULL
;
361 if (!route
->exclude
|| --route
->exclude
->refs
> 0)
365 this->excludes
->remove(this->excludes
, route
->exclude
, NULL
);
367 dst
= route
->exclude
->dst
;
368 DBG2(DBG_KNL
, "uninstalling exclude route for %H src %H",
369 dst
, route
->exclude
->src
);
370 if (hydra
->kernel_interface
->get_interface(
371 hydra
->kernel_interface
,
372 route
->exclude
->src
, &if_name
) &&
373 hydra
->kernel_interface
->del_route(hydra
->kernel_interface
,
374 dst
->get_address(dst
),
375 dst
->get_family(dst
) == AF_INET ?
32 : 128,
376 route
->exclude
->gtw
, route
->exclude
->src
,
379 DBG1(DBG_KNL
, "uninstalling exclude route for %H failed", dst
);
381 exclude_route_destroy(route
->exclude
);
382 route
->exclude
= NULL
;
387 * Install a route for the given policy
389 * this->mutex is released by this function
391 static bool install_route(private_kernel_libipsec_ipsec_t
*this,
392 host_t
*src
, host_t
*dst
, traffic_selector_t
*src_ts
,
393 traffic_selector_t
*dst_ts
, policy_entry_t
*policy
)
395 route_entry_t
*route
, *old
;
399 if (policy
->direction
!= POLICY_OUT
)
401 this->mutex
->unlock(this->mutex
);
405 if (hydra
->kernel_interface
->get_address_by_ts(hydra
->kernel_interface
,
406 src_ts
, &src_ip
, &is_virtual
) != SUCCESS
)
408 traffic_selector_t
*multicast
, *broadcast
= NULL
;
411 this->mutex
->unlock(this->mutex
);
412 switch (src_ts
->get_type(src_ts
))
414 case TS_IPV4_ADDR_RANGE
:
415 multicast
= traffic_selector_create_from_cidr("224.0.0.0/4",
417 broadcast
= traffic_selector_create_from_cidr("255.255.255.255/32",
420 case TS_IPV6_ADDR_RANGE
:
421 multicast
= traffic_selector_create_from_cidr("ff00::/8",
427 ignore
= src_ts
->is_contained_in(src_ts
, multicast
);
428 ignore
|= broadcast
&& src_ts
->is_contained_in(src_ts
, broadcast
);
429 multicast
->destroy(multicast
);
430 DESTROY_IF(broadcast
);
433 DBG1(DBG_KNL
, "error installing route with policy %R === %R %N",
434 src_ts
, dst_ts
, policy_dir_names
, policy
->direction
);
440 .if_name
= router
->get_tun_name(router
, is_virtual ? src_ip
: NULL
),
442 .dst_net
= chunk_clone(policy
->dst
.net
->get_address(policy
->dst
.net
)),
443 .prefixlen
= policy
->dst
.mask
,
446 /* on Linux we cant't install a gateway */
447 route
->gateway
= hydra
->kernel_interface
->get_nexthop(
448 hydra
->kernel_interface
, dst
, -1, src
);
455 if (route_entry_equals(old
, route
))
456 { /* such a route already exists */
457 route_entry_destroy(route
);
458 this->mutex
->unlock(this->mutex
);
461 /* uninstall previously installed route */
462 if (hydra
->kernel_interface
->del_route(hydra
->kernel_interface
,
463 old
->dst_net
, old
->prefixlen
, old
->gateway
,
464 old
->src_ip
, old
->if_name
) != SUCCESS
)
466 DBG1(DBG_KNL
, "error uninstalling route installed with policy "
467 "%R === %R %N", src_ts
, dst_ts
, policy_dir_names
,
470 route_entry_destroy(old
);
471 policy
->route
= NULL
;
474 if (!this->allow_peer_ts
&& dst_ts
->is_host(dst_ts
, dst
))
476 DBG1(DBG_KNL
, "can't install route for %R === %R %N, conflicts with "
477 "IKE traffic", src_ts
, dst_ts
, policy_dir_names
,
479 route_entry_destroy(route
);
480 this->mutex
->unlock(this->mutex
);
483 /* if remote traffic selector covers the IKE peer, add an exclude route */
484 if (!this->allow_peer_ts
&& dst_ts
->includes(dst_ts
, dst
))
486 /* add exclude route for peer */
487 add_exclude_route(this, route
, src
, dst
);
490 DBG2(DBG_KNL
, "installing route: %R src %H dev %s",
491 dst_ts
, route
->src_ip
, route
->if_name
);
493 switch (hydra
->kernel_interface
->add_route(hydra
->kernel_interface
,
494 route
->dst_net
, route
->prefixlen
, route
->gateway
,
495 route
->src_ip
, route
->if_name
))
498 /* route exists, do not uninstall */
499 remove_exclude_route(this, route
);
500 route_entry_destroy(route
);
501 this->mutex
->unlock(this->mutex
);
504 /* cache the installed route */
505 policy
->route
= route
;
506 this->mutex
->unlock(this->mutex
);
509 DBG1(DBG_KNL
, "installing route failed: %R src %H dev %s",
510 dst_ts
, route
->src_ip
, route
->if_name
);
511 remove_exclude_route(this, route
);
512 route_entry_destroy(route
);
513 this->mutex
->unlock(this->mutex
);
518 METHOD(kernel_ipsec_t
, add_policy
, status_t
,
519 private_kernel_libipsec_ipsec_t
*this, host_t
*src
, host_t
*dst
,
520 traffic_selector_t
*src_ts
, traffic_selector_t
*dst_ts
,
521 policy_dir_t direction
, policy_type_t type
, ipsec_sa_cfg_t
*sa
, mark_t mark
,
522 policy_priority_t priority
)
524 policy_entry_t
*policy
, *found
= NULL
;
527 status
= ipsec
->policies
->add_policy(ipsec
->policies
, src
, dst
, src_ts
,
528 dst_ts
, direction
, type
, sa
, mark
, priority
);
529 if (status
!= SUCCESS
)
533 /* we track policies in order to install routes */
534 policy
= create_policy_entry(src_ts
, dst_ts
, direction
);
536 this->mutex
->lock(this->mutex
);
537 if (this->policies
->find_first(this->policies
,
538 (linked_list_match_t
)policy_entry_equals
,
539 (void**)&found
, policy
) == SUCCESS
)
541 policy_entry_destroy(policy
);
545 { /* use the new one, if we have no such policy */
546 this->policies
->insert_last(this->policies
, policy
);
550 if (!install_route(this, src
, dst
, src_ts
, dst_ts
, policy
))
557 METHOD(kernel_ipsec_t
, query_policy
, status_t
,
558 private_kernel_libipsec_ipsec_t
*this, traffic_selector_t
*src_ts
,
559 traffic_selector_t
*dst_ts
, policy_dir_t direction
, mark_t mark
,
562 return NOT_SUPPORTED
;
565 METHOD(kernel_ipsec_t
, del_policy
, status_t
,
566 private_kernel_libipsec_ipsec_t
*this, traffic_selector_t
*src_ts
,
567 traffic_selector_t
*dst_ts
, policy_dir_t direction
, u_int32_t reqid
,
568 mark_t mark
, policy_priority_t priority
)
570 policy_entry_t
*policy
, *found
= NULL
;
573 status
= ipsec
->policies
->del_policy(ipsec
->policies
, src_ts
, dst_ts
,
574 direction
, reqid
, mark
, priority
);
576 policy
= create_policy_entry(src_ts
, dst_ts
, direction
);
578 this->mutex
->lock(this->mutex
);
579 if (this->policies
->find_first(this->policies
,
580 (linked_list_match_t
)policy_entry_equals
,
581 (void**)&found
, policy
) != SUCCESS
)
583 policy_entry_destroy(policy
);
584 this->mutex
->unlock(this->mutex
);
587 policy_entry_destroy(policy
);
590 if (--policy
->refs
> 0)
591 { /* policy is still in use */
592 this->mutex
->unlock(this->mutex
);
598 route_entry_t
*route
= policy
->route
;
600 if (hydra
->kernel_interface
->del_route(hydra
->kernel_interface
,
601 route
->dst_net
, route
->prefixlen
, route
->gateway
, route
->src_ip
,
602 route
->if_name
) != SUCCESS
)
604 DBG1(DBG_KNL
, "error uninstalling route installed with "
605 "policy %R === %R %N", src_ts
, dst_ts
,
606 policy_dir_names
, direction
);
608 remove_exclude_route(this, route
);
610 this->policies
->remove(this->policies
, policy
, NULL
);
611 policy_entry_destroy(policy
);
612 this->mutex
->unlock(this->mutex
);
616 METHOD(kernel_ipsec_t
, flush_policies
, status_t
,
617 private_kernel_libipsec_ipsec_t
*this)
622 status
= ipsec
->policies
->flush_policies(ipsec
->policies
);
624 this->mutex
->lock(this->mutex
);
625 while (this->policies
->remove_first(this->policies
, (void*)&pol
) == SUCCESS
)
629 route_entry_t
*route
= pol
->route
;
631 hydra
->kernel_interface
->del_route(hydra
->kernel_interface
,
632 route
->dst_net
, route
->prefixlen
, route
->gateway
,
633 route
->src_ip
, route
->if_name
);
634 remove_exclude_route(this, route
);
636 policy_entry_destroy(pol
);
638 this->mutex
->unlock(this->mutex
);
642 METHOD(kernel_ipsec_t
, bypass_socket
, bool,
643 private_kernel_libipsec_ipsec_t
*this, int fd
, int family
)
645 /* we use exclude routes for this */
646 return NOT_SUPPORTED
;
649 METHOD(kernel_ipsec_t
, enable_udp_decap
, bool,
650 private_kernel_libipsec_ipsec_t
*this, int fd
, int family
, u_int16_t port
)
652 return NOT_SUPPORTED
;
655 METHOD(kernel_ipsec_t
, destroy
, void,
656 private_kernel_libipsec_ipsec_t
*this)
658 ipsec
->events
->unregister_listener(ipsec
->events
, &this->ipsec_listener
);
659 this->policies
->destroy_function(this->policies
, (void*)policy_entry_destroy
);
660 this->excludes
->destroy(this->excludes
);
661 this->mutex
->destroy(this->mutex
);
666 * Described in header.
668 kernel_libipsec_ipsec_t
*kernel_libipsec_ipsec_create()
670 private_kernel_libipsec_ipsec_t
*this;
675 .get_features
= _get_features
,
679 .update_sa
= _update_sa
,
680 .query_sa
= _query_sa
,
682 .flush_sas
= _flush_sas
,
683 .add_policy
= _add_policy
,
684 .query_policy
= _query_policy
,
685 .del_policy
= _del_policy
,
686 .flush_policies
= _flush_policies
,
687 .bypass_socket
= _bypass_socket
,
688 .enable_udp_decap
= _enable_udp_decap
,
695 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
696 .policies
= linked_list_create(),
697 .excludes
= linked_list_create(),
698 .allow_peer_ts
= lib
->settings
->get_bool(lib
->settings
,
699 "%s.plugins.kernel-libipsec.allow_peer_ts", FALSE
, lib
->ns
),
702 ipsec
->events
->register_listener(ipsec
->events
, &this->ipsec_listener
);
704 return &this->public;