2 * @file kernel_interface.c
4 * @brief Implementation of kernel_interface_t.
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 * Copyright (C) 2003 Herbert Xu.
13 * Contains modified parts from pluto.
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 2 of the License, or (at your
18 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <linux/netlink.h>
35 #include "kernel_interface.h"
38 #include <utils/linked_list.h>
44 #define SPD_PRIORITY 1024
46 #define XFRM_DATA_LENGTH 512
49 typedef struct xfrm_data_t xfrm_data_t
;
52 * Lenght/Type/data struct for userdata in xfrm
53 * We dont use the "I-don't-know-where-they-come-from"-structs
68 * and the data itself, for different purposes
72 struct xfrm_algo algo
;
74 struct xfrm_user_tmpl tmpl
[2];
79 typedef struct netlink_message_t netlink_message_t
;
82 * Representation of ANY netlink message used
84 struct netlink_message_t
{
87 * header of the netlink message
94 /** message for spi allocation */
95 struct xfrm_userspi_info spi
;
96 /** message for SA manipulation */
97 struct xfrm_usersa_id sa_id
;
98 /** message for SA installation */
99 struct xfrm_usersa_info sa
;
100 /** message for policy manipulation */
101 struct xfrm_userpolicy_id policy_id
;
102 /** message for policy installation */
103 struct xfrm_userpolicy_info policy
;
105 u_int8_t data
[XFRM_DATA_LENGTH
];
109 typedef struct private_kernel_interface_t private_kernel_interface_t
;
112 * @brief Private Variables and Functions of kernel_interface class.
115 struct private_kernel_interface_t
{
117 * Public part of the kernel_interface_t object.
119 kernel_interface_t
public;
122 * Netlink communication socket.
127 * Process id of kernel thread
132 * Sequence number for messages.
137 * List of responded messages.
139 linked_list_t
*responses
;
142 * Thread which receives messages.
147 * Mutex locks access to replies list.
149 pthread_mutex_t mutex
;
152 * Condvar allows signaling of threads waiting for a reply.
154 pthread_cond_t condvar
;
157 * Logger for XFRM stuff
162 * Function for the thread, receives messages.
164 void (*receive_messages
) (private_kernel_interface_t
*this);
167 * Sends a netlink_message_t down to the kernel and wait for reply.
169 status_t (*send_message
) (private_kernel_interface_t
*this, netlink_message_t
*request
, netlink_message_t
**response
);
173 * In the kernel, algorithms are identified as strings, we use our
174 * mapping functions...
175 * Algorithms for encryption.
176 * TODO: Add missing algorithm strings
178 mapping_t kernel_encryption_algs_m
[] = {
181 {ENCR_3DES
, "des3_ede"},
184 {ENCR_CAST
, "cast128"},
185 {ENCR_BLOWFISH
, "blowfish"},
189 {ENCR_AES_CBC
, "aes"},
194 * In the kernel, algorithms are identified as strings, we use our
195 * mapping functions...
196 * Algorithms for integrity protection.
197 * TODO: Add missing algorithm strings
199 mapping_t kernel_integrity_algs_m
[] = {
200 {AUTH_HMAC_MD5_96
, "md5"},
201 {AUTH_HMAC_SHA1_96
, "sha1"},
204 {AUTH_AES_XCBC_96
, ""},
210 * Implementation of kernel_interface_t.get_spi.
212 static status_t
get_spi(private_kernel_interface_t
*this,
213 host_t
*src
, host_t
*dest
,
214 protocol_id_t protocol
, u_int32_t reqid
,
217 netlink_message_t request
, *response
;
218 status_t status
= SUCCESS
;
221 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "getting spi");
223 memset(&request
, 0, sizeof(request
));
224 request
.hdr
.nlmsg_len
= NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request
.spi
)));
225 request
.hdr
.nlmsg_flags
= NLM_F_REQUEST
;
226 request
.hdr
.nlmsg_type
= XFRM_MSG_ALLOCSPI
;
227 request
.spi
.info
.saddr
= src
->get_xfrm_addr(src
);
228 request
.spi
.info
.id
.daddr
= dest
->get_xfrm_addr(dest
);
229 request
.spi
.info
.mode
= TRUE
; /* tunnel mode */
230 request
.spi
.info
.reqid
= reqid
;
231 request
.spi
.info
.id
.proto
= (protocol
== PROTO_ESP
) ? KERNEL_ESP
: KERNEL_AH
;
232 request
.spi
.info
.family
= PF_INET
;
233 request
.spi
.min
= 0xc0000000;
234 request
.spi
.max
= 0xcFFFFFFF;
236 if (this->send_message(this, &request
, &response
) != SUCCESS
)
238 this->logger
->log(this->logger
, ERROR
, "netlink communication failed");
241 else if (response
->hdr
.nlmsg_type
== NLMSG_ERROR
)
243 this->logger
->log(this->logger
, ERROR
, "netlink request XFRM_MSG_ALLOCSPI got an error: %s",
244 strerror(-response
->e
.error
));
247 else if (response
->hdr
.nlmsg_type
!= XFRM_MSG_NEWSA
)
249 this->logger
->log(this->logger
, ERROR
, "netlink request XFRM_MSG_ALLOCSPI got a unknown reply");
252 else if (response
->hdr
.nlmsg_len
< NLMSG_LENGTH(sizeof(response
->sa
)))
254 this->logger
->log(this->logger
, ERROR
, "netlink request XFRM_MSG_ALLOCSPI got an invalid reply");
259 *spi
= response
->sa
.id
.spi
;
267 * Implementation of kernel_interface_t.add_sa.
269 static status_t
add_sa( private_kernel_interface_t
*this,
275 encryption_algorithm_t enc_alg
,
276 chunk_t encryption_key
,
277 integrity_algorithm_t int_alg
,
278 chunk_t integrity_key
,
281 netlink_message_t request
, *response
;
282 memset(&request
, 0, sizeof(request
));
283 status_t status
= SUCCESS
;
285 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "adding SA");
287 request
.hdr
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
288 request
.hdr
.nlmsg_type
= replace
? XFRM_MSG_UPDSA
: XFRM_MSG_NEWSA
;
290 request
.sa
.saddr
= me
->get_xfrm_addr(me
);
291 request
.sa
.id
.daddr
= other
->get_xfrm_addr(other
);
293 request
.sa
.id
.spi
= spi
;
294 request
.sa
.id
.proto
= (protocol
== PROTO_ESP
) ? KERNEL_ESP
: KERNEL_AH
;
295 request
.sa
.family
= me
->get_family(me
);
296 request
.sa
.mode
= TRUE
; /* tunnel mode */
297 request
.sa
.replay_window
= 32;
298 request
.sa
.reqid
= reqid
;
299 request
.sa
.lft
.soft_byte_limit
= XFRM_INF
;
300 request
.sa
.lft
.soft_packet_limit
= XFRM_INF
;
301 request
.sa
.lft
.hard_byte_limit
= XFRM_INF
;
302 request
.sa
.lft
.hard_packet_limit
= XFRM_INF
;
304 request
.hdr
.nlmsg_len
= NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request
.sa
)));
306 if (enc_alg
!= ENCR_UNDEFINED
)
308 xfrm_data_t
*data
= (xfrm_data_t
*)(((u_int8_t
*)&request
) + request
.hdr
.nlmsg_len
);
310 data
->type
= XFRMA_ALG_CRYPT
;
311 data
->length
= 4 + sizeof(data
->algo
) + encryption_key
.len
;
312 data
->algo
.alg_key_len
= encryption_key
.len
* 8;
313 request
.hdr
.nlmsg_len
+= data
->length
;
314 if (request
.hdr
.nlmsg_len
> sizeof(request
))
318 strcpy(data
->algo
.alg_name
, mapping_find(kernel_encryption_algs_m
, enc_alg
));
319 memcpy(data
->algo
.alg_key
, encryption_key
.ptr
, encryption_key
.len
);
322 if (int_alg
!= AUTH_UNDEFINED
)
324 xfrm_data_t
*data
= (xfrm_data_t
*)(((u_int8_t
*)&request
) + request
.hdr
.nlmsg_len
);
326 data
->type
= XFRMA_ALG_AUTH
;
327 data
->length
= 4 + sizeof(data
->algo
) + integrity_key
.len
;
328 data
->algo
.alg_key_len
= integrity_key
.len
* 8;
329 request
.hdr
.nlmsg_len
+= data
->length
;
330 if (request
.hdr
.nlmsg_len
> sizeof(request
))
334 strcpy(data
->algo
.alg_name
, mapping_find(kernel_integrity_algs_m
, int_alg
));
335 memcpy(data
->algo
.alg_key
, integrity_key
.ptr
, integrity_key
.len
);
338 /* TODO: add IPComp here*/
340 if (this->send_message(this, &request
, &response
) != SUCCESS
)
342 this->logger
->log(this->logger
, ERROR
, "netlink communication failed");
345 else if (response
->hdr
.nlmsg_type
!= NLMSG_ERROR
)
347 this->logger
->log(this->logger
, ERROR
, "netlink request XFRM_MSG_NEWSA not acknowledged");
350 else if (response
->e
.error
)
352 this->logger
->log(this->logger
, ERROR
, "netlink request XFRM_MSG_NEWSA got error %s",
353 strerror(-response
->e
.error
));
361 static status_t
del_sa( private_kernel_interface_t
*this,
364 protocol_id_t protocol
)
366 netlink_message_t request
, *response
;
367 memset(&request
, 0, sizeof(request
));
368 status_t status
= SUCCESS
;
370 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "deleting SA");
372 request
.hdr
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
373 request
.hdr
.nlmsg_type
= XFRM_MSG_DELSA
;
375 request
.sa_id
.daddr
= dst
->get_xfrm_addr(dst
);
377 request
.sa_id
.spi
= spi
;
378 request
.sa_id
.proto
= (protocol
== PROTO_ESP
) ? KERNEL_ESP
: KERNEL_AH
;
379 request
.sa_id
.family
= dst
->get_family(dst
);
381 request
.hdr
.nlmsg_len
= NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request
.sa_id
)));
383 if (this->send_message(this, &request
, &response
) != SUCCESS
)
387 else if (response
->hdr
.nlmsg_type
!= NLMSG_ERROR
)
391 else if (response
->e
.error
)
401 * Implementation of kernel_interface_t.add_policy.
403 static status_t
add_policy(private_kernel_interface_t
*this,
404 host_t
*me
, host_t
*other
,
405 host_t
*src
, host_t
*dst
,
406 u_int8_t src_hostbits
, u_int8_t dst_hostbits
,
407 int direction
, int upper_proto
,
411 netlink_message_t request
, *response
;
412 status_t status
= SUCCESS
;
414 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "adding policy");
416 memset(&request
, 0, sizeof(request
));
417 request
.hdr
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
419 request
.policy
.sel
.sport
= htons(src
->get_port(src
));
420 request
.policy
.sel
.dport
= htons(dst
->get_port(dst
));
421 request
.policy
.sel
.sport_mask
= (request
.policy
.sel
.sport
) ? ~0 : 0;
422 request
.policy
.sel
.dport_mask
= (request
.policy
.sel
.dport
) ? ~0 : 0;
423 request
.policy
.sel
.saddr
= src
->get_xfrm_addr(src
);
424 request
.policy
.sel
.daddr
= dst
->get_xfrm_addr(dst
);
425 request
.policy
.sel
.prefixlen_s
= src_hostbits
;
426 request
.policy
.sel
.prefixlen_d
= dst_hostbits
;
427 request
.policy
.sel
.proto
= upper_proto
;
428 request
.policy
.sel
.family
= src
->get_family(src
);
430 request
.hdr
.nlmsg_type
= XFRM_MSG_NEWPOLICY
;
431 request
.hdr
.nlmsg_len
= NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request
.policy
)));
433 request
.policy
.dir
= direction
;
434 request
.policy
.priority
= SPD_PRIORITY
;
435 request
.policy
.action
= XFRM_POLICY_ALLOW
;
436 request
.policy
.share
= XFRM_SHARE_ANY
;
438 request
.policy
.lft
.soft_byte_limit
= XFRM_INF
;
439 request
.policy
.lft
.soft_packet_limit
= XFRM_INF
;
440 request
.policy
.lft
.hard_byte_limit
= XFRM_INF
;
441 request
.policy
.lft
.hard_packet_limit
= XFRM_INF
;
447 data
= (xfrm_data_t
*)(((u_int8_t
*)&request
) + request
.hdr
.nlmsg_len
);
448 data
->type
= XFRMA_TMPL
;
451 data
->tmpl
[tmpl_pos
].reqid
= reqid
;
452 data
->tmpl
[tmpl_pos
].id
.proto
= KERNEL_ESP
;
453 data
->tmpl
[tmpl_pos
].aalgos
= data
->tmpl
[tmpl_pos
].ealgos
= data
->tmpl
[tmpl_pos
].calgos
= ~0;
454 data
->tmpl
[tmpl_pos
].mode
= TRUE
;
456 data
->tmpl
[tmpl_pos
].saddr
= me
->get_xfrm_addr(me
);
457 data
->tmpl
[tmpl_pos
].id
.daddr
= me
->get_xfrm_addr(other
);
463 data
->tmpl
[tmpl_pos
].reqid
= reqid
;
464 data
->tmpl
[tmpl_pos
].id
.proto
= KERNEL_AH
;
465 data
->tmpl
[tmpl_pos
].aalgos
= data
->tmpl
[tmpl_pos
].ealgos
= data
->tmpl
[tmpl_pos
].calgos
= ~0;
466 data
->tmpl
[tmpl_pos
].mode
= TRUE
;
468 data
->tmpl
[tmpl_pos
].saddr
= me
->get_xfrm_addr(me
);
469 data
->tmpl
[tmpl_pos
].id
.daddr
= other
->get_xfrm_addr(other
);
473 data
->length
= 4 + sizeof(struct xfrm_user_tmpl
) * tmpl_pos
;
474 request
.hdr
.nlmsg_len
+= data
->length
;
477 if (this->send_message(this, &request
, &response
) != SUCCESS
)
479 this->logger
->log(this->logger
, ERROR
, "netlink communication failed");
482 else if (response
->hdr
.nlmsg_type
!= NLMSG_ERROR
)
484 this->logger
->log(this->logger
, ERROR
, "netlink request XFRM_MSG_NEWPOLICY not acknowledged");
487 else if (response
->e
.error
)
489 this->logger
->log(this->logger
, ERROR
, "netlink request XFRM_MSG_NEWPOLICY got error %s",
490 strerror(-response
->e
.error
));
499 * Implementation of kernel_interface_t.del_policy.
501 static status_t
del_policy(private_kernel_interface_t
*this,
502 host_t
*me
, host_t
*other
,
503 host_t
*src
, host_t
*dst
,
504 u_int8_t src_hostbits
, u_int8_t dst_hostbits
,
505 int direction
, int upper_proto
)
507 netlink_message_t request
, *response
;
508 status_t status
= SUCCESS
;
511 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "deleting policy");
513 memset(&request
, 0, sizeof(request
));
514 request
.hdr
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
516 request
.policy_id
.sel
.sport
= htons(src
->get_port(src
));
517 request
.policy_id
.sel
.dport
= htons(dst
->get_port(dst
));
518 request
.policy_id
.sel
.sport_mask
= (request
.policy
.sel
.sport
) ? ~0 : 0;
519 request
.policy_id
.sel
.dport_mask
= (request
.policy
.sel
.dport
) ? ~0 : 0;
520 request
.policy_id
.sel
.saddr
= src
->get_xfrm_addr(src
);
521 request
.policy_id
.sel
.daddr
= dst
->get_xfrm_addr(dst
);
522 request
.policy_id
.sel
.prefixlen_s
= src_hostbits
;
523 request
.policy_id
.sel
.prefixlen_d
= dst_hostbits
;
524 request
.policy_id
.sel
.proto
= upper_proto
;
525 request
.policy_id
.sel
.family
= src
->get_family(src
);
527 request
.policy_id
.dir
= direction
;
529 request
.hdr
.nlmsg_type
= XFRM_MSG_DELPOLICY
;
530 request
.hdr
.nlmsg_len
= NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request
.policy_id
)));
532 if (this->send_message(this, &request
, &response
) != SUCCESS
)
536 else if (response
->hdr
.nlmsg_type
!= NLMSG_ERROR
)
540 else if (response
->e
.error
)
550 * Implementation of private_kernel_interface_t.send_message.
552 static status_t
send_message(private_kernel_interface_t
*this, netlink_message_t
*request
, netlink_message_t
**response
)
555 struct sockaddr_nl addr
;
557 request
->hdr
.nlmsg_seq
= ++this->seq
;
558 request
->hdr
.nlmsg_pid
= this->pid
;
560 memset(&addr
, 0, sizeof(struct sockaddr_nl
));
561 addr
.nl_family
= AF_NETLINK
;
565 length
= sendto(this->socket
,(void *)request
, request
->hdr
.nlmsg_len
, 0, (struct sockaddr
*)&addr
, sizeof(addr
));
571 else if (length
!= request
->hdr
.nlmsg_len
)
576 pthread_mutex_lock(&(this->mutex
));
580 iterator_t
*iterator
;
582 /* search list, break if found */
583 iterator
= this->responses
->create_iterator(this->responses
, TRUE
);
584 while (iterator
->has_next(iterator
))
586 netlink_message_t
*listed_response
;
587 iterator
->current(iterator
, (void**)&listed_response
);
588 if (listed_response
->hdr
.nlmsg_seq
== request
->hdr
.nlmsg_seq
)
590 /* matches our request, this is the reply */
591 *response
= listed_response
;
596 iterator
->destroy(iterator
);
602 /* TODO: we should time out, if something goes wrong!??? */
603 pthread_cond_wait(&(this->condvar
), &(this->mutex
));
606 pthread_mutex_unlock(&(this->mutex
));
612 * Implementation of private_kernel_interface_t.receive_messages.
614 static void receive_messages(private_kernel_interface_t
*this)
618 netlink_message_t response
, *listed_response
;
621 struct sockaddr_nl addr
;
622 socklen_t addr_length
;
625 addr_length
= sizeof(addr
);
627 response
.hdr
.nlmsg_type
= XFRM_MSG_NEWSA
;
628 length
= recvfrom(this->socket
, &response
, sizeof(response
), 0, (struct sockaddr
*)&addr
, &addr_length
);
633 /* interrupted, try again */
636 charon
->kill(charon
, "receiving from netlink socket failed");
638 if (!NLMSG_OK(&response
.hdr
, length
))
640 /* bad netlink message */
643 if (addr
.nl_pid
!= 0)
645 /* not from kernel. not interested, try another one */
651 /* got a valid message.
652 * requests are handled on our own,
653 * responses are listed for the requesters
655 if (response
.hdr
.nlmsg_flags
& NLM_F_REQUEST
)
661 /* add response to queue */
662 listed_response
= malloc(sizeof(response
));
663 memcpy(listed_response
, &response
, sizeof(response
));
665 pthread_mutex_lock(&(this->mutex
));
666 this->responses
->insert_last(this->responses
, (void*)listed_response
);
667 pthread_mutex_unlock(&(this->mutex
));
668 /* signal ALL waiting threads */
669 pthread_cond_broadcast(&(this->condvar
));
671 /* get the next one */
676 * Implementation of kernel_interface_t.destroy.
678 static void destroy(private_kernel_interface_t
*this)
680 pthread_cancel(this->thread
);
681 pthread_join(this->thread
, NULL
);
683 this->responses
->destroy(this->responses
);
688 * Described in header.
690 kernel_interface_t
*kernel_interface_create()
692 private_kernel_interface_t
*this = malloc_thing(private_kernel_interface_t
);
694 /* public functions */
695 this->public.get_spi
= (status_t(*)(kernel_interface_t
*,host_t
*,host_t
*,protocol_id_t
,u_int32_t
,u_int32_t
*))get_spi
;
696 this->public.add_sa
= (status_t(*)(kernel_interface_t
*,host_t
*,host_t
*,u_int32_t
,protocol_id_t
,u_int32_t
,encryption_algorithm_t
,chunk_t
,integrity_algorithm_t
,chunk_t
,bool))add_sa
;
697 this->public.add_policy
= (status_t(*)(kernel_interface_t
*,host_t
*, host_t
*,host_t
*,host_t
*,u_int8_t
,u_int8_t
,int,int,bool,bool,u_int32_t
))add_policy
;
698 this->public.del_sa
= (status_t(*)(kernel_interface_t
*,host_t
*,u_int32_t
,protocol_id_t
))del_sa
;
699 this->public.del_policy
= (status_t(*)(kernel_interface_t
*,host_t
*,host_t
*,host_t
*,host_t
*,u_int8_t
,u_int8_t
,int,int))del_policy
;
701 this->public.destroy
= (void(*)(kernel_interface_t
*)) destroy
;
703 /* private members */
704 this->receive_messages
= receive_messages
;
705 this->send_message
= send_message
;
706 this->pid
= getpid();
707 this->responses
= linked_list_create();
708 this->logger
= logger_manager
->get_logger(logger_manager
, XFRM
);
709 pthread_mutex_init(&(this->mutex
),NULL
);
710 pthread_cond_init(&(this->condvar
),NULL
);
712 this->socket
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_XFRM
);
713 if (this->socket
<= 0)
715 this->responses
->destroy(this->responses
);
717 charon
->kill(charon
, "Unable to create netlink socket");
720 if (pthread_create(&(this->thread
), NULL
, (void*(*)(void*))this->receive_messages
, this) != 0)
722 this->responses
->destroy(this->responses
);
725 charon
->kill(charon
, "Unable to create netlink thread");
728 return (&this->public);