From d39e04b5577ebbe6a3b916f55b797b792d701753 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 30 Sep 2014 18:43:20 +0200 Subject: [PATCH 01/13] vici: Fix message encoding type values in documentation --- src/libcharon/plugins/vici/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index aeabbbd4d..598be1fb6 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -84,12 +84,12 @@ The message encoding consists of a sequence of elements. Each element starts with the element type, optionally followed by an element name and/or an element value. Currently the following message element types are defined: -* _SECTION_START = 0_: Begin a new section having a name -* _SECTION_END = 1_: End a previously started section -* _KEY_VALUE = 2_: Define a value for a named key in the current section -* _LIST_START = 3_: Begin a named list for list items -* _LIST_ITEM = 4_: Define an unnamed item value in the current list -* _LIST_END = 5_: End a previously started list +* _SECTION_START = 1_: Begin a new section having a name +* _SECTION_END = 2_: End a previously started section +* _KEY_VALUE = 3_: Define a value for a named key in the current section +* _LIST_START = 4_: Begin a named list for list items +* _LIST_ITEM = 5_: Define an unnamed item value in the current list +* _LIST_END = 6_: End a previously started list Types are encoded as 8-bit values. Types having a name (SECTION_START, KEY_VALUE and LIST_START) have an ASCII string following the type, which itself From 94d939820226c13ba30b2af35876744e09c96791 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 6 Oct 2014 18:13:39 +0200 Subject: [PATCH 02/13] vici: Return a success result for the clear-creds command Even if the command actually can't fail, this looks more aligned to similar commands. --- src/libcharon/plugins/vici/vici_cred.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libcharon/plugins/vici/vici_cred.c b/src/libcharon/plugins/vici/vici_cred.c index cc6434b62..d4c02de6d 100644 --- a/src/libcharon/plugins/vici/vici_cred.c +++ b/src/libcharon/plugins/vici/vici_cred.c @@ -270,13 +270,10 @@ CALLBACK(load_shared, vici_message_t*, CALLBACK(clear_creds, vici_message_t*, private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) { - vici_builder_t *builder; - this->creds->clear(this->creds); lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); - builder = vici_builder_create(); - return builder->finalize(builder); + return create_reply(NULL); } static void manage_command(private_vici_cred_t *this, From 1038d96537049072c2558b083306d308b04f1d63 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 1 Oct 2014 15:59:43 +0200 Subject: [PATCH 03/13] vici: Add a ruby gem providing a native vici interface --- src/libcharon/plugins/vici/ruby/.gitignore | 1 + src/libcharon/plugins/vici/ruby/lib/vici.rb | 569 +++++++++++++++++++ src/libcharon/plugins/vici/ruby/vici.gemspec | 16 + 3 files changed, 586 insertions(+) create mode 100644 src/libcharon/plugins/vici/ruby/.gitignore create mode 100644 src/libcharon/plugins/vici/ruby/lib/vici.rb create mode 100644 src/libcharon/plugins/vici/ruby/vici.gemspec diff --git a/src/libcharon/plugins/vici/ruby/.gitignore b/src/libcharon/plugins/vici/ruby/.gitignore new file mode 100644 index 000000000..c111b3313 --- /dev/null +++ b/src/libcharon/plugins/vici/ruby/.gitignore @@ -0,0 +1 @@ +*.gem diff --git a/src/libcharon/plugins/vici/ruby/lib/vici.rb b/src/libcharon/plugins/vici/ruby/lib/vici.rb new file mode 100644 index 000000000..e8a9ddca9 --- /dev/null +++ b/src/libcharon/plugins/vici/ruby/lib/vici.rb @@ -0,0 +1,569 @@ +## +# The Vici module implements a native ruby client side library for the +# strongSwan VICI protocol. The Connection class provides a high-level +# interface to issue requests or listen for events. +# +# Copyright (C) 2014 Martin Willi +# Copyright (C) 2014 revosec AG +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +module Vici + + ## + # Vici specific exception all others inherit from + class Error < StandardError + end + + ## + # Error while parsing a vici message from the daemon + class ParseError < Error + end + + ## + # Error while encoding a vici message from ruby data structures + class EncodeError < Error + end + + ## + # Error while exchanging messages over the vici Transport layer + class TransportError < Error + end + + ## + # Generic vici command execution error + class CommandError < Error + end + + ## + # Error if an issued vici command is unknown by the daemon + class CommandUnknownError < CommandError + end + + ## + # Error if a command failed to execute in the daemon + class CommandExecError < CommandError + end + + ## + # Generic vici event handling error + class EventError < Error + end + + ## + # Tried to register to / unregister from an unknown vici event + class EventUnknownError < EventError + end + + ## + # Exception to raise from an event listening closure to stop listening + class StopEventListening < Exception + end + + + ## + # The Message class provides the low level encoding and decoding of vici + # protocol messages. Directly using this class is usually not required. + class Message + + SECTION_START = 1 + SECTION_END = 2 + KEY_VALUE = 3 + LIST_START = 4 + LIST_ITEM = 5 + LIST_END = 6 + + def initialize(data = "") + if data == nil + @root = Hash.new() + elsif data.is_a?(Hash) + @root = data + else + @encoded = data + end + end + + ## + # Get the raw byte encoding of an on-the-wire message + def encoding + if @encoded == nil + @encoded = encode(@root) + end + @encoded + end + + ## + # Get the root element of the parsed ruby data structures + def root + if @root == nil + @root = parse(@encoded) + end + @root + end + + private + + def encode_name(name) + [name.length].pack("c") << name + end + + def encode_value(value) + if value.class != String + value = value.to_s + end + [value.length].pack("n") << value + end + + def encode_kv(encoding, key, value) + encoding << KEY_VALUE << encode_name(key) << encode_value(value) + end + + def encode_section(encoding, key, value) + encoding << SECTION_START << encode_name(key) + encoding << encode(value) << SECTION_END + end + + def encode_list(encoding, key, value) + encoding << LIST_START << encode_name(key) + value.each do |item| + encoding << LIST_ITEM << encode_value(item) + end + encoding << LIST_END + end + + def encode(node) + encoding = "" + node.each do |key, value| + case value.class + when String, Fixnum, true, false + encoding = encode_kv(encoding, key, value) + else + if value.is_a?(Hash) + encoding = encode_section(encoding, key, value) + elsif value.is_a?(Array) + encoding = encode_list(encoding, key, value) + else + encoding = encode_kv(encoding, key, value) + end + end + end + encoding + end + + def parse_name(encoding) + len = encoding.unpack("c")[0] + name = encoding[1, len] + return encoding[(1 + len)..-1], name + end + + def parse_value(encoding) + len = encoding.unpack("n")[0] + value = encoding[2, len] + return encoding[(2 + len)..-1], value + end + + def parse(encoding) + stack = [Hash.new] + list = nil + while encoding.length != 0 do + type = encoding.unpack("c")[0] + encoding = encoding[1..-1] + case type + when SECTION_START + encoding, name = parse_name(encoding) + stack.push(stack[-1][name] = Hash.new) + when SECTION_END + if stack.length() == 1 + raise ParseError, "unexpected section end" + end + stack.pop() + when KEY_VALUE + encoding, name = parse_name(encoding) + encoding, value = parse_value(encoding) + stack[-1][name] = value + when LIST_START + encoding, name = parse_name(encoding) + stack[-1][name] = [] + list = name + when LIST_ITEM + raise ParseError, "unexpected list item" if list == nil + encoding, value = parse_value(encoding) + stack[-1][list].push(value) + when LIST_END + raise ParseError, "unexpected list end" if list == nil + list = nil + else + raise ParseError, "invalid type: #{type}" + end + end + if stack.length() > 1 + raise ParseError, "unexpected message end" + end + stack[0] + end + end + + + ## + # The Transport class implements to low level segmentation of packets + # to the underlying transport stream. Directly using this class is usually + # not required. + class Transport + + CMD_REQUEST = 0 + CMD_RESPONSE = 1 + CMD_UNKNOWN = 2 + EVENT_REGISTER = 3 + EVENT_UNREGISTER = 4 + EVENT_CONFIRM = 5 + EVENT_UNKNOWN = 6 + EVENT = 7 + + ## + # Create a transport layer using a provided socket for communication. + def initialize(socket) + @socket = socket + @events = Hash.new + end + + ## + # Write a packet prefixed by its length over the transport socket. Type + # specifies the message, the optional label and message get appended. + def write(type, label, message) + encoding = "" + if label + encoding << label.length << label + end + if message + encoding << message.encoding + end + @socket.send([encoding.length + 1, type].pack("Nc") + encoding, 0) + end + + ## + # Read a packet from the transport socket. Returns the packet type, and + # if available in the packet a label and the contained message. + def read + len = @socket.recv(4).unpack("N")[0] + encoding = @socket.recv(len) + type = encoding.unpack("c")[0] + len = 1 + case type + when CMD_REQUEST, EVENT_REGISTER, EVENT_UNREGISTER, EVENT + label = encoding[2, encoding[1].unpack("c")[0]] + len += label.length + 1 + when CMD_RESPONSE, CMD_UNKNOWN, EVENT_CONFIRM, EVENT_UNKNOWN + label = nil + else + raise TransportError, "invalid message: #{type}" + end + if encoding.length == len + return type, label, Message.new + end + return type, label, Message.new(encoding[len..-1]) + end + + def dispatch_event(name, message) + @events[name].each do |handler| + handler.call(name, message) + end + end + + def read_and_dispatch_event + type, label, message = read + p + if type == EVENT + dispatch_event(label, message) + else + raise TransportError, "unexpected message: #{type}" + end + end + + def read_and_dispatch_events + loop do + type, label, message = read + if type == EVENT + dispatch_event(label, message) + else + return type, label, message + end + end + end + + ## + # Send a command with a given name, and optionally a message. Returns + # the reply message on success. + def request(name, message = nil) + write(CMD_REQUEST, name, message) + type, label, message = read_and_dispatch_events + case type + when CMD_RESPONSE + return message + when CMD_UNKNOWN + raise CommandUnknownError, name + else + raise CommandError, "invalid response for #{name}" + end + end + + ## + # Register a handler method for the given event name + def register(name, handler) + write(EVENT_REGISTER, name, nil) + type, label, message = read_and_dispatch_events + case type + when EVENT_CONFIRM + if @events.has_key?(name) + @events[name] += [handler] + else + @events[name] = [handler]; + end + when EVENT_UNKNOWN + raise EventUnknownError, name + else + raise EventError, "invalid response for #{name} register" + end + end + + ## + # Unregister a handler method for the given event name + def unregister(name, handler) + write(EVENT_UNREGISTER, name, nil) + type, label, message = read_and_dispatch_events + case type + when EVENT_CONFIRM + @events[name] -= [handler] + when EVENT_UNKNOWN + raise EventUnknownError, name + else + raise EventError, "invalid response for #{name} unregister" + end + end + end + + + ## + # The Connection class provides the high-level interface to monitor, configure + # and control the IKE daemon. It takes a connected stream-oriented Socket for + # the communication with the IKE daemon. + # + # This class takes and returns ruby objects for the exchanged message data. + # * Sections get encoded as Hash, containing other sections as Hash, or + # * Key/Values, where the values are Strings as Hash values + # * Lists get encoded as Arrays with String values + # Non-String values that are not a Hash nor an Array get converted with .to_s + # during encoding. + class Connection + + def initialize(socket) + @transp = Transport.new(socket) + end + + ## + # List matching loaded connections. The provided closure is invoked + # for each matching connection. + def list_conns(match = nil, &block) + call_with_event("list-conns", Message.new(match), "list-conn", &block) + end + + ## + # List matching active SAs. The provided closure is invoked for each + # matching SA. + def list_sas(match = nil, &block) + call_with_event("list-sas", Message.new(match), "list-sa", &block) + end + + ## + # List matching installed policies. The provided closure is invoked + # for each matching policy. + def list_policies(match, &block) + call_with_event("list-policies", Message.new(match), "list-policy", + &block) + end + + ## + # List matching loaded certificates. The provided closure is invoked + # for each matching certificate definition. + def list_certs(match = nil, &block) + call_with_event("list-certs", Message.new(match), "list-cert", &block) + end + + ## + # Load a connection into the daemon. + def load_conn(conn) + check_success(@transp.request("load-conn", Message.new(conn))) + end + + ## + # Unload a connection from the daemon. + def unload_conn(conn) + check_success(@transp.request("unload-conn", Message.new(conn))) + end + + ## + # Get the names of connections managed by vici. + def get_conns() + @transp.request("get-conns").root + end + + ## + # Clear all loaded credentials. + def clear_creds() + check_success(@transp.request("clear-creds")) + end + + ## + # Load a certificate into the daemon. + def load_cert(cert) + check_success(@transp.request("load-cert", Message.new(cert))) + end + + ## + # Load a private key into the daemon. + def load_key(key) + check_success(@transp.request("load-key", Message.new(key))) + end + + ## + # Load a shared key into the daemon. + def load_shared(shared) + check_success(@transp.request("load-shared", Message.new(shared))) + end + + ## + # Load a virtual IP / attribute pool + def load_pool(pool) + check_success(@transp.request("load-pool", Message.new(pool))) + end + + ## + # Unload a virtual IP / attribute pool + def unload_pool(pool) + check_success(@transp.request("unload-pool", Message.new(pool))) + end + + ## + # Get the currently loaded pools. + def get_pools() + @transp.request("get-pools").root + end + + ## + # Initiate a connection. The provided closure is invoked for each log line. + def initiate(options, &block) + check_success(call_with_event("initiate", Message.new(options), + "control-log", &block)) + end + + ## + # Terminate a connection. The provided closure is invoked for each log line. + def terminate(options, &block) + check_success(call_with_event("terminate", Message.new(options), + "control-log", &block)) + end + + ## + # Install a shunt/route policy. + def install(policy) + check_success(@transp.request("install", Message.new(policy))) + end + + ## + # Uninstall a shunt/route policy. + def uninstall(policy) + check_success(@transp.request("uninstall", Message.new(policy))) + end + + ## + # Reload strongswan.conf settings. + def reload_settings + check_success(@transp.request("reload-settings", nil)) + end + + ## + # Get daemon statistics and information. + def stats + @transp.request("stats", nil).root + end + + ## + # Get daemon version information + def version + @transp.request("version", nil).root + end + + ## + # Listen for a set of event messages. This call is blocking, and invokes + # the passed closure for each event received. The closure receives the + # event name and the event message as argument. To stop listening, the + # closure may raise a StopEventListening exception, the only catched + # exception. + def listen_events(events, &block) + self.class.instance_eval do + define_method(:listen_event) do |label, message| + block.call(label, message.root) + end + end + events.each do |event| + @transp.register(event, method(:listen_event)) + end + begin + loop do + @transp.read_and_dispatch_event + end + rescue StopEventListening + ensure + events.each do |event| + @transp.unregister(event, method(:listen_event)) + end + end + end + + ## + # Issue a command request, but register for a specific event while the + # command is active. VICI uses this mechanism to stream potentially large + # data objects continuously. The provided closure is invoked for all + # event messages. + def call_with_event(command, request, event, &block) + self.class.instance_eval do + define_method(:call_event) do |label, message| + block.call(message.root) + end + end + @transp.register(event, method(:call_event)) + begin + reply = @transp.request(command, request) + ensure + @transp.unregister(event, method(:call_event)) + end + reply + end + + ## + # Check if the reply of a command indicates "success", otherwise raise a + # CommandExecError exception + def check_success(reply) + root = reply.root + if root["success"] != "yes" + raise CommandExecError, root["errmsg"] + end + root + end + end +end diff --git a/src/libcharon/plugins/vici/ruby/vici.gemspec b/src/libcharon/plugins/vici/ruby/vici.gemspec new file mode 100644 index 000000000..36bc21b90 --- /dev/null +++ b/src/libcharon/plugins/vici/ruby/vici.gemspec @@ -0,0 +1,16 @@ +Gem::Specification.new do |s| + s.name = "vici" + s.version = "0.0.1" + s.authors = ["Martin Willi"] + s.email = ["martin@strongswan.ch"] + s.description = %q{ + The strongSwan VICI protocol allows external application to monitor, + configure and control the IKE daemon charon. This ruby gem provides a + native client side implementation of the VICI protocol, well suited to + script automated tasks in a relaible way. + } + s.summary = "Native ruby interface for strongSwan VICI" + s.homepage = "https://wiki.strongswan.org/projects/strongswan/wiki/Vici" + s.license = "MIT" + s.files = "lib/vici.rb" +end From 409f1fc144f47e12f1d8644382d41c5c12482f1b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 8 Oct 2014 13:44:44 +0200 Subject: [PATCH 04/13] configure: Add global --enable-ruby-gems and --with-rubygemdir options This provides the options to build and install ruby gems for components providing them, such as vici. --- configure.ac | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/configure.ac b/configure.ac index 2ea3742d0..01951709f 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,7 @@ ARG_WITH_SET([capabilities], [no], [set capability dropping library. Cur ARG_WITH_SET([mpz_powm_sec], [yes], [use the more side-channel resistant mpz_powm_sec in libgmp, if available]) ARG_WITH_SET([dev-headers], [no], [install strongSwan development headers to directory.]) ARG_WITH_SET([printf-hooks], [auto], [force the use of a specific printf hook implementation (auto, builtin, glibc, vstr).]) +ARG_WITH_SET([rubygemdir], ["gem environment gemdir"], [path to install ruby gems to]) if test -n "$PKG_CONFIG"; then systemdsystemunitdir_default=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) @@ -285,6 +286,7 @@ ARG_ENABL_SET([integrity-test], [enable integrity testing of libstrongswan and p ARG_DISBL_SET([load-warning], [disable the charon plugin load option warning in starter.]) ARG_ENABL_SET([mediation], [enable IKEv2 Mediation Extension.]) ARG_ENABL_SET([unwind-backtraces],[use libunwind to create backtraces for memory leaks and segfaults.]) +ARG_ENABL_SET([ruby-gems], [enable installation of provided ruby gems.]) # compile options ARG_ENABL_SET([coverage], [enable lcov coverage report generation.]) ARG_ENABL_SET([leak-detective], [enable malloc hooks to find memory leaks.]) @@ -1152,6 +1154,17 @@ if test x$coverage = xtrue; then CFLAGS="${CFLAGS} -g -O0" fi +if test x$ruby_gems = xtrue; then + AC_PATH_PROG([GEM], [gem], [], [$PATH:/bin:/usr/bin:/usr/local/bin]) + if test x$GEM = x; then + AC_MSG_ERROR(RubyGems package manager not found) + fi + if test "x$rubygemdir" = "xgem environment gemdir"; then + rubygemdir=$($GEM environment gemdir) + fi + AC_SUBST(RUBYGEMDIR, "$rubygemdir") +fi + # =============================================== # collect plugin list for strongSwan components # =============================================== @@ -1511,6 +1524,7 @@ AM_CONDITIONAL(USE_SWANCTL, test x$swanctl = xtrue) AM_CONDITIONAL(USE_SVC, test x$svc = xtrue) AM_CONDITIONAL(USE_SYSTEMD, test x$systemd = xtrue) AM_CONDITIONAL(USE_LEGACY_SYSTEMD, test -n "$systemdsystemunitdir" -a "x$systemdsystemunitdir" != xno) +AM_CONDITIONAL(USE_RUBY_GEMS, test x$ruby_gems = xtrue) # ======================== # set global definitions From f684be6583d97aa4b5d1619cbbaff62d7214f4e2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 8 Oct 2014 13:46:22 +0200 Subject: [PATCH 05/13] vici: Use "gem"-assisted vici ruby gem building and installation --- configure.ac | 1 + src/libcharon/plugins/vici/Makefile.am | 7 +++++++ src/libcharon/plugins/vici/ruby/.gitignore | 1 + src/libcharon/plugins/vici/ruby/Makefile.am | 20 +++++++++++++++++++ .../ruby/{vici.gemspec => vici.gemspec.in} | 2 +- 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/libcharon/plugins/vici/ruby/Makefile.am rename src/libcharon/plugins/vici/ruby/{vici.gemspec => vici.gemspec.in} (94%) diff --git a/configure.ac b/configure.ac index 01951709f..dab78a9b4 100644 --- a/configure.ac +++ b/configure.ac @@ -1727,6 +1727,7 @@ AC_CONFIG_FILES([ src/libcharon/plugins/maemo/Makefile src/libcharon/plugins/stroke/Makefile src/libcharon/plugins/vici/Makefile + src/libcharon/plugins/vici/ruby/Makefile src/libcharon/plugins/updown/Makefile src/libcharon/plugins/dhcp/Makefile src/libcharon/plugins/unit_tester/Makefile diff --git a/src/libcharon/plugins/vici/Makefile.am b/src/libcharon/plugins/vici/Makefile.am index 7e459c58d..da71de394 100644 --- a/src/libcharon/plugins/vici/Makefile.am +++ b/src/libcharon/plugins/vici/Makefile.am @@ -67,3 +67,10 @@ vici_tests_LDFLAGS = @COVERAGE_LDFLAGS@ vici_tests_LDADD = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ $(top_builddir)/src/libstrongswan/tests/libtest.la + + +SUBDIRS = + +if USE_RUBY_GEMS +SUBDIRS += ruby +endif diff --git a/src/libcharon/plugins/vici/ruby/.gitignore b/src/libcharon/plugins/vici/ruby/.gitignore index c111b3313..6b98b820a 100644 --- a/src/libcharon/plugins/vici/ruby/.gitignore +++ b/src/libcharon/plugins/vici/ruby/.gitignore @@ -1 +1,2 @@ *.gem +*.gemspec diff --git a/src/libcharon/plugins/vici/ruby/Makefile.am b/src/libcharon/plugins/vici/ruby/Makefile.am new file mode 100644 index 000000000..c4dbb808d --- /dev/null +++ b/src/libcharon/plugins/vici/ruby/Makefile.am @@ -0,0 +1,20 @@ +vici.gemspec: $(srcdir)/vici.gemspec.in + $(AM_V_GEN) sed \ + -e "s:@GEM_VERSION@:$(PACKAGE_VERSION):" \ + $(srcdir)/vici.gemspec.in > $@ + +vici-$(PACKAGE_VERSION).gem: vici.gemspec + $(GEM) build vici.gemspec + +all-local: vici-$(PACKAGE_VERSION).gem + +clean-local: + rm -f vici.gemspec vici-$(PACKAGE_VERSION).gem + +install-data-local: vici-$(PACKAGE_VERSION).gem + $(GEM) install --install-dir $(DESTDIR)$(RUBYGEMDIR) \ + vici-$(PACKAGE_VERSION).gem + +uninstall-local: + $(GEM) uninstall --install-dir $(DESTDIR)$(RUBYGEMDIR) \ + --version $(PACKAGE_VERSION) vici diff --git a/src/libcharon/plugins/vici/ruby/vici.gemspec b/src/libcharon/plugins/vici/ruby/vici.gemspec.in similarity index 94% rename from src/libcharon/plugins/vici/ruby/vici.gemspec rename to src/libcharon/plugins/vici/ruby/vici.gemspec.in index 36bc21b90..5ad61c0a0 100644 --- a/src/libcharon/plugins/vici/ruby/vici.gemspec +++ b/src/libcharon/plugins/vici/ruby/vici.gemspec.in @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "vici" - s.version = "0.0.1" + s.version = "@GEM_VERSION@" s.authors = ["Martin Willi"] s.email = ["martin@strongswan.ch"] s.description = %q{ From 56f17733c9a94ea70242e2e4cf4b74db729f4d9e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 8 Oct 2014 18:13:31 +0200 Subject: [PATCH 06/13] vici: Document the available vici command and event messages --- src/libcharon/plugins/vici/README.md | 510 ++++++++++++++++++++++++++- 1 file changed, 509 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index 598be1fb6..2c3a4df36 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -103,7 +103,8 @@ the length field itself. The interpretation of any value is not defined by the message format; it can take arbitrary blobs. The application may specify types for specific keys, such -as strings or integer representations. +as strings or integer representations. The vici plugin currently uses +non-null terminated strings as values only; numbers get encoded as strings. ### Sections ### @@ -165,6 +166,513 @@ the following C array: 1, }; +## Client-initiated commands ## + +Based on the packet layer, VICI implements commands requested by the client +and responded to by the server using named _CMD_REQUEST_ and _CMD_RESPONSE_ +packets wrapping messages. The request message may contain command arguments, +the response message the reply. + +Some commands use response streaming, that is, a request triggers a series of +events to consecutively stream data to the client before the response message +completes the stream. A client must register for the appropriate event to +receive the stream, and unregister after the response has been received. + +The following client issued commands with the appropriate command input and +output messages are currently defined: + +### version() ### + +Returns daemon and system specific version information. + + {} => { + daemon = + version = + sysname = + release = + machine = + } + +### stats() ### + +Returns IKE daemon statistics and load information. + + {} => { + uptime = { + running = + since = + } + workers = { + total = + idle = + active = { + critical = + high = + medium = + low = + } + } + queues = { + critical = + high = + medium = + low = + } + scheduled = + ikesas = { + total = + half-open = + } + plugins = [ + + ] + mem = { # available if built with leak-detective or on Windows + total = + allocs = + * = { # on Windows only + total = + allocs = + } + } + mallinfo = { # available with mallinfo() support + sbrk = + mmap = + used = + free = + } + } + +### reload-settings() ### + +Reloads _strongswan.conf_ settings and all plugins supporting configuration +reload. + + {} => { + success = + errmsg = + } + +### initiate() ### + +Initiates an SA while streaming _control-log_ events. + + { + child = + timeout = + loglevel = + } => { + success = + errmsg = + } + +### terminate() ### + +Terminates an SA while streaming _control-log_ events. + + { + child = + ike = + child_id = + ike_id = + timeout = + loglevel = + } => { + success = + errmsg = + } + +### install() ### + +Install a trap, drop or bypass policy defined by a CHILD_SA config. + + { + child = + } => { + success = + errmsg = + } + +### uninstall() ### + +Uninstall a trap, drop or bypass policy defined by a CHILD_SA config. + + { + child = + } => { + success = + errmsg = + } + +### list-sas() ### + +Lists currently active IKE_SAs and associated CHILD_SAs by streaming _list-sa_ +events. + + { + noblock = + ike = + ike_id = + } => { + # completes after streaming list-sa events + } + +### list-policies() ### + +List currently installed trap, drop and bypass policies by streaming +_list-policy_ events. + + { + drop = + pass = + trap = + child = + } => { + # completes after streaming list-sa events + } + +### list-conns() ### + +List currently loaded connections by streaming _list-conn_ events. This +call includes all connections known by the daemon, not only those loaded +over vici. + + { + ike = + } => { + # completes after streaming list-conn events + } + +### get-conns() ### + +Return a list of connection names loaded exclusively over vici, not including +connections found in other backends. + + {} => { + conns = [ + + ] + } + +### list-certs() ### + +List currently loaded certificates by streaming _list-cert_ events. This +call includes all certificates known by the daemon, not only those loaded +over vici. + + { + type = + subject = + } => { + # completes after streaming list-cert events + } + +### load-conn() ### + +Load a single connection definition into the daemon. An existing connection +with the same name gets updated or replaced. + + { + = { + # IKE configuration parameters with authentication and CHILD_SA + # subsections. Refer to swanctl.conf(5) for details. + } => { + success = + errmsg = + } + } + +### unload-conn() ### + +Unload a previously loaded connection definition by name. + + { + name = + } => { + success = + errmsg = + } + +### load-cert() ### + +Load a certificate into the daemon. + + { + type = + data = + } => { + success = + errmsg = + } + +### load-key() ### + +Load a private key into the daemon. + + { + type = + data = + } => { + success = + errmsg = + } + +### load-shared() ### + +Load a shared IKE PSK, EAP or XAuth secret into the daemon. + + { + type = + data = + owners = [ + + ] + } => { + success = + errmsg = + } + +### clear-creds() ### + +Clear all loaded certificate, private key and shared key credentials. This +affects only credentials loaded over vici, but additionally flushes the +credential cache. + + {} => { + success = + errmsg = + } + +### load-pool() ### + +Load an in-memory virtual IP and configuration attribute pool. Existing +pools with the same name get updated, if possible. + + { + = { + addrs = + * = [ + # attribute type is one of address, dns, nbns, dhcp, netmask, + # server, subnet, split_include, split_exclude or a numerical + # attribute type identifier. + + ] + } + } => { + success = + errmsg = + } + +### unload-pool() ### + +Unload a previously loaded virtual IP and configuration attribute pool. +Unloading fails for pools with leases currently online. + + { + name = + } => { + success = + errmsg = + } + +### get-pools() ### + +List the currently loaded pools. + + {} => { + * = { + base = + size = + online = + offline = + } + } + +## Server-issued events ## + +Based on the packet layer, the vici plugin raises event messages using named +EVENT packets wrapping messages. The message contains event details. + +### log ### + +The _log_ event is issued to registered clients for each debug log message. +This event is not associated with a command. + + { + group = + level = + thread = + ikesa-name = + ikesa-uniqued = + msg = + } + +### control-log ### + +The _control-log_ event is issued for log events during active _initiate_ or +_terminate_ commands. It is issued only to clients currently having such +a command active. + + { + group = + level = + ikesa-name = + ikesa-uniqued = + msg = + } + +### list-sa ### + +The _list-sa_ event is issued to stream IKE_SAs during an active _list-sas_ +command. + + { + = { + uniqueid = + version = + state = + local-host = + local-id = + remote-host = + remote-id = + remote-xauth-id = + remote-eap-id = + initiator = + initiator-spi = + responder-spi = + encr-alg = + encr-keysize = + integ-alg = + integ-keysize = + prf-alg = + dh-group = + established = + rekey-time = + reauth-time = + tasks-queued = [ + + ] + tasks-active = [ + + ] + tasks-passive = [ + + ] + child-sas = { + * = { + reqid = + state = + mode = + protocol = + encap = + spi-in = + spi-out = + cpi-in = + cpi-out = + encr-alg = + encr-keysize = + integ-alg = + integ-keysize = + prf-alg = + dh-group = + esn = <1 if using extended sequence numbers> + bytes-in = + packets-in = + use-in = + bytes-out = + packets-out = + use-out = + rekey-time = + life-time = + install-time = + local-ts = [ + + ] + remote-ts = [ + + ] + } + } + } + } + +### list-policy ### + +The _list-policy_ event is issued to stream installed policies during an active +_list-policies_ command. + + { + = { + mode = + local-ts = [ + + ] + remote-ts = [ + + ] + } + } + +### list-conn ### + +The _list-conn_ event is issued to stream loaded connection during an active +_list-conns_ command. + + { + = { + local_addrs = [ + + ] + remote_addrs = [ + + ] + version = + + local*, remote* = { # multiple local and remote auth sections + class = + eap-type = + eap-vendor = + xauth = + revocation = + id = + aaa_id = + eap_id = + xauth_id = + groups = [ + + ] + certs = [ + + ] + cacerts = [ + + ] + } + children = { + * = { + mode = + local-ts = [ + + ] + remote-ts = [ + + ] + } + } + } + } + +### list-cert ### + +The _list-cert_ event is issued to stream loaded certificates during an active +_list-certs_ command. + + { + type = + has_privkey = + data = + } + + # libvici C client library # libvici is the reference implementation of a C client library implementing From dccb2c6eba3c22397e14fd02e88c9ea8232fa441 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 9 Oct 2014 16:42:01 +0200 Subject: [PATCH 07/13] vici: Add some simple libvici examples to the README --- src/libcharon/plugins/vici/README.md | 118 ++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index 2c3a4df36..0ca20a407 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -680,5 +680,119 @@ the vici protocol. It builds upon libstrongswan, but provides a stable API to implement client applications in the C programming language. libvici uses the libstrongswan thread pool to deliver event messages asynchronously. -More information about the libvici API is available in the libvici.h header -file. +## Connecting to the daemon ## + +This example shows how to connect to the daemon using the default URI, and +then perform proper cleanup: + + #include + #include + #include + + #include + + int main(int argc, char *argv[]) + { + vici_conn_t *conn; + int ret = 0; + + vici_init(); + conn = vici_connect(NULL); + if (conn) + { + /* do stuff */ + vici_disconnect(conn); + } + else + { + ret = errno; + fprintf(stderr, "connecting failed: %s\n", strerror(errno)); + } + vici_deinit(); + return ret; + } + +## A simple client request ## + +In the following example, a simple _version_ request is issued to the daemon +and the result is printed: + + int get_version(vici_conn_t *conn) + { + vici_req_t *req; + vici_res_t *res; + int ret = 0; + + req = vici_begin("version"); + res = vici_submit(req, conn); + if (res) + { + printf("%s %s (%s, %s, %s)\n", + vici_find_str(res, "", "daemon"), + vici_find_str(res, "", "version"), + vici_find_str(res, "", "sysname"), + vici_find_str(res, "", "release"), + vici_find_str(res, "", "machine")); + vici_free_res(res); + } + else + { + ret = errno; + fprintf(stderr, "version request failed: %s\n", strerror(errno)); + } + return ret; + } + +## A request with event streaming and callback parsing ## + +In this more advanced example, the _list-conns_ command is used to stream +loaded connections with the _list-conn_ event. The event message is parsed +with a simple callback to print the connection name: + + int conn_cb(void *null, vici_res_t *res, char *name) + { + printf("%s\n", name); + return 0; + } + + void list_cb(void *null, char *name, vici_res_t *res) + { + if (vici_parse_cb(res, conn_cb, NULL, NULL, NULL) != 0) + { + fprintf(stderr, "parsing failed: %s\n", strerror(errno)); + } + } + + int list_conns(vici_conn_t *conn) + { + vici_req_t *req; + vici_res_t *res; + int ret = 0; + + if (vici_register(conn, "list-conn", list_cb, NULL) == 0) + { + req = vici_begin("list-conns"); + res = vici_submit(req, conn); + if (res) + { + vici_free_res(res); + } + else + { + ret = errno; + fprintf(stderr, "request failed: %s\n", strerror(errno)); + } + vici_register(conn, "list-conn", NULL, NULL); + } + else + { + ret = errno; + fprintf(stderr, "registration failed: %s\n", strerror(errno)); + } + return ret; + } + +## API documentation ## + +More information about the libvici API is available in the _libvici.h_ header +file or the generated Doxygen documentation. From 6f5514933501769a709670cb1c1387426f2325a6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 9 Oct 2014 17:22:08 +0200 Subject: [PATCH 08/13] vici: Document the ruby gem and add some simple examples --- src/libcharon/plugins/vici/README.md | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index 0ca20a407..272491052 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -796,3 +796,61 @@ with a simple callback to print the connection name: More information about the libvici API is available in the _libvici.h_ header file or the generated Doxygen documentation. + +# vici ruby gem # + +The _vici ruby gem_ is a pure ruby implementation of the VICI protocol to +implement client applications. It is provided in the _ruby_ subdirectory, and +gets built and installed if strongSwan has been _./configure_'d with +_--enable-vici_ and _--enable-ruby-gems_. + +The _Connection_ class from the _Vici_ module provides the high level interface, +the underlying classes are usually not required to build ruby applications +using VICI. The _Connection_ class provides methods for the supported VICI +commands and an event listening mechanism. + +To represent the VICI message data tree, the gem converts the binary encoding +to ruby data types. The _Connection_ class takes and returns ruby objects for +the exchanged message data: + * Sections get encoded as Hash, containing other sections as Hash, or + * Key/Values, where the values are Strings as Hash values + * Lists get encoded as Arrays with String values +Non-String values that are not a Hash nor an Array get converted with .to_s +during encoding. + +## Connecting to the daemon ## + +To create a connection to the daemon, a socket must be passed to the +_Connection_ constructor. There is no default, but on Unix systems usually +a Unix socket over _/var/run/charon.vici_ is used: + + require "vici" + require "socket" + + v = Vici::Connection.new(UNIXSocket.new("/var/run/charon.vici")) + +## A simple client request ## + +An example to print the daemon version information is as simple as: + + x = v.version + puts "%s %s (%s, %s, %s)" % [ + x["daemon"], x["version"], x["sysname"], x["release"], x["machine"] + ] + +## A request with closure invocation ## + +The _Connection_ class takes care of event streaming by invoking a closure +for each event. The following example lists all loaded connections using the +_list-conns_ command and implicitly the _list-conn_ event: + + v.list_conns { |conn| + conn.each { |key, value| + puts key + } + } + +## API documentation ## + +For more details about the ruby gem refer to the comments in the gem source +code or the generated documentation. From 046b547a37907ee303f23ba47ea2fee190e256d4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 9 Oct 2014 16:11:29 +0200 Subject: [PATCH 09/13] vici: Don't include-depend on libstrongswan for boolean types As we want to avoid the libstrongswan include dependencies for libvici, avoid the use of the bool type. Unfortunately this change may break the ABI for vici_dump(). As this function is mostly for debugging purposes, we do it nonetheless; my apologies if somebody already relies on the ABI stability of that function. --- src/libcharon/plugins/vici/libvici.c | 2 +- src/libcharon/plugins/vici/libvici.h | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libcharon/plugins/vici/libvici.c b/src/libcharon/plugins/vici/libvici.c index a2cbb3082..54b8cc582 100644 --- a/src/libcharon/plugins/vici/libvici.c +++ b/src/libcharon/plugins/vici/libvici.c @@ -438,7 +438,7 @@ void vici_free_req(vici_req_t *req) free(req); } -int vici_dump(vici_res_t *res, char *label, bool pretty, FILE *out) +int vici_dump(vici_res_t *res, char *label, int pretty, FILE *out) { if (res->message->dump(res->message, label, pretty, out)) { diff --git a/src/libcharon/plugins/vici/libvici.h b/src/libcharon/plugins/vici/libvici.h index 58595d8cc..641370efd 100644 --- a/src/libcharon/plugins/vici/libvici.h +++ b/src/libcharon/plugins/vici/libvici.h @@ -75,8 +75,6 @@ #include -#include - /** * Opaque vici connection contex. */ @@ -284,7 +282,7 @@ void vici_free_req(vici_req_t *req); * @param out FILE to dump to * @return 0 if dumped complete message, 1 on error */ -int vici_dump(vici_res_t *res, char *label, bool pretty, FILE *out); +int vici_dump(vici_res_t *res, char *label, int pretty, FILE *out); /** * Parse next element from a vici response message. From 3db58e837caa5eabfcb752b32960f4116ee9b209 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 9 Oct 2014 16:14:38 +0200 Subject: [PATCH 10/13] vici: Reduce debug level during thread spawning We want to avoid libvici users to get a cluttered stderr for no real error. --- src/libcharon/plugins/vici/libvici.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcharon/plugins/vici/libvici.c b/src/libcharon/plugins/vici/libvici.c index 54b8cc582..20b007447 100644 --- a/src/libcharon/plugins/vici/libvici.c +++ b/src/libcharon/plugins/vici/libvici.c @@ -754,7 +754,9 @@ void vici_init() library_init(NULL, "vici"); if (lib->processor->get_total_threads(lib->processor) < 4) { + dbg_default_set_level(0); lib->processor->set_threads(lib->processor, 4); + dbg_default_set_level(1); } } From d4d85135c5713f3bddebdc5ccc3c0bf0fa4b022a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 9 Oct 2014 16:15:29 +0200 Subject: [PATCH 11/13] vici: Cancel processor before calling library_deinit() For non-direct libstrongswan users, the deinitialization segfaults because of the missing worker thread cancellation. --- src/libcharon/plugins/vici/libvici.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/plugins/vici/libvici.c b/src/libcharon/plugins/vici/libvici.c index 20b007447..c0205ccb6 100644 --- a/src/libcharon/plugins/vici/libvici.c +++ b/src/libcharon/plugins/vici/libvici.c @@ -762,5 +762,6 @@ void vici_init() void vici_deinit() { + lib->processor->cancel(lib->processor); library_deinit(); } From 67f9f09dd3aec23f8ebc514220c53833996dd1ea Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 9 Oct 2014 16:48:29 +0200 Subject: [PATCH 12/13] swanctl: Fix exit codes based on errno As fprintf() most likely sets errno, we should save it before printing the error message. --- src/swanctl/command.c | 3 ++- src/swanctl/commands/initiate.c | 6 ++++-- src/swanctl/commands/install.c | 3 ++- src/swanctl/commands/list_certs.c | 7 +++++-- src/swanctl/commands/list_conns.c | 7 +++++-- src/swanctl/commands/list_pols.c | 7 +++++-- src/swanctl/commands/list_pools.c | 3 ++- src/swanctl/commands/list_sas.c | 8 +++++--- src/swanctl/commands/log.c | 4 +++- src/swanctl/commands/reload_settings.c | 3 ++- src/swanctl/commands/stats.c | 4 +++- src/swanctl/commands/terminate.c | 6 ++++-- src/swanctl/commands/version.c | 4 +++- 13 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/swanctl/command.c b/src/swanctl/command.c index dbe16c3b7..1c079ec3a 100644 --- a/src/swanctl/command.c +++ b/src/swanctl/command.c @@ -267,9 +267,10 @@ static int call_command(command_t *cmd) conn = vici_connect(uri); if (!conn) { + ret = errno; command_usage("connecting to '%s' URI failed: %s", uri ?: "default", strerror(errno)); - return errno; + return ret; } ret = cmd->call(conn); vici_disconnect(conn); diff --git a/src/swanctl/commands/initiate.c b/src/swanctl/commands/initiate.c index 080dc4131..eb7b6adbd 100644 --- a/src/swanctl/commands/initiate.c +++ b/src/swanctl/commands/initiate.c @@ -71,8 +71,9 @@ static int initiate(vici_conn_t *conn) if (vici_register(conn, "control-log", log_cb, &format) != 0) { + ret = errno; fprintf(stderr, "registering for log failed: %s\n", strerror(errno)); - return errno; + return ret; } req = vici_begin("initiate"); if (child) @@ -87,8 +88,9 @@ static int initiate(vici_conn_t *conn) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "initiate request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/install.c b/src/swanctl/commands/install.c index e8727d573..59c5c24ab 100644 --- a/src/swanctl/commands/install.c +++ b/src/swanctl/commands/install.c @@ -55,8 +55,9 @@ static int manage_policy(vici_conn_t *conn, char *label) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "%s request failed: %s\n", label, strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/list_certs.c b/src/swanctl/commands/list_certs.c index bee5fda27..ecb65289a 100644 --- a/src/swanctl/commands/list_certs.c +++ b/src/swanctl/commands/list_certs.c @@ -590,6 +590,7 @@ static int list_certs(vici_conn_t *conn) vici_res_t *res; command_format_options_t format = COMMAND_FORMAT_NONE; char *arg, *subject = NULL, *type = NULL; + int ret; while (TRUE) { @@ -621,9 +622,10 @@ static int list_certs(vici_conn_t *conn) } if (vici_register(conn, "list-cert", list_cb, &format) != 0) { + ret = errno; fprintf(stderr, "registering for certificates failed: %s\n", strerror(errno)); - return errno; + return ret; } req = vici_begin("list-certs"); if (type) @@ -637,8 +639,9 @@ static int list_certs(vici_conn_t *conn) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "list-certs request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/list_conns.c b/src/swanctl/commands/list_conns.c index ec5da4bef..31ab9c40a 100644 --- a/src/swanctl/commands/list_conns.c +++ b/src/swanctl/commands/list_conns.c @@ -183,6 +183,7 @@ static int list_conns(vici_conn_t *conn) vici_res_t *res; command_format_options_t format = COMMAND_FORMAT_NONE; char *arg; + int ret; while (TRUE) { @@ -205,16 +206,18 @@ static int list_conns(vici_conn_t *conn) } if (vici_register(conn, "list-conn", list_cb, &format) != 0) { + ret = errno; fprintf(stderr, "registering for connections failed: %s\n", strerror(errno)); - return errno; + return ret; } req = vici_begin("list-conns"); res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "list-conns request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/list_pols.c b/src/swanctl/commands/list_pols.c index 2317b2542..f2ae22172 100644 --- a/src/swanctl/commands/list_pols.c +++ b/src/swanctl/commands/list_pols.c @@ -116,6 +116,7 @@ static int list_pols(vici_conn_t *conn) bool trap = FALSE, drop = FALSE, pass = FALSE; command_format_options_t format = COMMAND_FORMAT_NONE; char *arg, *child = NULL; + int ret; while (TRUE) { @@ -154,9 +155,10 @@ static int list_pols(vici_conn_t *conn) } if (vici_register(conn, "list-policy", list_cb, &format) != 0) { + ret = errno; fprintf(stderr, "registering for policies failed: %s\n", strerror(errno)); - return errno; + return ret; } req = vici_begin("list-policies"); if (child) @@ -178,8 +180,9 @@ static int list_pols(vici_conn_t *conn) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "list-policies request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/list_pools.c b/src/swanctl/commands/list_pools.c index 17ea539a9..155771657 100644 --- a/src/swanctl/commands/list_pools.c +++ b/src/swanctl/commands/list_pools.c @@ -68,8 +68,9 @@ static int list_pools(vici_conn_t *conn) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "get-pools request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/list_sas.c b/src/swanctl/commands/list_sas.c index 80c279ce8..35e7469a9 100644 --- a/src/swanctl/commands/list_sas.c +++ b/src/swanctl/commands/list_sas.c @@ -283,7 +283,7 @@ static int list_sas(vici_conn_t *conn) bool noblock = FALSE; command_format_options_t format = COMMAND_FORMAT_NONE; char *arg, *ike = NULL; - int ike_id = 0; + int ike_id = 0, ret; while (TRUE) { @@ -315,8 +315,9 @@ static int list_sas(vici_conn_t *conn) } if (vici_register(conn, "list-sa", list_cb, &format) != 0) { + ret = errno; fprintf(stderr, "registering for SAs failed: %s\n", strerror(errno)); - return errno; + return ret; } req = vici_begin("list-sas"); if (ike) @@ -334,8 +335,9 @@ static int list_sas(vici_conn_t *conn) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "list-sas request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/log.c b/src/swanctl/commands/log.c index 99ba328a7..d7082bfca 100644 --- a/src/swanctl/commands/log.c +++ b/src/swanctl/commands/log.c @@ -50,6 +50,7 @@ static int logcmd(vici_conn_t *conn) { command_format_options_t format = COMMAND_FORMAT_NONE; char *arg; + int ret; while (TRUE) { @@ -73,8 +74,9 @@ static int logcmd(vici_conn_t *conn) if (vici_register(conn, "log", log_cb, &format) != 0) { + ret = errno; fprintf(stderr, "registering for log failed: %s\n", strerror(errno)); - return errno; + return ret; } wait_sigint(); diff --git a/src/swanctl/commands/reload_settings.c b/src/swanctl/commands/reload_settings.c index ecd633866..efad1300f 100644 --- a/src/swanctl/commands/reload_settings.c +++ b/src/swanctl/commands/reload_settings.c @@ -49,8 +49,9 @@ static int reload_settings(vici_conn_t *conn) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "reload-settings request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/stats.c b/src/swanctl/commands/stats.c index b5425f504..a28ca83ba 100644 --- a/src/swanctl/commands/stats.c +++ b/src/swanctl/commands/stats.c @@ -23,6 +23,7 @@ static int stats(vici_conn_t *conn) vici_res_t *res; char *arg; command_format_options_t format = COMMAND_FORMAT_NONE; + int ret; while (TRUE) { @@ -48,8 +49,9 @@ static int stats(vici_conn_t *conn) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "stats request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/terminate.c b/src/swanctl/commands/terminate.c index 689ba4d50..8b3233c89 100644 --- a/src/swanctl/commands/terminate.c +++ b/src/swanctl/commands/terminate.c @@ -80,8 +80,9 @@ static int terminate(vici_conn_t *conn) if (vici_register(conn, "control-log", log_cb, &format) != 0) { + ret = errno; fprintf(stderr, "registering for log failed: %s\n", strerror(errno)); - return errno; + return ret; } req = vici_begin("terminate"); if (child) @@ -108,8 +109,9 @@ static int terminate(vici_conn_t *conn) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "terminate request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { diff --git a/src/swanctl/commands/version.c b/src/swanctl/commands/version.c index 4f24a0fc2..0c499e4cc 100644 --- a/src/swanctl/commands/version.c +++ b/src/swanctl/commands/version.c @@ -24,6 +24,7 @@ static int version(vici_conn_t *conn) char *arg; bool daemon = FALSE; command_format_options_t format = COMMAND_FORMAT_NONE; + int ret; while (TRUE) { @@ -58,8 +59,9 @@ static int version(vici_conn_t *conn) res = vici_submit(req, conn); if (!res) { + ret = errno; fprintf(stderr, "version request failed: %s\n", strerror(errno)); - return errno; + return ret; } if (format & COMMAND_FORMAT_RAW) { From 7431ad0de54d25c5ac08054972896a48d75f9f70 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 10 Oct 2014 11:03:47 +0200 Subject: [PATCH 13/13] NEWS: Introduce the vici ruby gem --- NEWS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 6139fa5e8..f1a4b2146 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,11 @@ strongswan-5.2.1 - The new ext-auth plugin calls an external script to implement custom IKE_SA authorization logic, courtesy of Vyronas Tsingaras. +- For the vici plugin a ruby gem has been added to allow ruby applications + to control or monitor the IKE daemon. The vici documentation has been updated + to include a description of the available operations and some simple examples + using both the libvici C interface and the ruby gem. + strongswan-5.2.0 ----------------