Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2013 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 <unistd.h>
17: #include <fcntl.h>
18:
19: #include "kernel_libipsec_router.h"
20:
21: #include <daemon.h>
22: #include <ipsec.h>
23: #include <collections/hashtable.h>
24: #include <networking/tun_device.h>
25: #include <threading/rwlock.h>
26: #include <threading/thread.h>
27: #include <processing/jobs/callback_job.h>
28:
29: typedef struct private_kernel_libipsec_router_t private_kernel_libipsec_router_t;
30:
31: /**
32: * Entry in the TUN device map
33: */
34: typedef struct {
35: /** virtual IP (points to internal data of tun) */
36: host_t *addr;
37: /** underlying TUN file descriptor (cached from tun) */
38: int fd;
39: /** TUN device */
40: tun_device_t *tun;
41: } tun_entry_t;
42:
43: /**
44: * Single instance of the router
45: */
46: kernel_libipsec_router_t *router;
47:
48: /**
49: * Private data
50: */
51: struct private_kernel_libipsec_router_t {
52:
53: /**
54: * Public interface
55: */
56: kernel_libipsec_router_t public;
57:
58: /**
59: * Default TUN device if kernel interface does not require separate TUN
60: * devices per VIP or for tunnels without VIP.
61: */
62: tun_entry_t tun;
63:
64: /**
65: * Hashtable that maps virtual IPs to TUN devices (tun_entry_t).
66: */
67: hashtable_t *tuns;
68:
69: /**
70: * Lock for TUN device map
71: */
72: rwlock_t *lock;
73:
74: /**
75: * Pipe to signal handle_plain() about changes regarding TUN devices
76: */
77: int notify[2];
78: };
79:
80: /**
81: * Hash function for TUN device map
82: */
83: static u_int tun_entry_hash(tun_entry_t *entry)
84: {
85: return chunk_hash(entry->addr->get_address(entry->addr));
86: }
87:
88: /**
89: * Comparison function for TUN device map
90: */
91: static bool tun_entry_equals(tun_entry_t *a, tun_entry_t *b)
92: {
93: return a->addr->ip_equals(a->addr, b->addr);
94: }
95:
96: /**
97: * Outbound callback
98: */
99: static void send_esp(void *data, esp_packet_t *packet)
100: {
101: charon->sender->send_no_marker(charon->sender, (packet_t*)packet);
102: }
103:
104: /**
105: * Receiver callback
106: */
107: static void receiver_esp_cb(void *data, packet_t *packet)
108: {
109: ipsec->processor->queue_inbound(ipsec->processor,
110: esp_packet_create_from_packet(packet));
111: }
112:
113: /**
114: * Inbound callback
115: */
116: static void deliver_plain(private_kernel_libipsec_router_t *this,
117: ip_packet_t *packet)
118: {
119: tun_device_t *tun;
120: tun_entry_t *entry, lookup = {
121: .addr = packet->get_destination(packet),
122: };
123:
124: this->lock->read_lock(this->lock);
125: entry = this->tuns->get(this->tuns, &lookup);
126: tun = entry ? entry->tun : this->tun.tun;
127: tun->write_packet(tun, packet->get_encoding(packet));
128: this->lock->unlock(this->lock);
129: packet->destroy(packet);
130: }
131:
132: /**
133: * Read and process outbound plaintext packet for the given TUN device
134: */
135: static void process_plain(tun_device_t *tun)
136: {
137: chunk_t raw;
138:
139: if (tun->read_packet(tun, &raw))
140: {
141: ip_packet_t *packet;
142:
143: packet = ip_packet_create(raw);
144: if (packet)
145: {
146: ipsec->processor->queue_outbound(ipsec->processor, packet);
147: }
148: else
149: {
150: DBG1(DBG_KNL, "invalid IP packet read from TUN device");
151: }
152: }
153: }
154:
155: /**
156: * Find flagged revents in a pollfd set by fd
157: */
158: static int find_revents(struct pollfd *pfd, int count, int fd)
159: {
160: int i;
161:
162: for (i = 0; i < count; i++)
163: {
164: if (pfd[i].fd == fd)
165: {
166: return pfd[i].revents;
167: }
168: }
169: return 0;
170: }
171:
172: /**
173: * Job handling outbound plaintext packets
174: */
175: static job_requeue_t handle_plain(private_kernel_libipsec_router_t *this)
176: {
177: enumerator_t *enumerator;
178: tun_entry_t *entry;
179: bool oldstate;
180: int count = 0;
181: char buf[1];
182: struct pollfd *pfd;
183:
184: this->lock->read_lock(this->lock);
185:
186: pfd = alloca(sizeof(*pfd) * (this->tuns->get_count(this->tuns) + 2));
187: pfd[count].fd = this->notify[0];
188: pfd[count].events = POLLIN;
189: count++;
190: pfd[count].fd = this->tun.fd;
191: pfd[count].events = POLLIN;
192: count++;
193:
194: enumerator = this->tuns->create_enumerator(this->tuns);
195: while (enumerator->enumerate(enumerator, NULL, &entry))
196: {
197: pfd[count].fd = entry->fd;
198: pfd[count].events = POLLIN;
199: count++;
200: }
201: enumerator->destroy(enumerator);
202: this->lock->unlock(this->lock);
203:
204: oldstate = thread_cancelability(TRUE);
205: if (poll(pfd, count, -1) <= 0)
206: {
207: thread_cancelability(oldstate);
208: return JOB_REQUEUE_FAIR;
209: }
210: thread_cancelability(oldstate);
211:
212: if (pfd[0].revents & POLLIN)
213: {
214: /* list of TUN devices changed, read notification data, rebuild FDs */
215: while (read(this->notify[0], &buf, sizeof(buf)) == sizeof(buf))
216: {
217: /* nop */
218: }
219: return JOB_REQUEUE_DIRECT;
220: }
221:
222: if (pfd[1].revents & POLLIN)
223: {
224: process_plain(this->tun.tun);
225: }
226:
227: this->lock->read_lock(this->lock);
228: enumerator = this->tuns->create_enumerator(this->tuns);
229: while (enumerator->enumerate(enumerator, NULL, &entry))
230: {
231: if (find_revents(pfd, count, entry->fd) & POLLIN)
232: {
233: process_plain(entry->tun);
234: }
235: }
236: enumerator->destroy(enumerator);
237: this->lock->unlock(this->lock);
238:
239: return JOB_REQUEUE_DIRECT;
240: }
241:
242: METHOD(kernel_listener_t, tun, bool,
243: private_kernel_libipsec_router_t *this, tun_device_t *tun, bool created)
244: {
245: tun_entry_t *entry, lookup;
246: char buf[] = {0x01};
247:
248: this->lock->write_lock(this->lock);
249: if (created)
250: {
251: INIT(entry,
252: .addr = tun->get_address(tun, NULL),
253: .fd = tun->get_fd(tun),
254: .tun = tun,
255: );
256: this->tuns->put(this->tuns, entry, entry);
257: }
258: else
259: {
260: lookup.addr = tun->get_address(tun, NULL);
261: entry = this->tuns->remove(this->tuns, &lookup);
262: free(entry);
263: }
264: /* notify handler thread to recreate FD set */
265: ignore_result(write(this->notify[1], buf, sizeof(buf)));
266: this->lock->unlock(this->lock);
267: return TRUE;
268: }
269:
270: METHOD(kernel_libipsec_router_t, get_tun_name, char*,
271: private_kernel_libipsec_router_t *this, host_t *vip)
272: {
273: tun_entry_t *entry, lookup = {
274: .addr = vip,
275: };
276: tun_device_t *tun;
277: char *name;
278:
279: if (!vip)
280: {
281: return strdup(this->tun.tun->get_name(this->tun.tun));
282: }
283: this->lock->read_lock(this->lock);
284: entry = this->tuns->get(this->tuns, &lookup);
285: tun = entry ? entry->tun : this->tun.tun;
286: name = strdup(tun->get_name(tun));
287: this->lock->unlock(this->lock);
288: return name;
289: }
290:
291: METHOD(kernel_libipsec_router_t, destroy, void,
292: private_kernel_libipsec_router_t *this)
293: {
294: charon->receiver->del_esp_cb(charon->receiver,
295: (receiver_esp_cb_t)receiver_esp_cb);
296: ipsec->processor->unregister_outbound(ipsec->processor,
297: (ipsec_outbound_cb_t)send_esp);
298: ipsec->processor->unregister_inbound(ipsec->processor,
299: (ipsec_inbound_cb_t)deliver_plain);
300: charon->kernel->remove_listener(charon->kernel, &this->public.listener);
301: this->lock->destroy(this->lock);
302: this->tuns->destroy(this->tuns);
303: close(this->notify[0]);
304: close(this->notify[1]);
305: router = NULL;
306: free(this);
307: }
308:
309: /**
310: * Set O_NONBLOCK on the given socket.
311: */
312: static bool set_nonblock(int socket)
313: {
314: int flags = fcntl(socket, F_GETFL);
315: return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1;
316: }
317:
318: /*
319: * See header file
320: */
321: kernel_libipsec_router_t *kernel_libipsec_router_create()
322: {
323: private_kernel_libipsec_router_t *this;
324:
325: INIT(this,
326: .public = {
327: .listener = {
328: .tun = _tun,
329: },
330: .get_tun_name = _get_tun_name,
331: .destroy = _destroy,
332: },
333: .tun = {
334: .tun = lib->get(lib, "kernel-libipsec-tun"),
335: }
336: );
337:
338: if (pipe(this->notify) != 0 ||
339: !set_nonblock(this->notify[0]) || !set_nonblock(this->notify[1]))
340: {
341: DBG1(DBG_KNL, "creating notify pipe for kernel-libipsec router failed");
342: free(this);
343: return NULL;
344: }
345:
346: this->tun.fd = this->tun.tun->get_fd(this->tun.tun);
347:
348: this->tuns = hashtable_create((hashtable_hash_t)tun_entry_hash,
349: (hashtable_equals_t)tun_entry_equals, 4);
350: this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
351:
352: charon->kernel->add_listener(charon->kernel, &this->public.listener);
353: ipsec->processor->register_outbound(ipsec->processor, send_esp, NULL);
354: ipsec->processor->register_inbound(ipsec->processor,
355: (ipsec_inbound_cb_t)deliver_plain, this);
356: charon->receiver->add_esp_cb(charon->receiver,
357: (receiver_esp_cb_t)receiver_esp_cb, NULL);
358: lib->processor->queue_job(lib->processor,
359: (job_t*)callback_job_create((callback_job_cb_t)handle_plain, this,
360: NULL, (callback_job_cancel_t)return_false));
361:
362: router = &this->public;
363: return &this->public;
364: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>