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