2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
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>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "unity_handler.h"
19 #include <threading/mutex.h>
20 #include <utils/linked_list.h>
21 #include <processing/jobs/callback_job.h>
23 typedef struct private_unity_handler_t private_unity_handler_t
;
26 * Private data of an unity_handler_t object.
28 struct private_unity_handler_t
{
31 * Public unity_handler_t interface.
33 unity_handler_t
public;
36 * List of subnets to include, as entry_t
38 linked_list_t
*include
;
41 * Mutex for concurrent access to lists
47 * Traffic selector entry for networks to include under a given IKE_SA
50 /** associated IKE_SA, unique ID */
52 /** traffic selector to include/exclude */
53 traffic_selector_t
*ts
;
59 static void entry_destroy(entry_t
*this)
61 this->ts
->destroy(this->ts
);
66 * Create a traffic selector from a unity subnet definition
68 static traffic_selector_t
*create_ts(chunk_t subnet
)
77 net
= chunk_create(subnet
.ptr
, 4);
78 mask
= chunk_clonea(chunk_skip(subnet
, 4));
79 for (i
= 0; i
< net
.len
; i
++)
81 mask
.ptr
[i
] = (mask
.ptr
[i
] ^ 0xFF) | net
.ptr
[i
];
83 return traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE
,
88 * Store a subnet to include in tunnels under this IKE_SA
90 static bool add_include(private_unity_handler_t
*this, chunk_t subnet
)
92 traffic_selector_t
*ts
;
96 ike_sa
= charon
->bus
->get_sa(charon
->bus
);
101 ts
= create_ts(subnet
);
107 .sa
= ike_sa
->get_unique_id(ike_sa
),
111 this->mutex
->lock(this->mutex
);
112 this->include
->insert_last(this->include
, entry
);
113 this->mutex
->unlock(this->mutex
);
118 * Rempve a subnet from the inclusion list for this IKE_SA
120 static bool remove_include(private_unity_handler_t
*this, chunk_t subnet
)
122 enumerator_t
*enumerator
;
123 traffic_selector_t
*ts
;
127 ike_sa
= charon
->bus
->get_sa(charon
->bus
);
132 ts
= create_ts(subnet
);
138 this->mutex
->lock(this->mutex
);
139 enumerator
= this->include
->create_enumerator(this->include
);
140 while (enumerator
->enumerate(enumerator
, &entry
))
142 if (entry
->sa
== ike_sa
->get_unique_id(ike_sa
) &&
143 ts
->equals(ts
, entry
->ts
))
145 this->include
->remove_at(this->include
, enumerator
);
146 entry_destroy(entry
);
150 enumerator
->destroy(enumerator
);
151 this->mutex
->unlock(this->mutex
);
157 * Create a unique shunt name for a bypass policy
159 static void create_shunt_name(ike_sa_t
*ike_sa
, traffic_selector_t
*ts
,
160 char *buf
, size_t len
)
162 snprintf(buf
, len
, "Unity (%s[%u]: %R)", ike_sa
->get_name(ike_sa
),
163 ike_sa
->get_unique_id(ike_sa
), ts
);
167 * Install entry as a shunt policy
169 static job_requeue_t
add_exclude_async(entry_t
*entry
)
171 enumerator_t
*enumerator
;
172 child_cfg_t
*child_cfg
;
173 lifetime_cfg_t lft
= {};
177 bool has_vip
= FALSE
;
179 ike_sa
= charon
->ike_sa_manager
->checkout_by_id(charon
->ike_sa_manager
,
183 create_shunt_name(ike_sa
, entry
->ts
, name
, sizeof(name
));
185 child_cfg
= child_cfg_create(name
, &lft
, NULL
, TRUE
, MODE_PASS
,
186 ACTION_NONE
, ACTION_NONE
, ACTION_NONE
,
187 FALSE
, 0, 0, NULL
, NULL
, FALSE
);
188 child_cfg
->add_traffic_selector(child_cfg
, FALSE
,
189 entry
->ts
->clone(entry
->ts
));
190 enumerator
= ike_sa
->create_virtual_ip_enumerator(ike_sa
, TRUE
);
191 while (enumerator
->enumerate(enumerator
, &host
))
194 child_cfg
->add_traffic_selector(child_cfg
, TRUE
,
195 traffic_selector_create_from_subnet(host
->clone(host
), 32, 0, 0));
197 enumerator
->destroy(enumerator
);
201 host
= ike_sa
->get_my_host(ike_sa
);
202 child_cfg
->add_traffic_selector(child_cfg
, TRUE
,
203 traffic_selector_create_from_subnet(host
->clone(host
), 32, 0, 0));
205 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
207 charon
->shunts
->install(charon
->shunts
, child_cfg
);
208 child_cfg
->destroy(child_cfg
);
210 DBG1(DBG_IKE
, "installed %N bypass policy for %R",
211 configuration_attribute_type_names
, UNITY_LOCAL_LAN
, entry
->ts
);
213 return JOB_REQUEUE_NONE
;
217 * Add a bypass policy for a given subnet
219 static bool add_exclude(private_unity_handler_t
*this, chunk_t subnet
)
221 traffic_selector_t
*ts
;
225 ike_sa
= charon
->bus
->get_sa(charon
->bus
);
230 ts
= create_ts(subnet
);
236 .sa
= ike_sa
->get_unique_id(ike_sa
),
240 /* we can't install the shunt policy yet, as we don't know the virtual IP.
241 * Defer installation using an async callback. */
242 lib
->processor
->queue_job(lib
->processor
, (job_t
*)
243 callback_job_create((void*)add_exclude_async
, entry
,
244 (void*)entry_destroy
, NULL
));
249 * Remove a bypass policy for a given subnet
251 static bool remove_exclude(private_unity_handler_t
*this, chunk_t subnet
)
253 traffic_selector_t
*ts
;
257 ike_sa
= charon
->bus
->get_sa(charon
->bus
);
262 ts
= create_ts(subnet
);
267 create_shunt_name(ike_sa
, ts
, name
, sizeof(name
));
268 DBG1(DBG_IKE
, "uninstalling %N bypass policy for %R",
269 configuration_attribute_type_names
, UNITY_LOCAL_LAN
, ts
);
271 return charon
->shunts
->uninstall(charon
->shunts
, name
);
274 METHOD(attribute_handler_t
, handle
, bool,
275 private_unity_handler_t
*this, identification_t
*id
,
276 configuration_attribute_type_t type
, chunk_t data
)
280 case UNITY_SPLIT_INCLUDE
:
281 return add_include(this, data
);
282 case UNITY_LOCAL_LAN
:
283 return add_exclude(this, data
);
289 METHOD(attribute_handler_t
, release
, void,
290 private_unity_handler_t
*this, identification_t
*server
,
291 configuration_attribute_type_t type
, chunk_t data
)
295 case UNITY_SPLIT_INCLUDE
:
296 remove_include(this, data
);
298 case UNITY_LOCAL_LAN
:
299 remove_exclude(this, data
);
307 * Configuration attributes to request
309 static configuration_attribute_type_t attributes
[] = {
315 * Attribute enumerator implementation
318 /** implements enumerator_t */
320 /** position in attributes[] */
322 } attribute_enumerator_t
;
324 METHOD(enumerator_t
, enumerate_attributes
, bool,
325 attribute_enumerator_t
*this, configuration_attribute_type_t
*type
,
328 if (this->i
< countof(attributes
))
330 *type
= attributes
[this->i
++];
337 METHOD(attribute_handler_t
, create_attribute_enumerator
, enumerator_t
*,
338 unity_handler_t
*this, identification_t
*id
, linked_list_t
*vips
)
340 attribute_enumerator_t
*enumerator
;
344 .enumerate
= (void*)_enumerate_attributes
,
345 .destroy
= (void*)free
,
348 return &enumerator
->public;
352 /** mutex to unlock */
354 /** IKE_SA ID to filter for */
359 * Include enumerator filter function
361 static bool include_filter(include_filter_t
*data
,
362 entry_t
**entry
, traffic_selector_t
**ts
)
364 if ((*entry
)->sa
== data
->id
)
373 * Destroy include filter data, unlock mutex
375 static void destroy_filter(include_filter_t
*data
)
377 data
->mutex
->unlock(data
->mutex
);
381 METHOD(unity_handler_t
, create_include_enumerator
, enumerator_t
*,
382 private_unity_handler_t
*this, u_int32_t id
)
384 include_filter_t
*data
;
387 .mutex
= this->mutex
,
390 data
->mutex
->lock(data
->mutex
);
391 return enumerator_create_filter(
392 this->include
->create_enumerator(this->include
),
393 (void*)include_filter
, data
, (void*)destroy_filter
);
396 METHOD(unity_handler_t
, destroy
, void,
397 private_unity_handler_t
*this)
399 this->include
->destroy(this->include
);
400 this->mutex
->destroy(this->mutex
);
407 unity_handler_t
*unity_handler_create()
409 private_unity_handler_t
*this;
416 .create_attribute_enumerator
= _create_attribute_enumerator
,
418 .create_include_enumerator
= _create_include_enumerator
,
421 .include
= linked_list_create(),
422 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
425 return &this->public;