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(
212 charon
->controller
, TRUE
);
213 while (enumerator
->enumerate(enumerator
, &ike_sa
))
216 host_t
*local
, *remote
;
217 enumerator_t
*children
;
218 child_sa_t
*child_sa
;
220 id
= ike_sa
->get_id(ike_sa
);
222 xmlTextWriterStartElement(writer
, "ikesa");
223 xmlTextWriterWriteFormatElement(writer
, "id", "%d",
224 ike_sa
->get_unique_id(ike_sa
));
225 xmlTextWriterWriteFormatElement(writer
, "status", "%N",
226 ike_sa_state_lower_names
, ike_sa
->get_state(ike_sa
));
227 xmlTextWriterWriteElement(writer
, "role",
228 id
->is_initiator(id
) ?
"initiator" : "responder");
229 xmlTextWriterWriteElement(writer
, "peerconfig", ike_sa
->get_name(ike_sa
));
232 local
= ike_sa
->get_my_host(ike_sa
);
233 xmlTextWriterStartElement(writer
, "local");
234 xmlTextWriterWriteFormatElement(writer
, "spi", "%.16llx",
235 id
->is_initiator(id
) ? id
->get_initiator_spi(id
)
236 : id
->get_responder_spi(id
));
237 write_id(writer
, "identification", ike_sa
->get_my_id(ike_sa
));
238 write_address(writer
, "address", local
);
239 xmlTextWriterWriteFormatElement(writer
, "port", "%d",
240 local
->get_port(local
));
241 if (ike_sa
->supports_extension(ike_sa
, EXT_NATT
))
243 write_bool(writer
, "nat", ike_sa
->has_condition(ike_sa
, COND_NAT_HERE
));
245 xmlTextWriterEndElement(writer
);
249 remote
= ike_sa
->get_other_host(ike_sa
);
250 xmlTextWriterStartElement(writer
, "remote");
251 xmlTextWriterWriteFormatElement(writer
, "spi", "%.16llx",
252 id
->is_initiator(id
) ? id
->get_responder_spi(id
)
253 : id
->get_initiator_spi(id
));
254 write_id(writer
, "identification", ike_sa
->get_other_id(ike_sa
));
255 write_address(writer
, "address", remote
);
256 xmlTextWriterWriteFormatElement(writer
, "port", "%d",
257 remote
->get_port(remote
));
258 if (ike_sa
->supports_extension(ike_sa
, EXT_NATT
))
260 write_bool(writer
, "nat", ike_sa
->has_condition(ike_sa
, COND_NAT_THERE
));
262 xmlTextWriterEndElement(writer
);
266 xmlTextWriterStartElement(writer
, "childsalist");
267 children
= ike_sa
->create_child_sa_enumerator(ike_sa
);
268 while (children
->enumerate(children
, (void**)&child_sa
))
270 write_child(writer
, child_sa
);
272 children
->destroy(children
);
274 xmlTextWriterEndElement(writer
);
277 xmlTextWriterEndElement(writer
);
279 enumerator
->destroy(enumerator
);
282 xmlTextWriterEndElement(writer
);
286 * process a configlist query request message
288 static void request_query_config(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
290 enumerator_t
*enumerator
;
291 peer_cfg_t
*peer_cfg
;
294 xmlTextWriterStartElement(writer
, "configlist");
296 enumerator
= charon
->backends
->create_peer_cfg_enumerator(charon
->backends
,
297 NULL
, NULL
, NULL
, NULL
);
298 while (enumerator
->enumerate(enumerator
, &peer_cfg
))
300 enumerator_t
*children
;
301 child_cfg_t
*child_cfg
;
305 if (peer_cfg
->get_ike_version(peer_cfg
) != 2)
306 { /* only IKEv2 connections yet */
311 xmlTextWriterStartElement(writer
, "peerconfig");
312 xmlTextWriterWriteElement(writer
, "name", peer_cfg
->get_name(peer_cfg
));
314 /* TODO: write auth_cfgs */
317 ike_cfg
= peer_cfg
->get_ike_cfg(peer_cfg
);
318 xmlTextWriterStartElement(writer
, "ikeconfig");
319 xmlTextWriterWriteElement(writer
, "local", ike_cfg
->get_my_addr(ike_cfg
));
320 xmlTextWriterWriteElement(writer
, "remote", ike_cfg
->get_other_addr(ike_cfg
));
321 xmlTextWriterEndElement(writer
);
324 /* <childconfiglist> */
325 xmlTextWriterStartElement(writer
, "childconfiglist");
326 children
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
327 while (children
->enumerate(children
, &child_cfg
))
330 xmlTextWriterStartElement(writer
, "childconfig");
331 xmlTextWriterWriteElement(writer
, "name",
332 child_cfg
->get_name(child_cfg
));
333 list
= child_cfg
->get_traffic_selectors(child_cfg
, TRUE
, NULL
, NULL
);
334 write_networks(writer
, "local", list
);
335 list
->destroy_offset(list
, offsetof(traffic_selector_t
, destroy
));
336 list
= child_cfg
->get_traffic_selectors(child_cfg
, FALSE
, NULL
, NULL
);
337 write_networks(writer
, "remote", list
);
338 list
->destroy_offset(list
, offsetof(traffic_selector_t
, destroy
));
339 xmlTextWriterEndElement(writer
);
342 children
->destroy(children
);
343 /* </childconfiglist> */
344 xmlTextWriterEndElement(writer
);
346 xmlTextWriterEndElement(writer
);
348 enumerator
->destroy(enumerator
);
350 xmlTextWriterEndElement(writer
);
354 * callback which logs to a XML writer
356 static bool xml_callback(xmlTextWriterPtr writer
, debug_t group
, level_t level
,
357 ike_sa_t
* ike_sa
, char* format
, va_list args
)
362 xmlTextWriterStartElement(writer
, "item");
363 xmlTextWriterWriteFormatAttribute(writer
, "level", "%d", level
);
364 xmlTextWriterWriteFormatAttribute(writer
, "source", "%N", debug_names
, group
);
365 xmlTextWriterWriteFormatAttribute(writer
, "thread", "%u", thread_current_id());
366 xmlTextWriterWriteVFormatString(writer
, format
, args
);
367 xmlTextWriterEndElement(writer
);
374 * process a *terminate control request message
376 static void request_control_terminate(xmlTextReaderPtr reader
,
377 xmlTextWriterPtr writer
, bool ike
)
379 if (xmlTextReaderRead(reader
) &&
380 xmlTextReaderNodeType(reader
) == XML_READER_TYPE_TEXT
)
386 str
= xmlTextReaderConstValue(reader
);
389 DBG1(DBG_CFG
, "error parsing XML id string");
395 enumerator_t
*enumerator
;
398 enumerator
= charon
->controller
->create_ike_sa_enumerator(
399 charon
->controller
, TRUE
);
400 while (enumerator
->enumerate(enumerator
, &ike_sa
))
402 if (streq(str
, ike_sa
->get_name(ike_sa
)))
405 id
= ike_sa
->get_unique_id(ike_sa
);
409 enumerator
->destroy(enumerator
);
413 DBG1(DBG_CFG
, "error parsing XML id string");
417 DBG1(DBG_CFG
, "terminating %s_SA %d", ike ?
"IKE" : "CHILD", id
);
420 xmlTextWriterStartElement(writer
, "log");
423 status
= charon
->controller
->terminate_ike(
424 charon
->controller
, id
,
425 (controller_cb_t
)xml_callback
, writer
);
429 status
= charon
->controller
->terminate_child(
430 charon
->controller
, id
,
431 (controller_cb_t
)xml_callback
, writer
);
434 xmlTextWriterEndElement(writer
);
435 xmlTextWriterWriteFormatElement(writer
, "status", "%d", status
);
440 * process a *initiate control request message
442 static void request_control_initiate(xmlTextReaderPtr reader
,
443 xmlTextWriterPtr writer
, bool ike
)
445 if (xmlTextReaderRead(reader
) &&
446 xmlTextReaderNodeType(reader
) == XML_READER_TYPE_TEXT
)
449 status_t status
= FAILED
;
451 child_cfg_t
*child
= NULL
;
452 enumerator_t
*enumerator
;
454 str
= xmlTextReaderConstValue(reader
);
457 DBG1(DBG_CFG
, "error parsing XML config name string");
460 DBG1(DBG_CFG
, "initiating %s_SA %s", ike ?
"IKE" : "CHILD", str
);
463 xmlTextWriterStartElement(writer
, "log");
464 peer
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
, (char*)str
);
467 enumerator
= peer
->create_child_cfg_enumerator(peer
);
470 if (!enumerator
->enumerate(enumerator
, &child
))
474 child
->get_ref(child
);
478 while (enumerator
->enumerate(enumerator
, &child
))
480 if (streq(child
->get_name(child
), str
))
482 child
->get_ref(child
);
488 enumerator
->destroy(enumerator
);
491 status
= charon
->controller
->initiate(charon
->controller
,
492 peer
, child
, (controller_cb_t
)xml_callback
,
501 xmlTextWriterEndElement(writer
);
502 xmlTextWriterWriteFormatElement(writer
, "status", "%d", status
);
507 * process a query request
509 static void request_query(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
512 xmlTextWriterStartElement(writer
, "query");
513 while (xmlTextReaderRead(reader
))
515 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
517 if (streq(xmlTextReaderConstName(reader
), "ikesalist"))
519 request_query_ikesa(reader
, writer
);
522 if (streq(xmlTextReaderConstName(reader
), "configlist"))
524 request_query_config(reader
, writer
);
530 xmlTextWriterEndElement(writer
);
534 * process a control request
536 static void request_control(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
539 xmlTextWriterStartElement(writer
, "control");
540 while (xmlTextReaderRead(reader
))
542 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
544 if (streq(xmlTextReaderConstName(reader
), "ikesaterminate"))
546 request_control_terminate(reader
, writer
, TRUE
);
549 if (streq(xmlTextReaderConstName(reader
), "childsaterminate"))
551 request_control_terminate(reader
, writer
, FALSE
);
554 if (streq(xmlTextReaderConstName(reader
), "ikesainitiate"))
556 request_control_initiate(reader
, writer
, TRUE
);
559 if (streq(xmlTextReaderConstName(reader
), "childsainitiate"))
561 request_control_initiate(reader
, writer
, FALSE
);
567 xmlTextWriterEndElement(writer
);
571 * process a request message
573 static void request(xmlTextReaderPtr reader
, char *id
, int fd
)
575 xmlTextWriterPtr writer
;
577 writer
= xmlNewTextWriter(xmlOutputBufferCreateFd(fd
, NULL
));
580 DBG1(DBG_CFG
, "opening SMP XML writer failed");
584 xmlTextWriterStartDocument(writer
, NULL
, NULL
, NULL
);
585 /* <message xmlns="http://www.strongswan.org/smp/1.0"
586 id="id" type="response"> */
587 xmlTextWriterStartElement(writer
, "message");
588 xmlTextWriterWriteAttribute(writer
, "xmlns",
589 "http://www.strongswan.org/smp/1.0");
590 xmlTextWriterWriteAttribute(writer
, "id", id
);
591 xmlTextWriterWriteAttribute(writer
, "type", "response");
593 while (xmlTextReaderRead(reader
))
595 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
597 if (streq(xmlTextReaderConstName(reader
), "query"))
599 request_query(reader
, writer
);
602 if (streq(xmlTextReaderConstName(reader
), "control"))
604 request_control(reader
, writer
);
609 /* </message> and close document */
610 xmlTextWriterEndDocument(writer
);
611 xmlFreeTextWriter(writer
);
615 * cleanup helper function for open file descriptors
617 static void closefdp(int *fd
)
623 * read from a opened connection and process it
625 static job_requeue_t
process(int *fdp
)
631 xmlTextReaderPtr reader
;
632 char *id
= NULL
, *type
= NULL
;
634 thread_cleanup_push((thread_cleanup_t
)closefdp
, (void*)&fd
);
635 oldstate
= thread_cancelability(TRUE
);
636 len
= read(fd
, buffer
, sizeof(buffer
));
637 thread_cancelability(oldstate
);
638 thread_cleanup_pop(FALSE
);
642 DBG2(DBG_CFG
, "SMP XML connection closed");
643 return JOB_REQUEUE_NONE
;
645 DBG3(DBG_CFG
, "got XML request: %b", buffer
, len
);
647 reader
= xmlReaderForMemory(buffer
, len
, NULL
, NULL
, 0);
650 DBG1(DBG_CFG
, "opening SMP XML reader failed");
651 return JOB_REQUEUE_FAIR
;;
654 /* read message type and id */
655 while (xmlTextReaderRead(reader
))
657 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
&&
658 streq(xmlTextReaderConstName(reader
), "message"))
660 id
= xmlTextReaderGetAttribute(reader
, "id");
661 type
= xmlTextReaderGetAttribute(reader
, "type");
666 /* process message */
669 if (streq(type
, "request"))
671 request(reader
, id
, fd
);
675 /* response(reader, id) */
678 xmlFreeTextReader(reader
);
679 return JOB_REQUEUE_FAIR
;;
683 * accept from XML socket and create jobs to process connections
685 static job_requeue_t
dispatch(private_smp_t
*this)
687 struct sockaddr_un strokeaddr
;
688 int fd
, *fdp
, strokeaddrlen
= sizeof(strokeaddr
);
692 /* wait for connections, but allow thread to terminate */
693 oldstate
= thread_cancelability(TRUE
);
694 fd
= accept(this->socket
, (struct sockaddr
*)&strokeaddr
, &strokeaddrlen
);
695 thread_cancelability(oldstate
);
699 DBG1(DBG_CFG
, "accepting SMP XML socket failed: %s", strerror(errno
));
701 return JOB_REQUEUE_FAIR
;;
704 fdp
= malloc_thing(int);
706 job
= callback_job_create((callback_job_cb_t
)process
, fdp
, free
, this->job
);
707 lib
->processor
->queue_job(lib
->processor
, (job_t
*)job
);
709 return JOB_REQUEUE_DIRECT
;
712 METHOD(plugin_t
, get_name
, char*,
718 METHOD(plugin_t
, destroy
, void,
721 this->job
->cancel(this->job
);
727 * Described in header file
729 plugin_t
*smp_plugin_create()
731 struct sockaddr_un unix_addr
= { AF_UNIX
, IPSEC_PIDDIR
"/charon.xml"};
738 .get_name
= _get_name
,
739 .reload
= (void*)return_false
,
745 /* set up unix socket */
746 this->socket
= socket(AF_UNIX
, SOCK_STREAM
, 0);
747 if (this->socket
== -1)
749 DBG1(DBG_CFG
, "could not create XML socket");
754 unlink(unix_addr
.sun_path
);
755 old
= umask(~(S_IRWXU
| S_IRWXG
));
756 if (bind(this->socket
, (struct sockaddr
*)&unix_addr
, sizeof(unix_addr
)) < 0)
758 DBG1(DBG_CFG
, "could not bind XML socket: %s", strerror(errno
));
764 if (chown(unix_addr
.sun_path
, charon
->uid
, charon
->gid
) != 0)
766 DBG1(DBG_CFG
, "changing XML socket permissions failed: %s", strerror(errno
));
769 if (listen(this->socket
, 5) < 0)
771 DBG1(DBG_CFG
, "could not listen on XML socket: %s", strerror(errno
));
777 this->job
= callback_job_create_with_prio((callback_job_cb_t
)dispatch
,
778 this, NULL
, NULL
, JOB_PRIO_CRITICAL
);
779 lib
->processor
->queue_job(lib
->processor
, (job_t
*)this->job
);
781 return &this->public.plugin
;