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
20 #include <sys/types.h>
22 #include <sys/socket.h>
27 #include <libxml/xmlreader.h>
28 #include <libxml/xmlwriter.h>
32 #include <threading/thread.h>
33 #include <processing/jobs/callback_job.h>
36 typedef struct private_smp_t private_smp_t
;
39 * Private data of an smp_t object.
41 struct private_smp_t
{
44 * Public part of smp_t object.
54 * job accepting stroke messages
59 ENUM(ike_sa_state_lower_names
, IKE_CREATED
, IKE_DELETING
,
68 * write a bool into element
70 static void write_bool(xmlTextWriterPtr writer
, char *element
, bool val
)
72 xmlTextWriterWriteElement(writer
, element
, val ?
"true" : "false");
76 * write a identification_t into element
78 static void write_id(xmlTextWriterPtr writer
, char *element
, identification_t
*id
)
80 xmlTextWriterStartElement(writer
, element
);
81 switch (id
->get_type(id
))
109 xmlTextWriterWriteAttribute(writer
, "type", type
);
110 xmlTextWriterWriteFormatString(writer
, "%Y", id
);
114 /* TODO: base64 keyid */
115 xmlTextWriterWriteAttribute(writer
, "type", "keyid");
118 xmlTextWriterEndElement(writer
);
122 * write a host_t address into an element
124 static void write_address(xmlTextWriterPtr writer
, char *element
, host_t
*host
)
126 xmlTextWriterStartElement(writer
, element
);
127 xmlTextWriterWriteAttribute(writer
, "type",
128 host
->get_family(host
) == AF_INET ?
"ipv4" : "ipv6");
129 if (host
->is_anyaddr(host
))
130 { /* do not use %any for XML */
131 xmlTextWriterWriteFormatString(writer
, "%s",
132 host
->get_family(host
) == AF_INET ?
"0.0.0.0" : "::");
136 xmlTextWriterWriteFormatString(writer
, "%H", host
);
138 xmlTextWriterEndElement(writer
);
142 * write networks element
144 static void write_networks(xmlTextWriterPtr writer
, char *element
,
147 enumerator_t
*enumerator
;
148 traffic_selector_t
*ts
;
150 xmlTextWriterStartElement(writer
, element
);
151 enumerator
= list
->create_enumerator(list
);
152 while (enumerator
->enumerate(enumerator
, (void**)&ts
))
154 xmlTextWriterStartElement(writer
, "network");
155 xmlTextWriterWriteAttribute(writer
, "type",
156 ts
->get_type(ts
) == TS_IPV4_ADDR_RANGE ?
"ipv4" : "ipv6");
157 xmlTextWriterWriteFormatString(writer
, "%R", ts
);
158 xmlTextWriterEndElement(writer
);
160 enumerator
->destroy(enumerator
);
161 xmlTextWriterEndElement(writer
);
167 static void write_childend(xmlTextWriterPtr writer
, child_sa_t
*child
, bool local
)
171 xmlTextWriterWriteFormatElement(writer
, "spi", "%lx",
172 htonl(child
->get_spi(child
, local
)));
173 list
= child
->get_traffic_selectors(child
, local
);
174 write_networks(writer
, "networks", list
);
180 static void write_child(xmlTextWriterPtr writer
, child_sa_t
*child
)
184 config
= child
->get_config(child
);
186 xmlTextWriterStartElement(writer
, "childsa");
187 xmlTextWriterWriteFormatElement(writer
, "reqid", "%d",
188 child
->get_reqid(child
));
189 xmlTextWriterWriteFormatElement(writer
, "childconfig", "%s",
190 config
->get_name(config
));
191 xmlTextWriterStartElement(writer
, "local");
192 write_childend(writer
, child
, TRUE
);
193 xmlTextWriterEndElement(writer
);
194 xmlTextWriterStartElement(writer
, "remote");
195 write_childend(writer
, child
, FALSE
);
196 xmlTextWriterEndElement(writer
);
197 xmlTextWriterEndElement(writer
);
201 * process a ikesalist query request message
203 static void request_query_ikesa(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
205 enumerator_t
*enumerator
;
209 xmlTextWriterStartElement(writer
, "ikesalist");
211 enumerator
= charon
->controller
->create_ike_sa_enumerator(charon
->controller
);
212 while (enumerator
->enumerate(enumerator
, &ike_sa
))
215 host_t
*local
, *remote
;
216 iterator_t
*children
;
217 child_sa_t
*child_sa
;
219 id
= ike_sa
->get_id(ike_sa
);
221 xmlTextWriterStartElement(writer
, "ikesa");
222 xmlTextWriterWriteFormatElement(writer
, "id", "%d",
223 ike_sa
->get_unique_id(ike_sa
));
224 xmlTextWriterWriteFormatElement(writer
, "status", "%N",
225 ike_sa_state_lower_names
, ike_sa
->get_state(ike_sa
));
226 xmlTextWriterWriteElement(writer
, "role",
227 id
->is_initiator(id
) ?
"initiator" : "responder");
228 xmlTextWriterWriteElement(writer
, "peerconfig", ike_sa
->get_name(ike_sa
));
231 local
= ike_sa
->get_my_host(ike_sa
);
232 xmlTextWriterStartElement(writer
, "local");
233 xmlTextWriterWriteFormatElement(writer
, "spi", "%.16llx",
234 id
->is_initiator(id
) ? id
->get_initiator_spi(id
)
235 : id
->get_responder_spi(id
));
236 write_id(writer
, "identification", ike_sa
->get_my_id(ike_sa
));
237 write_address(writer
, "address", local
);
238 xmlTextWriterWriteFormatElement(writer
, "port", "%d",
239 local
->get_port(local
));
240 if (ike_sa
->supports_extension(ike_sa
, EXT_NATT
))
242 write_bool(writer
, "nat", ike_sa
->has_condition(ike_sa
, COND_NAT_HERE
));
244 xmlTextWriterEndElement(writer
);
248 remote
= ike_sa
->get_other_host(ike_sa
);
249 xmlTextWriterStartElement(writer
, "remote");
250 xmlTextWriterWriteFormatElement(writer
, "spi", "%.16llx",
251 id
->is_initiator(id
) ? id
->get_responder_spi(id
)
252 : id
->get_initiator_spi(id
));
253 write_id(writer
, "identification", ike_sa
->get_other_id(ike_sa
));
254 write_address(writer
, "address", remote
);
255 xmlTextWriterWriteFormatElement(writer
, "port", "%d",
256 remote
->get_port(remote
));
257 if (ike_sa
->supports_extension(ike_sa
, EXT_NATT
))
259 write_bool(writer
, "nat", ike_sa
->has_condition(ike_sa
, COND_NAT_THERE
));
261 xmlTextWriterEndElement(writer
);
265 xmlTextWriterStartElement(writer
, "childsalist");
266 children
= ike_sa
->create_child_sa_iterator(ike_sa
);
267 while (children
->iterate(children
, (void**)&child_sa
))
269 write_child(writer
, child_sa
);
271 children
->destroy(children
);
273 xmlTextWriterEndElement(writer
);
276 xmlTextWriterEndElement(writer
);
278 enumerator
->destroy(enumerator
);
281 xmlTextWriterEndElement(writer
);
285 * process a configlist query request message
287 static void request_query_config(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
289 enumerator_t
*enumerator
;
290 peer_cfg_t
*peer_cfg
;
293 xmlTextWriterStartElement(writer
, "configlist");
295 enumerator
= charon
->backends
->create_peer_cfg_enumerator(charon
->backends
,
296 NULL
, NULL
, NULL
, NULL
);
297 while (enumerator
->enumerate(enumerator
, &peer_cfg
))
299 enumerator_t
*children
;
300 child_cfg_t
*child_cfg
;
304 if (peer_cfg
->get_ike_version(peer_cfg
) != 2)
305 { /* only IKEv2 connections yet */
310 xmlTextWriterStartElement(writer
, "peerconfig");
311 xmlTextWriterWriteElement(writer
, "name", peer_cfg
->get_name(peer_cfg
));
313 /* TODO: write auth_cfgs */
316 ike_cfg
= peer_cfg
->get_ike_cfg(peer_cfg
);
317 xmlTextWriterStartElement(writer
, "ikeconfig");
318 xmlTextWriterWriteElement(writer
, "local", ike_cfg
->get_my_addr(ike_cfg
));
319 xmlTextWriterWriteElement(writer
, "remote", ike_cfg
->get_other_addr(ike_cfg
));
320 xmlTextWriterEndElement(writer
);
323 /* <childconfiglist> */
324 xmlTextWriterStartElement(writer
, "childconfiglist");
325 children
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
326 while (children
->enumerate(children
, &child_cfg
))
329 xmlTextWriterStartElement(writer
, "childconfig");
330 xmlTextWriterWriteElement(writer
, "name",
331 child_cfg
->get_name(child_cfg
));
332 list
= child_cfg
->get_traffic_selectors(child_cfg
, TRUE
, NULL
, NULL
);
333 write_networks(writer
, "local", list
);
334 list
->destroy_offset(list
, offsetof(traffic_selector_t
, destroy
));
335 list
= child_cfg
->get_traffic_selectors(child_cfg
, FALSE
, NULL
, NULL
);
336 write_networks(writer
, "remote", list
);
337 list
->destroy_offset(list
, offsetof(traffic_selector_t
, destroy
));
338 xmlTextWriterEndElement(writer
);
341 children
->destroy(children
);
342 /* </childconfiglist> */
343 xmlTextWriterEndElement(writer
);
345 xmlTextWriterEndElement(writer
);
347 enumerator
->destroy(enumerator
);
349 xmlTextWriterEndElement(writer
);
353 * callback which logs to a XML writer
355 static bool xml_callback(xmlTextWriterPtr writer
, debug_t group
, level_t level
,
356 ike_sa_t
* ike_sa
, char* format
, va_list args
)
361 xmlTextWriterStartElement(writer
, "item");
362 xmlTextWriterWriteFormatAttribute(writer
, "level", "%d", level
);
363 xmlTextWriterWriteFormatAttribute(writer
, "source", "%N", debug_names
, group
);
364 xmlTextWriterWriteFormatAttribute(writer
, "thread", "%u", thread_current_id());
365 xmlTextWriterWriteVFormatString(writer
, format
, args
);
366 xmlTextWriterEndElement(writer
);
373 * process a *terminate control request message
375 static void request_control_terminate(xmlTextReaderPtr reader
,
376 xmlTextWriterPtr writer
, bool ike
)
378 if (xmlTextReaderRead(reader
) &&
379 xmlTextReaderNodeType(reader
) == XML_READER_TYPE_TEXT
)
385 str
= xmlTextReaderConstValue(reader
);
388 DBG1(DBG_CFG
, "error parsing XML id string");
394 enumerator_t
*enumerator
;
397 enumerator
= charon
->controller
->create_ike_sa_enumerator(charon
->controller
);
398 while (enumerator
->enumerate(enumerator
, &ike_sa
))
400 if (streq(str
, ike_sa
->get_name(ike_sa
)))
403 id
= ike_sa
->get_unique_id(ike_sa
);
407 enumerator
->destroy(enumerator
);
411 DBG1(DBG_CFG
, "error parsing XML id string");
415 DBG1(DBG_CFG
, "terminating %s_SA %d", ike ?
"IKE" : "CHILD", id
);
418 xmlTextWriterStartElement(writer
, "log");
421 status
= charon
->controller
->terminate_ike(
422 charon
->controller
, id
,
423 (controller_cb_t
)xml_callback
, writer
);
427 status
= charon
->controller
->terminate_child(
428 charon
->controller
, id
,
429 (controller_cb_t
)xml_callback
, writer
);
432 xmlTextWriterEndElement(writer
);
433 xmlTextWriterWriteFormatElement(writer
, "status", "%d", status
);
438 * process a *initiate control request message
440 static void request_control_initiate(xmlTextReaderPtr reader
,
441 xmlTextWriterPtr writer
, bool ike
)
443 if (xmlTextReaderRead(reader
) &&
444 xmlTextReaderNodeType(reader
) == XML_READER_TYPE_TEXT
)
447 status_t status
= FAILED
;
449 child_cfg_t
*child
= NULL
;
450 enumerator_t
*enumerator
;
452 str
= xmlTextReaderConstValue(reader
);
455 DBG1(DBG_CFG
, "error parsing XML config name string");
458 DBG1(DBG_CFG
, "initiating %s_SA %s", ike ?
"IKE" : "CHILD", str
);
461 xmlTextWriterStartElement(writer
, "log");
462 peer
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
, (char*)str
);
465 enumerator
= peer
->create_child_cfg_enumerator(peer
);
468 if (!enumerator
->enumerate(enumerator
, &child
))
472 child
->get_ref(child
);
476 while (enumerator
->enumerate(enumerator
, &child
))
478 if (streq(child
->get_name(child
), str
))
480 child
->get_ref(child
);
486 enumerator
->destroy(enumerator
);
489 status
= charon
->controller
->initiate(charon
->controller
,
490 peer
, child
, (controller_cb_t
)xml_callback
,
499 xmlTextWriterEndElement(writer
);
500 xmlTextWriterWriteFormatElement(writer
, "status", "%d", status
);
505 * process a query request
507 static void request_query(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
510 xmlTextWriterStartElement(writer
, "query");
511 while (xmlTextReaderRead(reader
))
513 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
515 if (streq(xmlTextReaderConstName(reader
), "ikesalist"))
517 request_query_ikesa(reader
, writer
);
520 if (streq(xmlTextReaderConstName(reader
), "configlist"))
522 request_query_config(reader
, writer
);
528 xmlTextWriterEndElement(writer
);
532 * process a control request
534 static void request_control(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
537 xmlTextWriterStartElement(writer
, "control");
538 while (xmlTextReaderRead(reader
))
540 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
542 if (streq(xmlTextReaderConstName(reader
), "ikesaterminate"))
544 request_control_terminate(reader
, writer
, TRUE
);
547 if (streq(xmlTextReaderConstName(reader
), "childsaterminate"))
549 request_control_terminate(reader
, writer
, FALSE
);
552 if (streq(xmlTextReaderConstName(reader
), "ikesainitiate"))
554 request_control_initiate(reader
, writer
, TRUE
);
557 if (streq(xmlTextReaderConstName(reader
), "childsainitiate"))
559 request_control_initiate(reader
, writer
, FALSE
);
565 xmlTextWriterEndElement(writer
);
569 * process a request message
571 static void request(xmlTextReaderPtr reader
, char *id
, int fd
)
573 xmlTextWriterPtr writer
;
575 writer
= xmlNewTextWriter(xmlOutputBufferCreateFd(fd
, NULL
));
578 DBG1(DBG_CFG
, "opening SMP XML writer failed");
582 xmlTextWriterStartDocument(writer
, NULL
, NULL
, NULL
);
583 /* <message xmlns="http://www.strongswan.org/smp/1.0"
584 id="id" type="response"> */
585 xmlTextWriterStartElement(writer
, "message");
586 xmlTextWriterWriteAttribute(writer
, "xmlns",
587 "http://www.strongswan.org/smp/1.0");
588 xmlTextWriterWriteAttribute(writer
, "id", id
);
589 xmlTextWriterWriteAttribute(writer
, "type", "response");
591 while (xmlTextReaderRead(reader
))
593 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
595 if (streq(xmlTextReaderConstName(reader
), "query"))
597 request_query(reader
, writer
);
600 if (streq(xmlTextReaderConstName(reader
), "control"))
602 request_control(reader
, writer
);
607 /* </message> and close document */
608 xmlTextWriterEndDocument(writer
);
609 xmlFreeTextWriter(writer
);
613 * cleanup helper function for open file descriptors
615 static void closefdp(int *fd
)
621 * read from a opened connection and process it
623 static job_requeue_t
process(int *fdp
)
629 xmlTextReaderPtr reader
;
630 char *id
= NULL
, *type
= NULL
;
632 thread_cleanup_push((thread_cleanup_t
)closefdp
, (void*)&fd
);
633 oldstate
= thread_cancelability(TRUE
);
634 len
= read(fd
, buffer
, sizeof(buffer
));
635 thread_cancelability(oldstate
);
636 thread_cleanup_pop(FALSE
);
640 DBG2(DBG_CFG
, "SMP XML connection closed");
641 return JOB_REQUEUE_NONE
;
643 DBG3(DBG_CFG
, "got XML request: %b", buffer
, len
);
645 reader
= xmlReaderForMemory(buffer
, len
, NULL
, NULL
, 0);
648 DBG1(DBG_CFG
, "opening SMP XML reader failed");
649 return JOB_REQUEUE_FAIR
;;
652 /* read message type and id */
653 while (xmlTextReaderRead(reader
))
655 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
&&
656 streq(xmlTextReaderConstName(reader
), "message"))
658 id
= xmlTextReaderGetAttribute(reader
, "id");
659 type
= xmlTextReaderGetAttribute(reader
, "type");
664 /* process message */
667 if (streq(type
, "request"))
669 request(reader
, id
, fd
);
673 /* response(reader, id) */
676 xmlFreeTextReader(reader
);
677 return JOB_REQUEUE_FAIR
;;
681 * accept from XML socket and create jobs to process connections
683 static job_requeue_t
dispatch(private_smp_t
*this)
685 struct sockaddr_un strokeaddr
;
686 int fd
, *fdp
, strokeaddrlen
= sizeof(strokeaddr
);
690 /* wait for connections, but allow thread to terminate */
691 oldstate
= thread_cancelability(TRUE
);
692 fd
= accept(this->socket
, (struct sockaddr
*)&strokeaddr
, &strokeaddrlen
);
693 thread_cancelability(oldstate
);
697 DBG1(DBG_CFG
, "accepting SMP XML socket failed: %s", strerror(errno
));
699 return JOB_REQUEUE_FAIR
;;
702 fdp
= malloc_thing(int);
704 job
= callback_job_create((callback_job_cb_t
)process
, fdp
, free
, this->job
);
705 lib
->processor
->queue_job(lib
->processor
, (job_t
*)job
);
707 return JOB_REQUEUE_DIRECT
;
710 METHOD(plugin_t
, get_name
, char*,
716 METHOD(plugin_t
, destroy
, void,
719 this->job
->cancel(this->job
);
725 * Described in header file
727 plugin_t
*smp_plugin_create()
729 struct sockaddr_un unix_addr
= { AF_UNIX
, IPSEC_PIDDIR
"/charon.xml"};
736 .get_name
= _get_name
,
742 /* set up unix socket */
743 this->socket
= socket(AF_UNIX
, SOCK_STREAM
, 0);
744 if (this->socket
== -1)
746 DBG1(DBG_CFG
, "could not create XML socket");
751 unlink(unix_addr
.sun_path
);
752 old
= umask(~(S_IRWXU
| S_IRWXG
));
753 if (bind(this->socket
, (struct sockaddr
*)&unix_addr
, sizeof(unix_addr
)) < 0)
755 DBG1(DBG_CFG
, "could not bind XML socket: %s", strerror(errno
));
761 if (chown(unix_addr
.sun_path
, charon
->uid
, charon
->gid
) != 0)
763 DBG1(DBG_CFG
, "changing XML socket permissions failed: %s", strerror(errno
));
766 if (listen(this->socket
, 5) < 0)
768 DBG1(DBG_CFG
, "could not listen on XML socket: %s", strerror(errno
));
774 this->job
= callback_job_create((callback_job_cb_t
)dispatch
, this, NULL
, NULL
);
775 lib
->processor
->queue_job(lib
->processor
, (job_t
*)this->job
);
777 return &this->public.plugin
;