837e628bca7e1815697d45a6550620c0ecaa155f
[strongswan.git] / src / libcharon / kernel / kernel_interface.c
1 /*
2 * Copyright (C) 2008-2009 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2010 Martin Willi
5 * Copyright (C) 2010 revosec AG
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "kernel_interface.h"
19
20 #include <daemon.h>
21
22 typedef struct private_kernel_interface_t private_kernel_interface_t;
23
24 /**
25 * Private data of a kernel_interface_t object.
26 */
27 struct private_kernel_interface_t {
28
29 /**
30 * Public part of kernel_interface_t object.
31 */
32 kernel_interface_t public;
33
34 /**
35 * ipsec interface
36 */
37 kernel_ipsec_t *ipsec;
38
39 /**
40 * network interface
41 */
42 kernel_net_t *net;
43 };
44
45 METHOD(kernel_interface_t, get_spi, status_t,
46 private_kernel_interface_t *this, host_t *src, host_t *dst,
47 protocol_id_t protocol, u_int32_t reqid, u_int32_t *spi)
48 {
49 if (!this->ipsec)
50 {
51 return NOT_SUPPORTED;
52 }
53 return this->ipsec->get_spi(this->ipsec, src, dst, protocol, reqid, spi);
54 }
55
56 METHOD(kernel_interface_t, get_cpi, status_t,
57 private_kernel_interface_t *this, host_t *src, host_t *dst,
58 u_int32_t reqid, u_int16_t *cpi)
59 {
60 if (!this->ipsec)
61 {
62 return NOT_SUPPORTED;
63 }
64 return this->ipsec->get_cpi(this->ipsec, src, dst, reqid, cpi);
65 }
66
67 METHOD(kernel_interface_t, add_sa, status_t,
68 private_kernel_interface_t *this, host_t *src, host_t *dst,
69 u_int32_t spi, protocol_id_t protocol, u_int32_t reqid,
70 mark_t mark, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
71 u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
72 u_int16_t cpi, bool encap, bool inbound, traffic_selector_t *src_ts,
73 traffic_selector_t *dst_ts)
74 {
75 if (!this->ipsec)
76 {
77 return NOT_SUPPORTED;
78 }
79 return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid,
80 mark, lifetime, enc_alg, enc_key, int_alg, int_key, mode, ipcomp,
81 cpi, encap, inbound, src_ts, dst_ts);
82 }
83
84 METHOD(kernel_interface_t, update_sa, status_t,
85 private_kernel_interface_t *this, u_int32_t spi, protocol_id_t protocol,
86 u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
87 bool encap, bool new_encap, mark_t mark)
88 {
89 if (!this->ipsec)
90 {
91 return NOT_SUPPORTED;
92 }
93 return this->ipsec->update_sa(this->ipsec, spi, protocol, cpi, src, dst,
94 new_src, new_dst, encap, new_encap, mark);
95 }
96
97 METHOD(kernel_interface_t, query_sa, status_t,
98 private_kernel_interface_t *this, host_t *src, host_t *dst,
99 u_int32_t spi, protocol_id_t protocol, mark_t mark, u_int64_t *bytes)
100 {
101 if (!this->ipsec)
102 {
103 return NOT_SUPPORTED;
104 }
105 return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, mark, bytes);
106 }
107
108 METHOD(kernel_interface_t, del_sa, status_t,
109 private_kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi,
110 protocol_id_t protocol, u_int16_t cpi, mark_t mark)
111 {
112 if (!this->ipsec)
113 {
114 return NOT_SUPPORTED;
115 }
116 return this->ipsec->del_sa(this->ipsec, src, dst, spi, protocol, cpi, mark);
117 }
118
119 METHOD(kernel_interface_t, add_policy, status_t,
120 private_kernel_interface_t *this, host_t *src, host_t *dst,
121 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
122 policy_dir_t direction, u_int32_t spi, protocol_id_t protocol,
123 u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp,
124 u_int16_t cpi, bool routed)
125 {
126 if (!this->ipsec)
127 {
128 return NOT_SUPPORTED;
129 }
130 return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts,
131 direction, spi, protocol, reqid, mark, mode, ipcomp, cpi, routed);
132 }
133
134 METHOD(kernel_interface_t, query_policy, status_t,
135 private_kernel_interface_t *this, traffic_selector_t *src_ts,
136 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
137 u_int32_t *use_time)
138 {
139 if (!this->ipsec)
140 {
141 return NOT_SUPPORTED;
142 }
143 return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts,
144 direction, mark, use_time);
145 }
146
147 METHOD(kernel_interface_t, del_policy, status_t,
148 private_kernel_interface_t *this, traffic_selector_t *src_ts,
149 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
150 bool unrouted)
151 {
152 if (!this->ipsec)
153 {
154 return NOT_SUPPORTED;
155 }
156 return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts,
157 direction, mark, unrouted);
158 }
159
160 METHOD(kernel_interface_t, get_source_addr, host_t*,
161 private_kernel_interface_t *this, host_t *dest, host_t *src)
162 {
163 if (!this->net)
164 {
165 return NULL;
166 }
167 return this->net->get_source_addr(this->net, dest, src);
168 }
169
170 METHOD(kernel_interface_t, get_nexthop, host_t*,
171 private_kernel_interface_t *this, host_t *dest)
172 {
173 if (!this->net)
174 {
175 return NULL;
176 }
177 return this->net->get_nexthop(this->net, dest);
178 }
179
180 METHOD(kernel_interface_t, get_interface, char*,
181 private_kernel_interface_t *this, host_t *host)
182 {
183 if (!this->net)
184 {
185 return NULL;
186 }
187 return this->net->get_interface(this->net, host);
188 }
189
190 METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*,
191 private_kernel_interface_t *this, bool include_down_ifaces,
192 bool include_virtual_ips)
193 {
194 if (!this->net)
195 {
196 return enumerator_create_empty();
197 }
198 return this->net->create_address_enumerator(this->net, include_down_ifaces,
199 include_virtual_ips);
200 }
201
202 METHOD(kernel_interface_t, add_ip, status_t,
203 private_kernel_interface_t *this, host_t *virtual_ip, host_t *iface_ip)
204 {
205 if (!this->net)
206 {
207 return NOT_SUPPORTED;
208 }
209 return this->net->add_ip(this->net, virtual_ip, iface_ip);
210 }
211
212 METHOD(kernel_interface_t, del_ip, status_t,
213 private_kernel_interface_t *this, host_t *virtual_ip)
214 {
215 if (!this->net)
216 {
217 return NOT_SUPPORTED;
218 }
219 return this->net->del_ip(this->net, virtual_ip);
220 }
221
222 METHOD(kernel_interface_t, add_route, status_t,
223 private_kernel_interface_t *this, chunk_t dst_net,
224 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
225 {
226 if (!this->net)
227 {
228 return NOT_SUPPORTED;
229 }
230 return this->net->add_route(this->net, dst_net, prefixlen, gateway,
231 src_ip, if_name);
232 }
233
234 METHOD(kernel_interface_t, del_route, status_t,
235 private_kernel_interface_t *this, chunk_t dst_net,
236 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
237 {
238 if (!this->net)
239 {
240 return NOT_SUPPORTED;
241 }
242 return this->net->del_route(this->net, dst_net, prefixlen, gateway,
243 src_ip, if_name);
244 }
245
246 METHOD(kernel_interface_t, bypass_socket, bool,
247 private_kernel_interface_t *this, int fd, int family)
248 {
249 if (!this->ipsec)
250 {
251 return FALSE;
252 }
253 return this->ipsec->bypass_socket(this->ipsec, fd, family);
254 }
255
256 METHOD(kernel_interface_t, get_address_by_ts, status_t,
257 private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip)
258 {
259 enumerator_t *addrs;
260 host_t *host;
261 int family;
262 bool found = FALSE;
263
264 DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts);
265
266 /* if we have a family which includes localhost, we do not
267 * search for an IP, we use the default */
268 family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
269
270 if (family == AF_INET)
271 {
272 host = host_create_from_string("127.0.0.1", 0);
273 }
274 else
275 {
276 host = host_create_from_string("::1", 0);
277 }
278
279 if (ts->includes(ts, host))
280 {
281 *ip = host_create_any(family);
282 host->destroy(host);
283 DBG2(DBG_KNL, "using host %H", *ip);
284 return SUCCESS;
285 }
286 host->destroy(host);
287
288 addrs = create_address_enumerator(this, TRUE, TRUE);
289 while (addrs->enumerate(addrs, (void**)&host))
290 {
291 if (ts->includes(ts, host))
292 {
293 found = TRUE;
294 *ip = host->clone(host);
295 break;
296 }
297 }
298 addrs->destroy(addrs);
299
300 if (!found)
301 {
302 DBG1(DBG_KNL, "no local address found in traffic selector %R", ts);
303 return FAILED;
304 }
305
306 DBG2(DBG_KNL, "using host %H", *ip);
307 return SUCCESS;
308 }
309
310
311 METHOD(kernel_interface_t, add_ipsec_interface, void,
312 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
313 {
314 if (!this->ipsec)
315 {
316 this->ipsec = constructor();
317 }
318 }
319
320 METHOD(kernel_interface_t, remove_ipsec_interface, void,
321 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
322 {
323 /* TODO: replace if interface currently in use */
324 }
325
326 METHOD(kernel_interface_t, add_net_interface, void,
327 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
328 {
329 if (!this->net)
330 {
331 this->net = constructor();
332 }
333 }
334
335 METHOD(kernel_interface_t, remove_net_interface, void,
336 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
337 {
338 /* TODO: replace if interface currently in use */
339 }
340
341 METHOD(kernel_interface_t, destroy, void,
342 private_kernel_interface_t *this)
343 {
344 DESTROY_IF(this->ipsec);
345 DESTROY_IF(this->net);
346 free(this);
347 }
348
349 /*
350 * Described in header-file
351 */
352 kernel_interface_t *kernel_interface_create()
353 {
354 private_kernel_interface_t *this;
355
356 INIT(this,
357 .public = {
358 .get_spi = _get_spi,
359 .get_cpi = _get_cpi,
360 .add_sa = _add_sa,
361 .update_sa = _update_sa,
362 .query_sa = _query_sa,
363 .del_sa = _del_sa,
364 .add_policy = _add_policy,
365 .query_policy = _query_policy,
366 .del_policy = _del_policy,
367 .get_source_addr = _get_source_addr,
368 .get_nexthop = _get_nexthop,
369 .get_interface = _get_interface,
370 .create_address_enumerator = _create_address_enumerator,
371 .add_ip = _add_ip,
372 .del_ip = _del_ip,
373 .add_route = _add_route,
374 .del_route = _del_route,
375 .bypass_socket = _bypass_socket,
376
377 .get_address_by_ts = _get_address_by_ts,
378 .add_ipsec_interface = _add_ipsec_interface,
379 .remove_ipsec_interface = _remove_ipsec_interface,
380 .add_net_interface = _add_net_interface,
381 .remove_net_interface = _remove_net_interface,
382 .destroy = _destroy,
383 },
384 );
385
386 return &this->public;
387 }
388