2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
22 #include <sys/types.h>
24 #include <sys/socket.h>
30 #include <libxml/xmlreader.h>
31 #include <libxml/xmlwriter.h>
35 #include <processing/jobs/callback_job.h>
38 typedef struct private_smp_t private_smp_t
;
41 * Private data of an smp_t object.
43 struct private_smp_t
{
46 * Public part of smp_t object.
56 * job accepting stroke messages
61 ENUM(ike_sa_state_lower_names
, IKE_CREATED
, IKE_DELETING
,
70 * write a bool into element
72 static void write_bool(xmlTextWriterPtr writer
, char *element
, bool val
)
74 xmlTextWriterWriteElement(writer
, element
, val ?
"true" : "false");
78 * write a identification_t into element
80 static void write_id(xmlTextWriterPtr writer
, char *element
, identification_t
*id
)
82 xmlTextWriterStartElement(writer
, element
);
83 switch (id
->get_type(id
))
111 xmlTextWriterWriteAttribute(writer
, "type", type
);
112 xmlTextWriterWriteFormatString(writer
, "%D", id
);
116 /* TODO: base64 keyid */
117 xmlTextWriterWriteAttribute(writer
, "type", "keyid");
120 xmlTextWriterEndElement(writer
);
124 * write a host_t address into an element
126 static void write_address(xmlTextWriterPtr writer
, char *element
, host_t
*host
)
128 xmlTextWriterStartElement(writer
, element
);
129 xmlTextWriterWriteAttribute(writer
, "type",
130 host
->get_family(host
) == AF_INET ?
"ipv4" : "ipv6");
131 if (host
->is_anyaddr(host
))
132 { /* do not use %any for XML */
133 xmlTextWriterWriteFormatString(writer
, "%s",
134 host
->get_family(host
) == AF_INET ?
"0.0.0.0" : "::");
138 xmlTextWriterWriteFormatString(writer
, "%H", host
);
140 xmlTextWriterEndElement(writer
);
144 * write networks element
146 static void write_networks(xmlTextWriterPtr writer
, char *element
,
149 enumerator_t
*enumerator
;
150 traffic_selector_t
*ts
;
152 xmlTextWriterStartElement(writer
, element
);
153 enumerator
= list
->create_enumerator(list
);
154 while (enumerator
->enumerate(enumerator
, (void**)&ts
))
156 xmlTextWriterStartElement(writer
, "network");
157 xmlTextWriterWriteAttribute(writer
, "type",
158 ts
->get_type(ts
) == TS_IPV4_ADDR_RANGE ?
"ipv4" : "ipv6");
159 xmlTextWriterWriteFormatString(writer
, "%R", ts
);
160 xmlTextWriterEndElement(writer
);
162 enumerator
->destroy(enumerator
);
163 xmlTextWriterEndElement(writer
);
169 static void write_childend(xmlTextWriterPtr writer
, child_sa_t
*child
, bool local
)
173 xmlTextWriterWriteFormatElement(writer
, "spi", "%lx",
174 htonl(child
->get_spi(child
, local
)));
175 list
= child
->get_traffic_selectors(child
, local
);
176 write_networks(writer
, "networks", list
);
182 static void write_child(xmlTextWriterPtr writer
, child_sa_t
*child
)
185 encryption_algorithm_t encr
;
186 integrity_algorithm_t int_algo
;
187 size_t encr_len
, int_len
;
188 u_int32_t rekey
, use_in
, use_out
, use_fwd
;
191 config
= child
->get_config(child
);
192 child
->get_stats(child
, &mode
, &encr
, &encr_len
, &int_algo
, &int_len
,
193 &rekey
, &use_in
, &use_out
, &use_fwd
);
195 xmlTextWriterStartElement(writer
, "childsa");
196 xmlTextWriterWriteFormatElement(writer
, "reqid", "%d", child
->get_reqid(child
));
197 xmlTextWriterWriteFormatElement(writer
, "childconfig", "%s",
198 config
->get_name(config
));
199 xmlTextWriterStartElement(writer
, "local");
200 write_childend(writer
, child
, TRUE
);
201 xmlTextWriterEndElement(writer
);
202 xmlTextWriterStartElement(writer
, "remote");
203 write_childend(writer
, child
, FALSE
);
204 xmlTextWriterEndElement(writer
);
205 xmlTextWriterEndElement(writer
);
209 * process a ikesalist query request message
211 static void request_query_ikesa(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
213 enumerator_t
*enumerator
;
217 xmlTextWriterStartElement(writer
, "ikesalist");
219 enumerator
= charon
->controller
->create_ike_sa_enumerator(charon
->controller
);
220 while (enumerator
->enumerate(enumerator
, &ike_sa
))
223 host_t
*local
, *remote
;
224 iterator_t
*children
;
225 child_sa_t
*child_sa
;
227 id
= ike_sa
->get_id(ike_sa
);
229 xmlTextWriterStartElement(writer
, "ikesa");
230 xmlTextWriterWriteFormatElement(writer
, "id", "%d",
231 ike_sa
->get_unique_id(ike_sa
));
232 xmlTextWriterWriteFormatElement(writer
, "status", "%N",
233 ike_sa_state_lower_names
, ike_sa
->get_state(ike_sa
));
234 xmlTextWriterWriteElement(writer
, "role",
235 id
->is_initiator(id
) ?
"initiator" : "responder");
236 xmlTextWriterWriteElement(writer
, "peerconfig", ike_sa
->get_name(ike_sa
));
239 local
= ike_sa
->get_my_host(ike_sa
);
240 xmlTextWriterStartElement(writer
, "local");
241 xmlTextWriterWriteFormatElement(writer
, "spi", "%.16llx",
242 id
->is_initiator(id
) ? id
->get_initiator_spi(id
)
243 : id
->get_responder_spi(id
));
244 write_id(writer
, "identification", ike_sa
->get_my_id(ike_sa
));
245 write_address(writer
, "address", local
);
246 xmlTextWriterWriteFormatElement(writer
, "port", "%d",
247 local
->get_port(local
));
248 if (ike_sa
->supports_extension(ike_sa
, EXT_NATT
))
250 write_bool(writer
, "nat", ike_sa
->has_condition(ike_sa
, COND_NAT_HERE
));
252 xmlTextWriterEndElement(writer
);
256 remote
= ike_sa
->get_other_host(ike_sa
);
257 xmlTextWriterStartElement(writer
, "remote");
258 xmlTextWriterWriteFormatElement(writer
, "spi", "%.16llx",
259 id
->is_initiator(id
) ? id
->get_responder_spi(id
)
260 : id
->get_initiator_spi(id
));
261 write_id(writer
, "identification", ike_sa
->get_other_id(ike_sa
));
262 write_address(writer
, "address", remote
);
263 xmlTextWriterWriteFormatElement(writer
, "port", "%d",
264 remote
->get_port(remote
));
265 if (ike_sa
->supports_extension(ike_sa
, EXT_NATT
))
267 write_bool(writer
, "nat", ike_sa
->has_condition(ike_sa
, COND_NAT_THERE
));
269 xmlTextWriterEndElement(writer
);
273 xmlTextWriterStartElement(writer
, "childsalist");
274 children
= ike_sa
->create_child_sa_iterator(ike_sa
);
275 while (children
->iterate(children
, (void**)&child_sa
))
277 write_child(writer
, child_sa
);
279 children
->destroy(children
);
281 xmlTextWriterEndElement(writer
);
284 xmlTextWriterEndElement(writer
);
286 enumerator
->destroy(enumerator
);
289 xmlTextWriterEndElement(writer
);
293 * process a configlist query request message
295 static void request_query_config(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
297 enumerator_t
*enumerator
;
298 peer_cfg_t
*peer_cfg
;
301 xmlTextWriterStartElement(writer
, "configlist");
303 enumerator
= charon
->backends
->create_peer_cfg_enumerator(charon
->backends
);
304 while (enumerator
->enumerate(enumerator
, (void**)&peer_cfg
))
306 enumerator_t
*children
;
307 child_cfg_t
*child_cfg
;
311 if (peer_cfg
->get_ike_version(peer_cfg
) != 2)
312 { /* only IKEv2 connections yet */
317 xmlTextWriterStartElement(writer
, "peerconfig");
318 xmlTextWriterWriteElement(writer
, "name", peer_cfg
->get_name(peer_cfg
));
319 write_id(writer
, "local", peer_cfg
->get_my_id(peer_cfg
));
320 write_id(writer
, "remote", peer_cfg
->get_other_id(peer_cfg
));
323 ike_cfg
= peer_cfg
->get_ike_cfg(peer_cfg
);
324 xmlTextWriterStartElement(writer
, "ikeconfig");
325 write_address(writer
, "local", ike_cfg
->get_my_host(ike_cfg
));
326 write_address(writer
, "remote", ike_cfg
->get_other_host(ike_cfg
));
327 xmlTextWriterEndElement(writer
);
330 /* <childconfiglist> */
331 xmlTextWriterStartElement(writer
, "childconfiglist");
332 children
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
333 while (children
->enumerate(children
, &child_cfg
))
336 xmlTextWriterStartElement(writer
, "childconfig");
337 xmlTextWriterWriteElement(writer
, "name",
338 child_cfg
->get_name(child_cfg
));
339 list
= child_cfg
->get_traffic_selectors(child_cfg
, TRUE
, NULL
, NULL
);
340 write_networks(writer
, "local", list
);
341 list
->destroy_offset(list
, offsetof(traffic_selector_t
, destroy
));
342 list
= child_cfg
->get_traffic_selectors(child_cfg
, FALSE
, NULL
, NULL
);
343 write_networks(writer
, "remote", list
);
344 list
->destroy_offset(list
, offsetof(traffic_selector_t
, destroy
));
345 xmlTextWriterEndElement(writer
);
348 children
->destroy(children
);
349 /* </childconfiglist> */
350 xmlTextWriterEndElement(writer
);
352 xmlTextWriterEndElement(writer
);
354 enumerator
->destroy(enumerator
);
356 xmlTextWriterEndElement(writer
);
360 * callback which logs to a XML writer
362 static bool xml_callback(xmlTextWriterPtr writer
, signal_t signal
, level_t level
,
363 ike_sa_t
* ike_sa
, char* format
, va_list args
)
368 xmlTextWriterStartElement(writer
, "item");
369 xmlTextWriterWriteFormatAttribute(writer
, "level", "%d", level
);
370 xmlTextWriterWriteFormatAttribute(writer
, "source", "%N", signal_names
, signal
);
371 xmlTextWriterWriteFormatAttribute(writer
, "thread", "%u", pthread_self());
372 xmlTextWriterWriteVFormatString(writer
, format
, args
);
373 xmlTextWriterEndElement(writer
);
380 * process a *terminate control request message
382 static void request_control_terminate(xmlTextReaderPtr reader
,
383 xmlTextWriterPtr writer
, bool ike
)
385 if (xmlTextReaderRead(reader
) &&
386 xmlTextReaderNodeType(reader
) == XML_READER_TYPE_TEXT
)
392 str
= xmlTextReaderConstValue(reader
);
393 if (str
== NULL
|| !(id
= atoi(str
)))
395 DBG1(DBG_CFG
, "error parsing XML id string");
398 DBG1(DBG_CFG
, "terminating %s_SA %d", ike ?
"IKE" : "CHILD", id
);
401 xmlTextWriterStartElement(writer
, "log");
404 status
= charon
->controller
->terminate_ike(
405 charon
->controller
, id
,
406 (controller_cb_t
)xml_callback
, writer
);
410 status
= charon
->controller
->terminate_child(
411 charon
->controller
, id
,
412 (controller_cb_t
)xml_callback
, writer
);
415 xmlTextWriterEndElement(writer
);
416 xmlTextWriterWriteFormatElement(writer
, "status", "%d", status
);
421 * process a *initiate control request message
423 static void request_control_initiate(xmlTextReaderPtr reader
,
424 xmlTextWriterPtr writer
, bool ike
)
426 if (xmlTextReaderRead(reader
) &&
427 xmlTextReaderNodeType(reader
) == XML_READER_TYPE_TEXT
)
430 status_t status
= FAILED
;
432 child_cfg_t
*child
= NULL
;
433 enumerator_t
*enumerator
;
435 str
= xmlTextReaderConstValue(reader
);
438 DBG1(DBG_CFG
, "error parsing XML config name string");
441 DBG1(DBG_CFG
, "initiating %s_SA %s", ike ?
"IKE" : "CHILD", str
);
444 xmlTextWriterStartElement(writer
, "log");
445 peer
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
, (char*)str
);
448 enumerator
= peer
->create_child_cfg_enumerator(peer
);
451 if (!enumerator
->enumerate(enumerator
, &child
))
455 child
->get_ref(child
);
459 while (enumerator
->enumerate(enumerator
, &child
))
461 if (streq(child
->get_name(child
), str
))
463 child
->get_ref(child
);
469 enumerator
->destroy(enumerator
);
472 status
= charon
->controller
->initiate(charon
->controller
,
473 peer
, child
, (controller_cb_t
)xml_callback
,
482 xmlTextWriterEndElement(writer
);
483 xmlTextWriterWriteFormatElement(writer
, "status", "%d", status
);
488 * process a query request
490 static void request_query(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
493 xmlTextWriterStartElement(writer
, "query");
494 while (xmlTextReaderRead(reader
))
496 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
498 if (streq(xmlTextReaderConstName(reader
), "ikesalist"))
500 request_query_ikesa(reader
, writer
);
503 if (streq(xmlTextReaderConstName(reader
), "configlist"))
505 request_query_config(reader
, writer
);
511 xmlTextWriterEndElement(writer
);
515 * process a control request
517 static void request_control(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
520 xmlTextWriterStartElement(writer
, "control");
521 while (xmlTextReaderRead(reader
))
523 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
525 if (streq(xmlTextReaderConstName(reader
), "ikesaterminate"))
527 request_control_terminate(reader
, writer
, TRUE
);
530 if (streq(xmlTextReaderConstName(reader
), "childsaterminate"))
532 request_control_terminate(reader
, writer
, FALSE
);
535 if (streq(xmlTextReaderConstName(reader
), "ikesainitiate"))
537 request_control_initiate(reader
, writer
, TRUE
);
540 if (streq(xmlTextReaderConstName(reader
), "childsainitiate"))
542 request_control_initiate(reader
, writer
, FALSE
);
548 xmlTextWriterEndElement(writer
);
552 * process a request message
554 static void request(xmlTextReaderPtr reader
, char *id
, int fd
)
556 xmlTextWriterPtr writer
;
558 writer
= xmlNewTextWriter(xmlOutputBufferCreateFd(fd
, NULL
));
561 DBG1(DBG_CFG
, "opening SMP XML writer failed");
565 xmlTextWriterStartDocument(writer
, NULL
, NULL
, NULL
);
566 /* <message xmlns="http://www.strongswan.org/smp/1.0"
567 id="id" type="response"> */
568 xmlTextWriterStartElement(writer
, "message");
569 xmlTextWriterWriteAttribute(writer
, "xmlns",
570 "http://www.strongswan.org/smp/1.0");
571 xmlTextWriterWriteAttribute(writer
, "id", id
);
572 xmlTextWriterWriteAttribute(writer
, "type", "response");
574 while (xmlTextReaderRead(reader
))
576 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
578 if (streq(xmlTextReaderConstName(reader
), "query"))
580 request_query(reader
, writer
);
583 if (streq(xmlTextReaderConstName(reader
), "control"))
585 request_control(reader
, writer
);
590 /* </message> and close document */
591 xmlTextWriterEndDocument(writer
);
592 xmlFreeTextWriter(writer
);
596 * cleanup helper function for open file descriptors
598 static void closefdp(int *fd
)
604 * read from a opened connection and process it
606 static job_requeue_t
process(int *fdp
)
608 int oldstate
, fd
= *fdp
;
611 xmlTextReaderPtr reader
;
612 char *id
= NULL
, *type
= NULL
;
614 pthread_cleanup_push((void*)closefdp
, (void*)&fd
);
615 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
616 len
= read(fd
, buffer
, sizeof(buffer
));
617 pthread_setcancelstate(oldstate
, NULL
);
618 pthread_cleanup_pop(0);
622 DBG2(DBG_CFG
, "SMP XML connection closed");
623 return JOB_REQUEUE_NONE
;
625 DBG3(DBG_CFG
, "got XML request: %b", buffer
, len
);
627 reader
= xmlReaderForMemory(buffer
, len
, NULL
, NULL
, 0);
630 DBG1(DBG_CFG
, "opening SMP XML reader failed");
631 return JOB_REQUEUE_FAIR
;;
634 /* read message type and id */
635 while (xmlTextReaderRead(reader
))
637 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
&&
638 streq(xmlTextReaderConstName(reader
), "message"))
640 id
= xmlTextReaderGetAttribute(reader
, "id");
641 type
= xmlTextReaderGetAttribute(reader
, "type");
646 /* process message */
649 if (streq(type
, "request"))
651 request(reader
, id
, fd
);
655 /* response(reader, id) */
658 xmlFreeTextReader(reader
);
659 return JOB_REQUEUE_FAIR
;;
663 * accept from XML socket and create jobs to process connections
665 static job_requeue_t
dispatch(private_smp_t
*this)
667 struct sockaddr_un strokeaddr
;
668 int oldstate
, fd
, *fdp
, strokeaddrlen
= sizeof(strokeaddr
);
671 /* wait for connections, but allow thread to terminate */
672 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
673 fd
= accept(this->socket
, (struct sockaddr
*)&strokeaddr
, &strokeaddrlen
);
674 pthread_setcancelstate(oldstate
, NULL
);
678 DBG1(DBG_CFG
, "accepting SMP XML socket failed: %s", strerror(errno
));
680 return JOB_REQUEUE_FAIR
;;
683 fdp
= malloc_thing(int);
685 job
= callback_job_create((callback_job_cb_t
)process
, fdp
, free
, this->job
);
686 charon
->processor
->queue_job(charon
->processor
, (job_t
*)job
);
688 return JOB_REQUEUE_DIRECT
;
692 * Implementation of itnerface_t.destroy.
694 static void destroy(private_smp_t
*this)
696 this->job
->cancel(this->job
);
702 * Described in header file
704 plugin_t
*plugin_create()
706 struct sockaddr_un unix_addr
= { AF_UNIX
, IPSEC_PIDDIR
"/charon.xml"};
707 private_smp_t
*this = malloc_thing(private_smp_t
);
710 this->public.plugin
.destroy
= (void (*)(plugin_t
*))destroy
;
712 /* set up unix socket */
713 this->socket
= socket(AF_UNIX
, SOCK_STREAM
, 0);
714 if (this->socket
== -1)
716 DBG1(DBG_CFG
, "could not create XML socket");
721 unlink(unix_addr
.sun_path
);
722 old
= umask(~(S_IRWXU
| S_IRWXG
));
723 if (bind(this->socket
, (struct sockaddr
*)&unix_addr
, sizeof(unix_addr
)) < 0)
725 DBG1(DBG_CFG
, "could not bind XML socket: %s", strerror(errno
));
731 if (chown(unix_addr
.sun_path
, IPSEC_UID
, IPSEC_GID
) != 0)
733 DBG1(DBG_CFG
, "changing XML socket permissions failed: %s", strerror(errno
));
736 if (listen(this->socket
, 5) < 0)
738 DBG1(DBG_CFG
, "could not listen on XML socket: %s", strerror(errno
));
744 this->job
= callback_job_create((callback_job_cb_t
)dispatch
, this, NULL
, NULL
);
745 charon
->processor
->queue_job(charon
->processor
, (job_t
*)this->job
);
747 return &this->public.plugin
;