kernel-libipsec: Handle packets between charon socket, libipsec and TUN device
[strongswan.git] / src / libcharon / plugins / kernel_libipsec / kernel_libipsec_plugin.c
1 /*
2 * Copyright (C) 2012-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 "kernel_libipsec_plugin.h"
17 #include "kernel_libipsec_ipsec.h"
18
19 #include <daemon.h>
20 #include <ipsec.h>
21 #include <networking/tun_device.h>
22 #include <processing/jobs/callback_job.h>
23 #include <utils/debug.h>
24
25 #define TUN_DEFAULT_MTU 1400
26
27 typedef struct private_kernel_libipsec_plugin_t private_kernel_libipsec_plugin_t;
28
29 /**
30 * private data of "kernel" libipsec plugin
31 */
32 struct private_kernel_libipsec_plugin_t {
33
34 /**
35 * implements plugin interface
36 */
37 kernel_libipsec_plugin_t public;
38
39 /**
40 * TUN device created by this plugin
41 */
42 tun_device_t *tun;
43
44 };
45
46 METHOD(plugin_t, get_name, char*,
47 private_kernel_libipsec_plugin_t *this)
48 {
49 return "kernel-libipsec";
50 }
51
52 /**
53 * Outbound callback
54 */
55 static void send_esp(void *data, esp_packet_t *packet)
56 {
57 charon->sender->send_no_marker(charon->sender, (packet_t*)packet);
58 }
59
60 /**
61 * Inbound callback
62 */
63 static void deliver_plain(private_kernel_libipsec_plugin_t *this,
64 ip_packet_t *packet)
65 {
66 this->tun->write_packet(this->tun, packet->get_encoding(packet));
67 packet->destroy(packet);
68 }
69
70 /**
71 * Receiver callback
72 */
73 static void receiver_esp_cb(void *data, packet_t *packet)
74 {
75 ipsec->processor->queue_inbound(ipsec->processor,
76 esp_packet_create_from_packet(packet));
77 }
78
79 /**
80 * Job handling outbound plaintext packets
81 */
82 static job_requeue_t handle_plain(private_kernel_libipsec_plugin_t *this)
83 {
84 chunk_t raw;
85
86 if (this->tun->read_packet(this->tun, &raw))
87 {
88 ip_packet_t *packet;
89
90 packet = ip_packet_create(raw);
91 if (packet)
92 {
93 ipsec->processor->queue_outbound(ipsec->processor, packet);
94 }
95 else
96 {
97 DBG1(DBG_KNL, "invalid IP packet read from TUN device");
98 }
99 }
100 return JOB_REQUEUE_DIRECT;
101 }
102
103 /**
104 * Initialize/deinitialize sender and receiver
105 */
106 static bool packet_handler_cb(private_kernel_libipsec_plugin_t *this,
107 plugin_feature_t *feature, bool reg, void *arg)
108 {
109 if (reg)
110 {
111 ipsec->processor->register_outbound(ipsec->processor, send_esp, NULL);
112 ipsec->processor->register_inbound(ipsec->processor,
113 (ipsec_inbound_cb_t)deliver_plain, this);
114 charon->receiver->add_esp_cb(charon->receiver,
115 (receiver_esp_cb_t)receiver_esp_cb, NULL);
116 lib->processor->queue_job(lib->processor,
117 (job_t*)callback_job_create((callback_job_cb_t)handle_plain, this,
118 NULL, (callback_job_cancel_t)return_false));
119 }
120 else
121 {
122 charon->receiver->del_esp_cb(charon->receiver,
123 (receiver_esp_cb_t)receiver_esp_cb);
124 ipsec->processor->unregister_outbound(ipsec->processor,
125 (ipsec_outbound_cb_t)send_esp);
126 ipsec->processor->unregister_inbound(ipsec->processor,
127 (ipsec_inbound_cb_t)deliver_plain);
128 }
129 return TRUE;
130 }
131
132 METHOD(plugin_t, get_features, int,
133 private_kernel_libipsec_plugin_t *this, plugin_feature_t *features[])
134 {
135 static plugin_feature_t f[] = {
136 PLUGIN_CALLBACK(kernel_ipsec_register, kernel_libipsec_ipsec_create),
137 PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
138 PLUGIN_CALLBACK((plugin_feature_callback_t)packet_handler_cb, NULL),
139 PLUGIN_PROVIDE(CUSTOM, "kernel-libipsec-handler"),
140 PLUGIN_DEPENDS(CUSTOM, "libcharon-receiver"),
141 };
142 *features = f;
143 return countof(f);
144 }
145
146 METHOD(plugin_t, destroy, void,
147 private_kernel_libipsec_plugin_t *this)
148 {
149 if (this->tun)
150 {
151 lib->set(lib, "kernel-libipsec-tun", NULL);
152 this->tun->destroy(this->tun);
153 }
154 libipsec_deinit();
155 free(this);
156 }
157
158 /*
159 * see header file
160 */
161 plugin_t *kernel_libipsec_plugin_create()
162 {
163 private_kernel_libipsec_plugin_t *this;
164
165 INIT(this,
166 .public = {
167 .plugin = {
168 .get_name = _get_name,
169 .get_features = _get_features,
170 .destroy = _destroy,
171 },
172 },
173 );
174
175 if (!libipsec_init())
176 {
177 DBG1(DBG_LIB, "initialization of libipsec failed");
178 destroy(this);
179 return NULL;
180 }
181
182 this->tun = tun_device_create("ipsec%d");
183 if (!this->tun)
184 {
185 DBG1(DBG_KNL, "failed to create TUN device");
186 destroy(this);
187 return NULL;
188 }
189 if (!this->tun->set_mtu(this->tun, TUN_DEFAULT_MTU) ||
190 !this->tun->up(this->tun))
191 {
192 DBG1(DBG_KNL, "failed to configure TUN device");
193 destroy(this);
194 return NULL;
195 }
196 lib->set(lib, "kernel-libipsec-tun", this->tun);
197
198 /* set TUN device as default to install VIPs */
199 lib->settings->set_str(lib->settings, "%s.install_virtual_ip_on",
200 this->tun->get_name(this->tun), charon->name);
201 return &this->public.plugin;
202 }