- comment cleanups
[strongswan.git] / Source / charon / threads / kernel_interface.c
1 /**
2 * @file kernel_interface.c
3 *
4 * @brief Implementation of kernel_interface_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <linux/netlink.h>
26 #include <linux/xfrm.h>
27 #include <pthread.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <string.h>
32
33 #include "kernel_interface.h"
34
35 #include <daemon.h>
36 #include <utils/allocator.h>
37 #include <utils/linked_list.h>
38
39
40 typedef struct netlink_message_t netlink_message_t;
41
42 /**
43 * Representation of ANY netlink message used
44 */
45 struct netlink_message_t {
46
47 /**
48 * header of the netlink message
49 */
50 struct nlmsghdr hdr;
51
52 union {
53 struct nlmsgerr e;
54 struct xfrm_userspi_info spi;
55 struct {
56 struct xfrm_usersa_info sa;
57 u_int8_t data[512];
58 };
59 };
60 };
61
62 typedef struct netlink_algo_t netlink_algo_t;
63
64 /**
65 * Add length and type to xfrm_algo
66 */
67 struct netlink_algo_t {
68 u_int16_t length;
69 u_int16_t type;
70 struct xfrm_algo algo;
71 };
72
73 typedef struct private_kernel_interface_t private_kernel_interface_t;
74
75 /**
76 * @brief Private Variables and Functions of kernel_interface class.
77 *
78 */
79 struct private_kernel_interface_t {
80 /**
81 * Public part of the kernel_interface_t object.
82 */
83 kernel_interface_t public;
84
85 /**
86 * Netlink communication socket.
87 */
88 int socket;
89
90 pid_t pid;
91 /**
92 * Sequence number for messages.
93 */
94 u_int32_t seq;
95
96 /**
97 * List of responded messages.
98 */
99 linked_list_t *responses;
100
101 /**
102 * Thread which receives messages.
103 */
104 pthread_t thread;
105
106 /**
107 * Mutex locks access to replies list.
108 */
109 pthread_mutex_t mutex;
110
111 /**
112 * Condvar allows signaling of threads waiting for a reply.
113 */
114 pthread_cond_t condvar;
115
116 /**
117 * Function for the thread, receives messages.
118 */
119 void (*receive_messages) (private_kernel_interface_t *this);
120
121 /**
122 * Sends a netlink_message_t down to the kernel and wait for reply.
123 */
124 status_t (*send_message) (private_kernel_interface_t *this, netlink_message_t *request, netlink_message_t **response);
125 };
126
127 mapping_t kernel_encryption_algs_m[] = {
128 {ENCR_DES_IV64, ""},
129 {ENCR_DES, "des"},
130 {ENCR_3DES, "3des"},
131 {ENCR_RC5, ""},
132 {ENCR_IDEA, ""},
133 {ENCR_CAST, ""},
134 {ENCR_BLOWFISH, ""},
135 {ENCR_3IDEA, ""},
136 {ENCR_DES_IV32, ""},
137 {ENCR_NULL, ""},
138 {ENCR_AES_CBC, "aes"},
139 {ENCR_AES_CTR, ""},
140 {MAPPING_END, NULL}
141 };
142
143 mapping_t kernel_integrity_algs_m[] = {
144 {AUTH_HMAC_MD5_96, "md5"},
145 {AUTH_HMAC_SHA1_96, "sha1"},
146 {AUTH_DES_MAC, ""},
147 {AUTH_KPDK_MD5, ""},
148 {AUTH_AES_XCBC_96, ""},
149 {MAPPING_END, NULL}
150 };
151
152
153 static status_t get_spi(private_kernel_interface_t *this, host_t *src, host_t *dest, protocol_id_t protocol, bool tunnel_mode, u_int32_t *spi)
154 {
155 netlink_message_t request, *response;
156
157 memset(&request, 0, sizeof(request));
158 request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.spi)));
159 request.hdr.nlmsg_flags = NLM_F_REQUEST;
160 request.hdr.nlmsg_type = XFRM_MSG_ALLOCSPI;
161 request.spi.info.saddr = src->get_xfrm_addr(src);
162 request.spi.info.id.daddr = dest->get_xfrm_addr(dest);
163 request.spi.info.mode = tunnel_mode;
164 request.spi.info.id.proto = protocol;
165 request.spi.info.family = PF_INET;
166 request.spi.min = 100;
167 request.spi.max = 200;
168
169 if (this->send_message(this, &request, &response) != SUCCESS)
170 {
171 return FAILED;
172 }
173
174 if (response->hdr.nlmsg_type == NLMSG_ERROR)
175 {
176 return FAILED;
177 }
178
179 if (response->hdr.nlmsg_type != XFRM_MSG_NEWSA)
180 {
181 return FAILED;
182 }
183 else if (response->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(response->sa)))
184 {
185 return FAILED;
186 }
187
188 *spi = response->sa.id.spi;
189 allocator_free(response);
190
191 return SUCCESS;
192 }
193
194 static status_t add_sa( private_kernel_interface_t *this,
195 host_t *me,
196 host_t *other,
197 u_int32_t spi,
198 int protocol,
199 bool tunnel_mode,
200 encryption_algorithm_t enc_alg,
201 size_t enc_size,
202 chunk_t enc_key,
203 integrity_algorithm_t int_alg,
204 size_t int_size,
205 chunk_t int_key,
206 bool replace)
207 {
208 netlink_message_t request, *response;
209
210 memset(&request, 0, sizeof(request));
211
212 request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
213 request.hdr.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA;
214
215 request.sa.saddr = me->get_xfrm_addr(me);
216 request.sa.id.daddr = other->get_xfrm_addr(other);
217
218 request.sa.id.spi = spi;
219 request.sa.id.proto = protocol;
220 request.sa.family = me->get_family(me);
221 request.sa.mode = tunnel_mode;
222 request.sa.replay_window = 0; //sa->replay_window; ???
223 request.sa.reqid = 0; //sa->reqid; ???
224 request.sa.lft.soft_byte_limit = XFRM_INF;
225 request.sa.lft.soft_packet_limit = XFRM_INF;
226 request.sa.lft.hard_byte_limit = XFRM_INF;
227 request.sa.lft.hard_packet_limit = XFRM_INF;
228
229 request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.sa)));
230
231 if (enc_alg != ENCR_UNDEFINED)
232 {
233 netlink_algo_t *nla = (netlink_algo_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len);
234
235 nla->type = XFRMA_ALG_CRYPT;
236 nla->length = sizeof(netlink_algo_t) + enc_size;
237 nla->algo.alg_key_len = enc_size * 8;
238
239 strcpy(nla->algo.alg_name, mapping_find(kernel_encryption_algs_m, enc_alg));
240 memcpy(nla->algo.alg_key, enc_key.ptr, enc_key.len);
241
242 request.hdr.nlmsg_len += nla->length;
243 }
244
245 if (int_alg != AUTH_UNDEFINED)
246 {
247 netlink_algo_t *nla = (netlink_algo_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len);
248
249 nla->type = XFRMA_ALG_AUTH;
250 nla->length = sizeof(netlink_algo_t) + int_size;
251 nla->algo.alg_key_len = int_size * 8;
252 strcpy(nla->algo.alg_name, mapping_find(kernel_integrity_algs_m, int_alg));
253 memcpy(nla->algo.alg_key, int_key.ptr, int_key.len);
254
255 request.hdr.nlmsg_len += nla->length;
256 }
257
258 /* add IPComp */
259
260 if (this->send_message(this, &request, &response) != SUCCESS)
261 {
262 allocator_free(response);
263 return FAILED;
264 }
265
266 allocator_free(response);
267 return SUCCESS;
268 }
269
270
271 static status_t send_message(private_kernel_interface_t *this, netlink_message_t *request, netlink_message_t **response)
272 {
273 size_t length;
274 struct sockaddr_nl addr;
275
276 request->hdr.nlmsg_seq = ++this->seq;
277 request->hdr.nlmsg_pid = this->pid;
278
279 memset(&addr, 0, sizeof(struct sockaddr_nl));
280 addr.nl_family = AF_NETLINK;
281 addr.nl_pid = 0;
282 addr.nl_groups = 0;
283
284 length = sendto(this->socket,(void *)request, request->hdr.nlmsg_len, 0, (struct sockaddr *)&addr, sizeof(addr));
285
286 if (length < 0)
287 {
288 return FAILED;
289 }
290 else if (length != request->hdr.nlmsg_len)
291 {
292 return FAILED;
293 }
294
295 pthread_mutex_lock(&(this->mutex));
296
297 while (TRUE)
298 {
299 iterator_t *iterator;
300 bool found = FALSE;
301 /* search list, break if found */
302 iterator = this->responses->create_iterator(this->responses, TRUE);
303 while (iterator->has_next(iterator))
304 {
305 netlink_message_t *listed_response;
306 iterator->current(iterator, (void**)&listed_response);
307 if (listed_response->hdr.nlmsg_seq == request->hdr.nlmsg_seq)
308 {
309 /* matches our request, this is the reply */
310 *response = listed_response;
311 found = TRUE;
312 break;
313 }
314 }
315 iterator->destroy(iterator);
316
317 if (found)
318 {
319 break;
320 }
321 /* we should time out, if something goes wrong */
322 pthread_cond_wait(&(this->condvar), &(this->mutex));
323 }
324
325 pthread_mutex_unlock(&(this->mutex));
326
327 return SUCCESS;
328 }
329
330
331 static void receive_messages(private_kernel_interface_t *this)
332 {
333 while(TRUE)
334 {
335 netlink_message_t response, *listed_response;
336 while (TRUE)
337 {
338 struct sockaddr_nl addr;
339 socklen_t addr_length;
340 size_t length;
341
342 addr_length = sizeof(addr);
343
344 response.hdr.nlmsg_type = XFRM_MSG_NEWSA;
345 length = recvfrom(this->socket, &response, sizeof(response), 0, (struct sockaddr*)&addr, &addr_length);
346 if (length < 0)
347 {
348 if (errno == EINTR)
349 {
350 /* interrupted, try again */
351 continue;
352 }
353 charon->kill(charon, "receiving from netlink socket failed");
354 }
355 if (!NLMSG_OK(&response.hdr, length))
356 {
357 /* bad netlink message */
358 continue;
359 }
360 if (addr.nl_pid != 0)
361 {
362 /* not from kernel. not interested, try another one */
363 continue;
364 }
365 break;
366 }
367
368 /* got a valid message.
369 * requests are handled on our own,
370 * responses are listed for the requesters
371 */
372 if (response.hdr.nlmsg_flags & NLM_F_REQUEST)
373 {
374 /* handle request */
375 }
376 else
377 {
378 /* add response to queue */
379 listed_response = allocator_alloc(sizeof(response));
380 memcpy(listed_response, &response, sizeof(response));
381
382 pthread_mutex_lock(&(this->mutex));
383 this->responses->insert_last(this->responses, (void*)listed_response);
384 pthread_mutex_unlock(&(this->mutex));
385 /* signal ALL waiting threads */
386 pthread_cond_broadcast(&(this->condvar));
387 }
388 /* get the next one */
389 }
390 }
391
392
393
394 /**
395 * Implementation of kernel_interface_t.destroy.
396 */
397 static void destroy(private_kernel_interface_t *this)
398 {
399 pthread_cancel(this->thread);
400 pthread_join(this->thread, NULL);
401 close(this->socket);
402 this->responses->destroy(this->responses);
403 allocator_free(this);
404 }
405
406 /*
407 * Described in header.
408 */
409 kernel_interface_t *kernel_interface_create()
410 {
411 private_kernel_interface_t *this = allocator_alloc_thing(private_kernel_interface_t);
412
413 /* public functions */
414 this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,bool,u_int32_t*))get_spi;
415
416 this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,int,bool,encryption_algorithm_t,size_t,chunk_t,integrity_algorithm_t,size_t,chunk_t,bool))add_sa;
417
418
419 this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
420
421 /* private members */
422 this->receive_messages = receive_messages;
423 this->send_message = send_message;
424 this->pid = getpid();
425 this->responses = linked_list_create();
426 pthread_mutex_init(&(this->mutex),NULL);
427 pthread_cond_init(&(this->condvar),NULL);
428 this->seq = 0;
429 this->socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_XFRM);
430 if (this->socket <= 0)
431 {
432 allocator_free(this);
433 charon->kill(charon, "Unable to create netlink socket");
434 }
435
436 if (pthread_create(&(this->thread), NULL, (void*(*)(void*))this->receive_messages, this) != 0)
437 {
438 close(this->socket);
439 allocator_free(this);
440 charon->kill(charon, "Unable to create netlink thread");
441 }
442
443 charon->logger_manager->enable_logger_level(charon->logger_manager, TESTER, FULL);
444 return (&this->public);
445 }