Annotation of embedaddon/strongswan/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2016 Tobias Brunner
3: * HSR Hochschule fuer Technik Rapperswil
4: *
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: *
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
13: * for more details.
14: */
15:
16: #include "bypass_lan_listener.h"
17:
18: #include <collections/hashtable.h>
19: #include <collections/linked_list.h>
20: #include <threading/mutex.h>
21: #include <processing/jobs/callback_job.h>
22:
23: #include <daemon.h>
24:
25: typedef struct private_bypass_lan_listener_t private_bypass_lan_listener_t;
26:
27: /**
28: * Private data
29: */
30: struct private_bypass_lan_listener_t {
31:
32: /**
33: * Public interface.
34: */
35: bypass_lan_listener_t public;
36:
37: /**
38: * Currently installed bypass policies, bypass_policy_t*.
39: */
40: hashtable_t *policies;
41:
42: /**
43: * Mutex to access list of policies.
44: */
45: mutex_t *mutex;
46:
47: /**
48: * List of interface names to include or exclude (char*), NULL if interfaces
49: * are not filtered.
50: */
51: linked_list_t *ifaces_filter;
52:
53: /**
54: * TRUE to exclude interfaces listed in ifaces_filter, FALSE to consider
55: * only those listed there.
56: */
57: bool ifaces_exclude;
58: };
59:
60: /**
61: * Data for bypass policies
62: */
63: typedef struct {
64: private_bypass_lan_listener_t *listener;
65: host_t *net;
66: uint8_t mask;
67: char *iface;
68: child_cfg_t *cfg;
69: } bypass_policy_t;
70:
71: /**
72: * Destroy a bypass policy
73: */
74: static void bypass_policy_destroy(bypass_policy_t *this)
75: {
76: traffic_selector_t *ts;
77:
78: if (this->cfg)
79: {
80: ts = traffic_selector_create_from_subnet(this->net->clone(this->net),
81: this->mask, 0, 0, 65535);
82: DBG1(DBG_IKE, "uninstalling bypass policy for %R", ts);
83: charon->shunts->uninstall(charon->shunts, "bypass-lan",
84: this->cfg->get_name(this->cfg));
85: this->cfg->destroy(this->cfg);
86: ts->destroy(ts);
87: }
88: this->net->destroy(this->net);
89: free(this->iface);
90: free(this);
91: }
92:
93: /**
94: * Hash a bypass policy
95: */
96: static u_int policy_hash(bypass_policy_t *policy)
97: {
98: return chunk_hash_inc(policy->net->get_address(policy->net),
99: chunk_hash(chunk_from_thing(policy->mask)));
100: }
101:
102: /**
103: * Compare bypass policy
104: */
105: static bool policy_equals(bypass_policy_t *a, bypass_policy_t *b)
106: {
107: return a->mask == b->mask && a->net->equals(a->net, b->net);
108: }
109:
110: /**
111: * Check if an interface should be considered
112: */
113: static bool consider_interface(private_bypass_lan_listener_t *this, char *iface)
114: {
115: if (!iface || !this->ifaces_filter)
116: {
117: return TRUE;
118: }
119: return this->ifaces_filter->find_first(this->ifaces_filter,
120: linked_list_match_str, NULL, iface) != this->ifaces_exclude;
121: }
122:
123: /**
124: * Job updating bypass policies
125: */
126: static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
127: {
128: enumerator_t *enumerator;
129: hashtable_t *seen;
130: bypass_policy_t *found, *lookup;
131: traffic_selector_t *ts;
132: host_t *net;
133: uint8_t mask;
134: char *iface;
135:
136: seen = hashtable_create((hashtable_hash_t)policy_hash,
137: (hashtable_equals_t)policy_equals, 4);
138:
139: this->mutex->lock(this->mutex);
140:
141: enumerator = charon->kernel->create_local_subnet_enumerator(charon->kernel);
142: while (enumerator->enumerate(enumerator, &net, &mask, &iface))
143: {
144: if (!consider_interface(this, iface))
145: {
146: continue;
147: }
148:
149: INIT(lookup,
150: .net = net->clone(net),
151: .mask = mask,
152: .iface = strdupnull(iface),
153: );
154: found = seen->put(seen, lookup, lookup);
155: if (found)
156: { /* in case the same subnet is on multiple interfaces */
157: bypass_policy_destroy(found);
158: }
159:
160: found = this->policies->get(this->policies, lookup);
161: if (!found)
162: {
163: child_cfg_create_t child = {
164: .mode = MODE_PASS,
165: };
166: child_cfg_t *cfg;
167: char name[128];
168:
169: ts = traffic_selector_create_from_subnet(net->clone(net), mask,
170: 0, 0, 65535);
171: snprintf(name, sizeof(name), "Bypass LAN %R", ts);
172:
173: cfg = child_cfg_create(name, &child);
174: cfg->add_traffic_selector(cfg, FALSE, ts->clone(ts));
175: cfg->add_traffic_selector(cfg, TRUE, ts);
176: charon->shunts->install(charon->shunts, "bypass-lan", cfg);
177: DBG1(DBG_IKE, "installed bypass policy for %R", ts);
178:
179: INIT(found,
180: .net = net->clone(net),
181: .mask = mask,
182: .iface = strdupnull(iface),
183: .cfg = cfg,
184: );
185: this->policies->put(this->policies, found, found);
186: }
187: }
188: enumerator->destroy(enumerator);
189:
190: enumerator = this->policies->create_enumerator(this->policies);
191: while (enumerator->enumerate(enumerator, NULL, &lookup))
192: {
193: found = seen->get(seen, lookup);
194: if (!found)
195: {
196: this->policies->remove_at(this->policies, enumerator);
197: bypass_policy_destroy(lookup);
198: }
199: else if (!streq(lookup->iface, found->iface))
200: { /* if the subnet is on multiple interfaces, we only get the last
201: * one (hopefully, they are enumerated in a consistent order) */
202: ts = traffic_selector_create_from_subnet(
203: lookup->net->clone(lookup->net),
204: lookup->mask, 0, 0, 65535);
205: DBG1(DBG_IKE, "interface change for bypass policy for %R (from %s "
206: "to %s)", ts, lookup->iface, found->iface);
207: ts->destroy(ts);
208: free(lookup->iface);
209: lookup->iface = strdupnull(found->iface);
210: /* there is currently no API to update shunts, so we remove and
211: * reinstall it to update the route */
212: charon->shunts->uninstall(charon->shunts, "bypass-lan",
213: lookup->cfg->get_name(lookup->cfg));
214: charon->shunts->install(charon->shunts, "bypass-lan", lookup->cfg);
215: }
216: }
217: enumerator->destroy(enumerator);
218: this->mutex->unlock(this->mutex);
219:
220: seen->destroy_function(seen, (void*)bypass_policy_destroy);
221: return JOB_REQUEUE_NONE;
222: }
223:
224: METHOD(kernel_listener_t, roam, bool,
225: private_bypass_lan_listener_t *this, bool address)
226: {
227: lib->processor->queue_job(lib->processor,
228: (job_t*)callback_job_create((callback_job_cb_t)update_bypass, this,
229: NULL, (callback_job_cancel_t)return_false));
230: return TRUE;
231: }
232:
233: METHOD(bypass_lan_listener_t, reload_interfaces, void,
234: private_bypass_lan_listener_t *this)
235: {
236: char *ifaces;
237:
238: this->mutex->lock(this->mutex);
239: DESTROY_FUNCTION_IF(this->ifaces_filter, (void*)free);
240: this->ifaces_filter = NULL;
241: this->ifaces_exclude = FALSE;
242:
243: ifaces = lib->settings->get_str(lib->settings,
244: "%s.plugins.bypass-lan.interfaces_use", NULL, lib->ns);
245: if (!ifaces)
246: {
247: this->ifaces_exclude = TRUE;
248: ifaces = lib->settings->get_str(lib->settings,
249: "%s.plugins.bypass-lan.interfaces_ignore", NULL, lib->ns);
250: }
251: if (ifaces)
252: {
253: enumerator_t *enumerator;
254: char *iface;
255:
256: enumerator = enumerator_create_token(ifaces, ",", " ");
257: while (enumerator->enumerate(enumerator, &iface))
258: {
259: if (!this->ifaces_filter)
260: {
261: this->ifaces_filter = linked_list_create();
262: }
263: this->ifaces_filter->insert_last(this->ifaces_filter,
264: strdup(iface));
265: }
266: enumerator->destroy(enumerator);
267: }
268: this->mutex->unlock(this->mutex);
269: lib->processor->queue_job(lib->processor,
270: (job_t*)callback_job_create((callback_job_cb_t)update_bypass, this,
271: NULL, (callback_job_cancel_t)return_false));
272: }
273:
274: METHOD(bypass_lan_listener_t, destroy, void,
275: private_bypass_lan_listener_t *this)
276: {
277: enumerator_t *enumerator;
278: bypass_policy_t *policy;
279:
280: enumerator = this->policies->create_enumerator(this->policies);
281: while (enumerator->enumerate(enumerator, NULL, &policy))
282: {
283: bypass_policy_destroy(policy);
284: }
285: enumerator->destroy(enumerator);
286: DESTROY_FUNCTION_IF(this->ifaces_filter, (void*)free);
287: this->policies->destroy(this->policies);
288: this->mutex->destroy(this->mutex);
289: free(this);
290: }
291:
292: /*
293: * See header
294: */
295: bypass_lan_listener_t *bypass_lan_listener_create()
296: {
297: private_bypass_lan_listener_t *this;
298:
299: INIT(this,
300: .public = {
301: .listener = {
302: .roam = _roam,
303: },
304: .reload_interfaces = _reload_interfaces,
305: .destroy = _destroy,
306: },
307: .policies = hashtable_create((hashtable_hash_t)policy_hash,
308: (hashtable_equals_t)policy_equals, 4),
309: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
310: );
311:
312: reload_interfaces(this);
313: return &this->public;
314: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>