Merge branch 'vici-ruby'
Adds a ruby gem for the VICI protocol, along with some documentation improvements and some minor fixes to vici and swanctl.
This commit is contained in:
@@ -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
|
||||
----------------
|
||||
|
||||
@@ -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
|
||||
@@ -1713,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 = <IKE daemon name>
|
||||
version = <strongSwan version>
|
||||
sysname = <operating system name>
|
||||
release = <operating system release>
|
||||
machine = <hardware identifier>
|
||||
}
|
||||
|
||||
### stats() ###
|
||||
|
||||
Returns IKE daemon statistics and load information.
|
||||
|
||||
{} => {
|
||||
uptime = {
|
||||
running = <relative uptime in human-readable form>
|
||||
since = <absolute startup time>
|
||||
}
|
||||
workers = {
|
||||
total = <total number of worker threads>
|
||||
idle = <worker threads currently idle>
|
||||
active = {
|
||||
critical = <threads processing "critical" priority jobs>
|
||||
high = <threads processing "high" priority jobs>
|
||||
medium = <threads processing "medium" priority jobs>
|
||||
low = <threads processing "low" priority jobs>
|
||||
}
|
||||
}
|
||||
queues = {
|
||||
critical = <jobs queued with "critical" priority>
|
||||
high = <jobs queued with "high" priority>
|
||||
medium = <jobs queued with "medium" priority>
|
||||
low = <jobs queued with "low" priority>
|
||||
}
|
||||
scheduled = <number of jobs scheduled for timed execution>
|
||||
ikesas = {
|
||||
total = <total number of IKE_SAs active>
|
||||
half-open = <number of IKE_SAs in half-open state>
|
||||
}
|
||||
plugins = [
|
||||
<names of loaded plugins>
|
||||
]
|
||||
mem = { # available if built with leak-detective or on Windows
|
||||
total = <total heap memory usage in bytes>
|
||||
allocs = <total heap allocation blocks>
|
||||
<heap-name>* = { # on Windows only
|
||||
total = <heap memory usage in bytes by this heap>
|
||||
allocs = <allocated blocks for this heap>
|
||||
}
|
||||
}
|
||||
mallinfo = { # available with mallinfo() support
|
||||
sbrk = <non-mmaped space available>
|
||||
mmap = <mmaped space available>
|
||||
used = <total number of bytes used>
|
||||
free = <available but unused bytes>
|
||||
}
|
||||
}
|
||||
|
||||
### reload-settings() ###
|
||||
|
||||
Reloads _strongswan.conf_ settings and all plugins supporting configuration
|
||||
reload.
|
||||
|
||||
{} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### initiate() ###
|
||||
|
||||
Initiates an SA while streaming _control-log_ events.
|
||||
|
||||
{
|
||||
child = <CHILD_SA configuration name to initiate>
|
||||
timeout = <timeout in seconds before returning>
|
||||
loglevel = <loglevel to issue "control-log" events for>
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure or timeout>
|
||||
}
|
||||
|
||||
### terminate() ###
|
||||
|
||||
Terminates an SA while streaming _control-log_ events.
|
||||
|
||||
{
|
||||
child = <terminate a CHILD_SA by configuration name>
|
||||
ike = <terminate an IKE_SA by configuration name>
|
||||
child_id = <terminate a CHILD_SA by its reqid>
|
||||
ike_id = <terminate an IKE_SA by its unique id>
|
||||
timeout = <timeout in seconds before returning>
|
||||
loglevel = <loglevel to issue "control-log" events for>
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure or timeout>
|
||||
}
|
||||
|
||||
### install() ###
|
||||
|
||||
Install a trap, drop or bypass policy defined by a CHILD_SA config.
|
||||
|
||||
{
|
||||
child = <CHILD_SA configuration name to install>
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### uninstall() ###
|
||||
|
||||
Uninstall a trap, drop or bypass policy defined by a CHILD_SA config.
|
||||
|
||||
{
|
||||
child = <CHILD_SA configuration name to install>
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### list-sas() ###
|
||||
|
||||
Lists currently active IKE_SAs and associated CHILD_SAs by streaming _list-sa_
|
||||
events.
|
||||
|
||||
{
|
||||
noblock = <use non-blocking mode if key is set>
|
||||
ike = <filter listed IKE_SAs by its name>
|
||||
ike_id = <filter listed IKE_SA by its unique id>
|
||||
} => {
|
||||
# completes after streaming list-sa events
|
||||
}
|
||||
|
||||
### list-policies() ###
|
||||
|
||||
List currently installed trap, drop and bypass policies by streaming
|
||||
_list-policy_ events.
|
||||
|
||||
{
|
||||
drop = <set to yes to list drop policies>
|
||||
pass = <set to yes to list bypass policies>
|
||||
trap = <set to yes to list trap policies>
|
||||
child = <filter by CHILD_SA configuration name>
|
||||
} => {
|
||||
# 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 = <list connections matching a given configuration name only>
|
||||
} => {
|
||||
# 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 of connection names>
|
||||
]
|
||||
}
|
||||
|
||||
### 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 = <certificate type to filter for, or ANY>
|
||||
subject = <set to list only certificates having 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_SA config name> = {
|
||||
# IKE configuration parameters with authentication and CHILD_SA
|
||||
# subsections. Refer to swanctl.conf(5) for details.
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
}
|
||||
|
||||
### unload-conn() ###
|
||||
|
||||
Unload a previously loaded connection definition by name.
|
||||
|
||||
{
|
||||
name = <IKE_SA config name>
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### load-cert() ###
|
||||
|
||||
Load a certificate into the daemon.
|
||||
|
||||
{
|
||||
type = <certificate type, X509|X509CA|X509AA|X509CRL|X509AC>
|
||||
data = <PEM or DER encoded certificate data>
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### load-key() ###
|
||||
|
||||
Load a private key into the daemon.
|
||||
|
||||
{
|
||||
type = <private key type, RSA|ECDSA>
|
||||
data = <PEM or DER encoded key data>
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### load-shared() ###
|
||||
|
||||
Load a shared IKE PSK, EAP or XAuth secret into the daemon.
|
||||
|
||||
{
|
||||
type = <private key type, IKE|EAP|XAUTH>
|
||||
data = <raw shared key data>
|
||||
owners = [
|
||||
<list of shared key owner identities>
|
||||
]
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### 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 = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### load-pool() ###
|
||||
|
||||
Load an in-memory virtual IP and configuration attribute pool. Existing
|
||||
pools with the same name get updated, if possible.
|
||||
|
||||
{
|
||||
<pool name> = {
|
||||
addrs = <subnet of virtual IP pool addresses>
|
||||
<attribute type>* = [
|
||||
# attribute type is one of address, dns, nbns, dhcp, netmask,
|
||||
# server, subnet, split_include, split_exclude or a numerical
|
||||
# attribute type identifier.
|
||||
<list of attributes for type>
|
||||
]
|
||||
}
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### unload-pool() ###
|
||||
|
||||
Unload a previously loaded virtual IP and configuration attribute pool.
|
||||
Unloading fails for pools with leases currently online.
|
||||
|
||||
{
|
||||
name = <virtual IP address pool to delete>
|
||||
} => {
|
||||
success = <yes or no>
|
||||
errmsg = <error string on failure>
|
||||
}
|
||||
|
||||
### get-pools() ###
|
||||
|
||||
List the currently loaded pools.
|
||||
|
||||
{} => {
|
||||
<pool name>* = {
|
||||
base = <virtual IP pool base address>
|
||||
size = <total number of addresses in the pool>
|
||||
online = <number of leases online>
|
||||
offline = <number of leases 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 = <subsystem identifier for debug message>
|
||||
level = <log level, 0-4>
|
||||
thread = <numerical thread identifier issuing the log message>
|
||||
ikesa-name = <name of IKE_SA, if log is associated with any>
|
||||
ikesa-uniqued = <unique identifier of IKE_A, if log associated with any>
|
||||
msg = <log message text>
|
||||
}
|
||||
|
||||
### 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 = <subsystem identifier for debug message>
|
||||
level = <log level, 0-4>
|
||||
ikesa-name = <name of IKE_SA, if log associated with any>
|
||||
ikesa-uniqued = <unique identifier of IKE_A, if log associated with any>
|
||||
msg = <log message text>
|
||||
}
|
||||
|
||||
### list-sa ###
|
||||
|
||||
The _list-sa_ event is issued to stream IKE_SAs during an active _list-sas_
|
||||
command.
|
||||
|
||||
{
|
||||
<IKE_SA config name> = {
|
||||
uniqueid = <IKE_SA unique identifier>
|
||||
version = <IKE version, 1 or 2>
|
||||
state = <IKE_SA state name>
|
||||
local-host = <local IKE endpoint address>
|
||||
local-id = <local IKE identity>
|
||||
remote-host = <remote IKE endpoint address>
|
||||
remote-id = <remote IKE identity>
|
||||
remote-xauth-id = <remote XAuth identity, if XAuth-authenticated>
|
||||
remote-eap-id = <remote EAP identity, if EAP-authenticated>
|
||||
initiator = <yes, if initiator of IKE_SA>
|
||||
initiator-spi = <hex encoded initiator SPI / cookie>
|
||||
responder-spi = <hex encoded responder SPI / cookie>
|
||||
encr-alg = <IKE encryption algorithm string>
|
||||
encr-keysize = <key size for encr-alg, if applicable>
|
||||
integ-alg = <IKE integrity algorithm string>
|
||||
integ-keysize = <key size for encr-alg, if applicable>
|
||||
prf-alg = <IKE pseudo random function string>
|
||||
dh-group = <IKE Diffie-Hellman group string>
|
||||
established = <seconds the IKE_SA has been established>
|
||||
rekey-time = <seconds before IKE_SA gets rekeyed>
|
||||
reauth-time = <seconds before IKE_SA gets re-authenticated>
|
||||
tasks-queued = [
|
||||
<list of currently queued tasks for execution>
|
||||
]
|
||||
tasks-active = [
|
||||
<list of tasks currently initiating actively>
|
||||
]
|
||||
tasks-passive = [
|
||||
<list of tasks currently handling passively>
|
||||
]
|
||||
child-sas = {
|
||||
<child-sa-name>* = {
|
||||
reqid = <reqid of CHILD_SA>
|
||||
state = <state string of CHILD_SA>
|
||||
mode = <IPsec mode, tunnel|transport|beet>
|
||||
protocol = <IPsec protocol AH|ESP>
|
||||
encap = <yes if using UDP encapsulation>
|
||||
spi-in = <hex encoded inbound SPI>
|
||||
spi-out = <hex encoded outbound SPI>
|
||||
cpi-in = <hex encoded inbound CPI, if using compression>
|
||||
cpi-out = <hex encoded outbound CPI, if using compression>
|
||||
encr-alg = <ESP encryption algorithm name, if any>
|
||||
encr-keysize = <ESP encryption key size, if applicable>
|
||||
integ-alg = <ESP or AH integrity algorithm name, if any>
|
||||
integ-keysize = <ESP or AH integrity key size, if applicable>
|
||||
prf-alg = <CHILD_SA pseudo random function name>
|
||||
dh-group = <CHILD_SA PFS rekeying DH group name, if any>
|
||||
esn = <1 if using extended sequence numbers>
|
||||
bytes-in = <number of input bytes processed>
|
||||
packets-in = <number of input packets processed>
|
||||
use-in = <seconds since last inbound packet, if any>
|
||||
bytes-out = <number of output bytes processed>
|
||||
packets-out = <number of output packets processed>
|
||||
use-out = <seconds since last outbound packet, if any>
|
||||
rekey-time = <seconds before CHILD_SA gets rekeyed>
|
||||
life-time = <seconds before CHILD_SA expires>
|
||||
install-time = <seconds the CHILD_SA has been installed>
|
||||
local-ts = [
|
||||
<list of local traffic selectors>
|
||||
]
|
||||
remote-ts = [
|
||||
<list of remote traffic selectors>
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### list-policy ###
|
||||
|
||||
The _list-policy_ event is issued to stream installed policies during an active
|
||||
_list-policies_ command.
|
||||
|
||||
{
|
||||
<child-sa-config-name> = {
|
||||
mode = <policy mode, tunnel|transport|pass|drop>
|
||||
local-ts = [
|
||||
<list of local traffic selectors>
|
||||
]
|
||||
remote-ts = [
|
||||
<list of remote traffic selectors>
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
### list-conn ###
|
||||
|
||||
The _list-conn_ event is issued to stream loaded connection during an active
|
||||
_list-conns_ command.
|
||||
|
||||
{
|
||||
<IKE_SA connection name> = {
|
||||
local_addrs = [
|
||||
<list of valid local IKE endpoint addresses>
|
||||
]
|
||||
remote_addrs = [
|
||||
<list of valid remote IKE endpoint addresses>
|
||||
]
|
||||
version = <IKE version as string, IKEv1|IKEv2 or 0 for any>
|
||||
|
||||
local*, remote* = { # multiple local and remote auth sections
|
||||
class = <authentication type>
|
||||
eap-type = <EAP type to authenticate if when using EAP>
|
||||
eap-vendor = <EAP vendor for type, if any>
|
||||
xauth = <xauth backend name>
|
||||
revocation = <revocation policy>
|
||||
id = <IKE identity>
|
||||
aaa_id = <AAA authentication backend identity>
|
||||
eap_id = <EAP identity for authentication>
|
||||
xauth_id = <XAuth username for authentication>
|
||||
groups = [
|
||||
<group membership required to use connection>
|
||||
]
|
||||
certs = [
|
||||
<certificates allowed for authentication>
|
||||
]
|
||||
cacerts = [
|
||||
<CA certificates allowed for authentication>
|
||||
]
|
||||
}
|
||||
children = {
|
||||
<CHILD_SA config name>* = {
|
||||
mode = <IPsec mode>
|
||||
local-ts = [
|
||||
<list of local traffic selectors>
|
||||
]
|
||||
remote-ts = [
|
||||
<list of remote traffic selectors>
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### list-cert ###
|
||||
|
||||
The _list-cert_ event is issued to stream loaded certificates during an active
|
||||
_list-certs_ command.
|
||||
|
||||
{
|
||||
type = <certificate type>
|
||||
has_privkey = <set if a private key for the certificate is available>
|
||||
data = <ASN1 encoded certificate data>
|
||||
}
|
||||
|
||||
|
||||
# libvici C client library #
|
||||
|
||||
libvici is the reference implementation of a C client library implementing
|
||||
@@ -172,5 +680,177 @@ 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libvici.h>
|
||||
|
||||
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.
|
||||
|
||||
# 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.
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
@@ -754,11 +754,14 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
void vici_deinit()
|
||||
{
|
||||
lib->processor->cancel(lib->processor);
|
||||
library_deinit();
|
||||
}
|
||||
|
||||
@@ -75,8 +75,6 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <utils/utils.h>
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
*.gem
|
||||
*.gemspec
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,16 @@
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "vici"
|
||||
s.version = "@GEM_VERSION@"
|
||||
s.authors = ["Martin Willi"]
|
||||
s.email = ["[email protected]"]
|
||||
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
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user