X-Git-Url: https://git.strongswan.org/?p=strongswan.git;a=blobdiff_plain;f=src%2Fcharon%2Fcontrol%2Finterfaces%2Fxml_interface.c;h=7710ae19cf356f61e991b675524382ad083e339e;hp=8dd614493f0f38c46d674b1c37042350fc5f6a69;hb=6baca3b2f1d0863d0caf4c7dc63530907193267b;hpb=9fe1a1ca7617bb562750864aae1892ece1a6a1e6 diff --git a/src/charon/control/interfaces/xml_interface.c b/src/charon/control/interfaces/xml_interface.c index 8dd6144..7710ae1 100644 --- a/src/charon/control/interfaces/xml_interface.c +++ b/src/charon/control/interfaces/xml_interface.c @@ -37,9 +37,7 @@ #include #include - - -static struct sockaddr_un socket_addr = { AF_UNIX, "/var/run/charon.xml"}; +#include typedef struct private_xml_interface_t private_xml_interface_t; @@ -60,164 +58,344 @@ struct private_xml_interface_t { int socket; /** - * thread receiving messages + * job accepting stroke messages */ - pthread_t thread; + callback_job_t *job; }; -static void get(private_xml_interface_t *this, - xmlTextReaderPtr reader, xmlTextWriterPtr writer) +ENUM(ike_sa_state_lower_names, IKE_CREATED, IKE_DELETING, + "created", + "connecting", + "established", + "rekeying", + "deleting", +); + +/** + * write a bool into element + */ +static void write_bool(xmlTextWriterPtr writer, char *element, bool val) { + xmlTextWriterWriteElement(writer, element, val ? "true" : "false"); +} - if (/* */ - xmlTextWriterStartElement(writer, "GetResponse") < 0 || - /* */ - xmlTextWriterStartElement(writer, "Status") < 0 || - xmlTextWriterWriteAttribute(writer, "Code", "200") < 0 || - xmlTextWriterStartElement(writer, "Message") < 0 || - xmlTextWriterEndElement(writer) < 0 || - xmlTextWriterEndElement(writer) < 0 || - /* */ - xmlTextWriterStartElement(writer, "ConnectionList") < 0 || - xmlTextWriterEndElement(writer) < 0 || - /* */ - xmlTextWriterEndElement(writer) < 0) +/** + * write a identification_t into element + */ +static void write_id(xmlTextWriterPtr writer, char *element, identification_t *id) +{ + xmlTextWriterStartElement(writer, element); + switch (id->get_type(id)) { - DBG1(DBG_CFG, "error writing XML document (GetResponse)"); + { + char *type = ""; + while (TRUE) + { + case ID_IPV4_ADDR: + type = "ipv4"; + break; + case ID_IPV6_ADDR: + type = "ipv6"; + break; + case ID_FQDN: + type = "fqdn"; + break; + case ID_RFC822_ADDR: + type = "email"; + break; + case ID_DER_ASN1_DN: + type = "asn1dn"; + break; + case ID_DER_ASN1_GN: + type = "asn1gn"; + break; + } + xmlTextWriterWriteAttribute(writer, "type", type); + xmlTextWriterWriteFormatString(writer, "%D", id); + break; + } + case ID_ANY: + xmlTextWriterWriteAttribute(writer, "type", "any"); + break; + default: + /* TODO: base64 keyid */ + xmlTextWriterWriteAttribute(writer, "type", "keyid"); + break; } - + xmlTextWriterEndElement(writer); +} -/* - DBG1(DBG_CFG, "%d %d %s %d %d %s", - xmlTextReaderDepth(reader), - , - xmlTextReaderConstName(reader), - xmlTextReaderIsEmptyElement(reader), - xmlTextReaderHasValue(reader), - xmlTextReaderConstValue(reader)); - */ +/** + * write a host_t address into an element + */ +static void write_address(xmlTextWriterPtr writer, char *element, host_t *host) +{ + xmlTextWriterStartElement(writer, element); + xmlTextWriterWriteAttribute(writer, "type", + host->get_family(host) == AF_INET ? "ipv4" : "ipv6"); + if (host->is_anyaddr(host)) + { /* do not use %any for XML */ + xmlTextWriterWriteFormatString(writer, "%s", + host->get_family(host) == AF_INET ? "0.0.0.0" : "::"); + } + else + { + xmlTextWriterWriteFormatString(writer, "%H", host); + } + xmlTextWriterEndElement(writer); } -static void receive(private_xml_interface_t *this) +/** + * process a ikesalist query request message + */ +static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer) { - charon->drop_capabilities(charon, TRUE); - - /* disable cancellation by default */ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + iterator_t *iterator; + ike_sa_t *ike_sa; + + /* */ + xmlTextWriterStartElement(writer, "ikesalist"); - while (TRUE) + iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager); + while (iterator->iterate(iterator, (void**)&ike_sa)) { - struct sockaddr_un strokeaddr; - int strokeaddrlen = sizeof(strokeaddr); - int oldstate; - int fd; - char buffer[4096]; - size_t len; + ike_sa_id_t *id; + host_t *local, *remote; + iterator_t *children; + child_sa_t *child_sa; + + id = ike_sa->get_id(ike_sa); - /* wait for connections, but allow thread to terminate */ - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); - pthread_setcancelstate(oldstate, NULL); + xmlTextWriterStartElement(writer, "ikesa"); + xmlTextWriterWriteFormatElement(writer, "id", "%d", + ike_sa->get_unique_id(ike_sa)); + xmlTextWriterWriteFormatElement(writer, "status", "%N", + ike_sa_state_lower_names, ike_sa->get_state(ike_sa)); + xmlTextWriterWriteElement(writer, "role", + id->is_initiator(id) ? "initiator" : "responder"); + xmlTextWriterWriteElement(writer, "peerconfig", ike_sa->get_name(ike_sa)); - if (fd < 0) + /* */ + local = ike_sa->get_my_host(ike_sa); + xmlTextWriterStartElement(writer, "local"); + xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx", + id->is_initiator(id) ? id->get_initiator_spi(id) + : id->get_responder_spi(id)); + write_id(writer, "identification", ike_sa->get_my_id(ike_sa)); + write_address(writer, "address", local); + xmlTextWriterWriteFormatElement(writer, "port", "%d", + local->get_port(local)); + if (ike_sa->supports_extension(ike_sa, EXT_NATT)) { - DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno)); - continue; + write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_HERE)); } - DBG2(DBG_CFG, "SMP XML connection opened"); - while (TRUE) + xmlTextWriterEndElement(writer); + /* */ + + /* */ + remote = ike_sa->get_other_host(ike_sa); + xmlTextWriterStartElement(writer, "remote"); + xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx", + id->is_initiator(id) ? id->get_responder_spi(id) + : id->get_initiator_spi(id)); + write_id(writer, "identification", ike_sa->get_other_id(ike_sa)); + write_address(writer, "address", remote); + xmlTextWriterWriteFormatElement(writer, "port", "%d", + remote->get_port(remote)); + if (ike_sa->supports_extension(ike_sa, EXT_NATT)) { - xmlTextReaderPtr reader; - xmlTextWriterPtr writer; - - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - len = read(fd, buffer, sizeof(buffer)); - pthread_setcancelstate(oldstate, NULL); - if (len <= 0) + write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_THERE)); + } + xmlTextWriterEndElement(writer); + /* */ + + /* */ + xmlTextWriterStartElement(writer, "childsalist"); + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + /* TODO: Children */ + } + children->destroy(children); + /* */ + xmlTextWriterEndElement(writer); + + /* */ + xmlTextWriterEndElement(writer); + } + iterator->destroy(iterator); + + /* */ + xmlTextWriterEndElement(writer); +} + +/** + * process a query request + */ +static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + /* */ + xmlTextWriterStartElement(writer, "query"); + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "ikesalist")) { - close(fd); - DBG2(DBG_CFG, "SMP XML connection closed"); + request_query_ikesa(reader, writer); break; } - - reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0); - if (reader == NULL) - { - DBG1(DBG_CFG, "opening SMP XML reader failed"); - continue; - } - - writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL)); - if (writer == NULL) - { - xmlFreeTextReader(reader); - DBG1(DBG_CFG, "opening SMP XML writer failed"); - continue; - } - - /* create the standard message parts */ - if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) < 0 || - /* */ - xmlTextWriterStartElement(writer, "SMPMessage") < 0 || - xmlTextWriterWriteAttribute(writer, "xmlns", - "http://www.strongswan.org/smp/1.0") < 0 || - /* */ - xmlTextWriterStartElement(writer, "Body") < 0) + } + } + /* */ + xmlTextWriterEndElement(writer); +} + +/** + * process a request message + */ +static void request(xmlTextReaderPtr reader, char *id, int fd) +{ + xmlTextWriterPtr writer; + + writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL)); + if (writer == NULL) + { + DBG1(DBG_CFG, "opening SMP XML writer failed"); + return; + } + + xmlTextWriterStartDocument(writer, NULL, NULL, NULL); + /* */ + xmlTextWriterStartElement(writer, "message"); + xmlTextWriterWriteAttribute(writer, "xmlns", + "http://www.strongswan.org/smp/1.0"); + xmlTextWriterWriteAttribute(writer, "id", id); + xmlTextWriterWriteAttribute(writer, "type", "response"); + + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "query")) { - xmlFreeTextReader(reader); - xmlFreeTextWriter(writer); - DBG1(DBG_CFG, "creating SMP XML message failed"); - continue; + request_query(reader, writer); + break; } - - while (TRUE) - { - switch (xmlTextReaderRead(reader)) - { - case 1: - { - if (xmlTextReaderNodeType(reader) == - XML_READER_TYPE_ELEMENT) - { - if (streq(xmlTextReaderConstName(reader), "GetRequest")) - { - get(this, reader, writer); - break; - } - } - continue; - } - case 0: - /* end of XML */ - break; - default: - DBG1(DBG_CFG, "parsing SMP XML message failed"); - break; - } - xmlFreeTextReader(reader); - break; - } - /* write and close document */ - if (xmlTextWriterEndDocument(writer) < 0) - { - DBG1(DBG_CFG, "completing SMP XML message failed"); - } - xmlFreeTextWriter(writer); - /* write a newline to indicate end of xml */ - write(fd, "\n", 1); } } + /* and close document */ + xmlTextWriterEndDocument(writer); + xmlFreeTextWriter(writer); +} + +/** + * cleanup helper function for open file descriptors + */ +static void closefdp(int *fd) +{ + close(*fd); +} + +/** + * read from a opened connection and process it + */ +static job_requeue_t process(int *fdp) +{ + int oldstate, fd = *fdp; + char buffer[4096]; + size_t len; + xmlTextReaderPtr reader; + char *id = NULL, *type = NULL; + + pthread_cleanup_push((void*)closefdp, (void*)&fd); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + len = read(fd, buffer, sizeof(buffer)); + pthread_setcancelstate(oldstate, NULL); + pthread_cleanup_pop(0); + if (len <= 0) + { + close(fd); + DBG2(DBG_CFG, "SMP XML connection closed"); + return JOB_REQUEUE_NONE; + } + DBG1(DBG_CFG, "got XML request: %b", buffer, len); + + reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0); + if (reader == NULL) + { + DBG1(DBG_CFG, "opening SMP XML reader failed"); + return JOB_REQUEUE_FAIR;; + } + + /* read message type and id */ + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT && + streq(xmlTextReaderConstName(reader), "message")) + { + id = xmlTextReaderGetAttribute(reader, "id"); + type = xmlTextReaderGetAttribute(reader, "type"); + break; + } + } + + /* process message */ + if (id && type) + { + if (streq(type, "request")) + { + request(reader, id, fd); + } + else + { + /* response(reader, id) */ + } + } + xmlFreeTextReader(reader); + return JOB_REQUEUE_FAIR;; +} + +/** + * accept from XML socket and create jobs to process connections + */ +static job_requeue_t dispatch(private_xml_interface_t *this) +{ + struct sockaddr_un strokeaddr; + int oldstate, fd, *fdp, strokeaddrlen = sizeof(strokeaddr); + callback_job_t *job; + + /* wait for connections, but allow thread to terminate */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); + pthread_setcancelstate(oldstate, NULL); + + if (fd < 0) + { + DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno)); + sleep(1); + return JOB_REQUEUE_FAIR;; + } + + fdp = malloc_thing(int); + *fdp = fd; + job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job); + charon->processor->queue_job(charon->processor, (job_t*)job); + + return JOB_REQUEUE_DIRECT; } +struct sockaddr_un unix_addr = { AF_UNIX, "/var/run/charon.xml"}; + /** * Implementation of itnerface_t.destroy. */ static void destroy(private_xml_interface_t *this) { - pthread_cancel(this->thread); - pthread_join(this->thread, NULL); + this->job->cancel(this->job); close(this->socket); - unlink(socket_addr.sun_path); + //unlink(unix_addr.sun_path); free(this); } @@ -227,12 +405,13 @@ static void destroy(private_xml_interface_t *this) interface_t *interface_create() { private_xml_interface_t *this = malloc_thing(private_xml_interface_t); - mode_t old; + //mode_t old; + struct sockaddr_in tcp_addr; this->public.interface.destroy = (void (*)(interface_t*))destroy; /* set up unix socket */ - this->socket = socket(AF_UNIX, SOCK_STREAM, 0); + this->socket = socket(AF_INET, SOCK_STREAM, 0);//socket(AF_UNIX, SOCK_STREAM, 0); if (this->socket == -1) { DBG1(DBG_CFG, "could not create XML socket"); @@ -240,32 +419,39 @@ interface_t *interface_create() return NULL; } - old = umask(~S_IRWXU); - if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0) + memset(&tcp_addr, 0, sizeof(tcp_addr)); + tcp_addr.sin_family = AF_INET; + tcp_addr.sin_addr.s_addr = INADDR_ANY; + tcp_addr.sin_port = htons(4502); + if (bind(this->socket, (struct sockaddr*)&tcp_addr, sizeof(tcp_addr)) < 0) { DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno)); close(this->socket); free(this); return NULL; } - umask(old); - if (listen(this->socket, 0) < 0) + /* + old = umask(~S_IRWXU); + if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0) { - DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno)); + DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno)); close(this->socket); free(this); return NULL; } + umask(old);*/ - if (pthread_create(&this->thread, NULL, (void*(*)(void*))receive, this) != 0) + if (listen(this->socket, 5) < 0) { - DBG1(DBG_CFG, "could not create XML socket thread: %s", strerror(errno)); + DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno)); close(this->socket); - unlink(socket_addr.sun_path); free(this); return NULL; } + + this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); return &this->public.interface; }