Code Monkey home page Code Monkey logo

davici's Introduction

davici - Decoupled Asynchronous VICI library

The strongSwan VICI interface is an RPC-like interface to configure, monitor and control the IKE daemon charon. It is implemented in the vici plugin and used by the swanctl configuration backend. VICI stands for Versatile IKE Configuration Interface, details about the protocol are provided in the strongSwan documentation.

strongSwan ships client libraries for the VICI protocol implemented in Ruby and Python, and the libvici library provides a client side implementation of the protocol in C. The libvici library, however, uses the libstrongswan base library, which is not well suited for integration in other software stacks: libstrongswan is GPLv2-licensed, so is libvici, and it makes use of threads for asynchronous event delivery.

davici is an alternative implementation of the VICI client protocol, targeting better integration in other software stacks. It uses an asynchronous, non-blocking API and can be integrated in third-party main dispatching loops without the use of threads. davici is a very low-level library intended as a foundation to build higher level control interfaces for strongSwan.

I/O dispatching and main loop integration

davici requires integration in an asynchronous I/O dispatching framework with file descriptors, such as select(), poll() or similar interfaces. Higher level main loop processing APIs can use davici as well, as long as they provide a mechanism to watch for file descriptor state changes.

When creating a VICI connection with davici, the constructor takes a davici_fdcb callback function. Any davici function may invoke the passed callback function to perform I/O dispatching registration. The callback receives a file descriptor, and a request for a set of file descriptor operations to monitor. That information must be used to add or update file descriptor watch operations using select(), poll() or similar calls.

When dispatching the passed file descriptor, the user code shall call davici_read() if the file descriptor is read-ready, and davici_write() if the file descriptor is write-ready. Both calls are non-blocking, and on failure the VICI connection shall be closed using davici_disconnect().

Use in multithreaded code

davici is not thread safe in the sense that multiple threads may operate on a single connection concurrently. It does not perform any locking. Individual threads may operate on individual connections, though, and multiple threads may also use a single connection if any call to davici functions is synchronized to a single concurrent thread.

Invoking commands

Commands are client-initiated exchanges including a request message sent by the client and a response message sent by the server. The davici_new_cmd() function creates a new and empty request message for a specific command, which then may be populated using the different functions provided by davici.

Once the request is complete (and balanced in regards to sections/lists), it may be queued for execution using davici_queue(). The provided user callback is invoked asynchronously once the server response is received or the exchange failed. If a valid response has been received, a non-negative error value is passed to the callback together with the response message. An arbitrary number of requests may be queued, but they do get executed synchronized one by one on a single connection.

Within the response callback the user may parse the response message using davici_parse() and associated functions. The function implements an iterative parser to process any kind of response message.

Streaming command response

Some commands in the VICI protocol use response streaming, that is, upon receiving a request the vici plugin starts sending related event messages. The end of the event stream is indicated by the response message matching the request.

The davici_queue_streamed() function queues a request for streamed response processing. It takes an additional event callback that is invoked for each streamed response. The event callback is also invoked for the implicit event registration with a NULL response to indicate any registration error.

As with the command response callback the user may use davici_parse() to process messages in the event callback. One may even use the same callback function for both usages, but care must be taken to properly handle the registration/deregistration invocations properly.

Event handling

To register for normal events, the davici_register() and davici_unregister() functions may be used. Both event registration and deregistration are confirmed (asynchronously) by invoking the event callback with a NULL response message. The error code indicates any failure, and should be checked in all invocations.

To parse event messages, the callback may invoke davici_parse() and related functions.

davici's People

Contributors

amitanandd avatar gonzopancho avatar martinwilli avatar tobiasbrunner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

davici's Issues

GCC11 compiler compatibility

The GCC11 compiler throws the following warning.
Requesting to make necessary changes in source code to stop the warnings.
Thank you

/strongswan/davici/davici.c:797:27: error: 'req' may be used uninitialized in this function [-Werror=maybe-uninitialized]
  797 |                 cur->next = r;
      |                 ~~~~~~~~~~^~~
/strongswan/davici/davici.c:859:32: note: 'req' was declared here
  859 |         struct davici_request *req;
      |                                ^~~
/strongswan/davici/davici.c: In function 'davici_unregister':
/strongswan/davici/davici.c:797:27: error: 'req' may be used uninitialized in this function [-Werror=maybe-uninitialized]
  797 |                 cur->next = r;
      |                 ~~~~~~~~~~^~~
/strongswan/davici/davici.c:877:32: note: 'req' was declared here
  877 |         struct davici_request *req;
      |                                ^~~

Using davici with EPOLLET

I had an issue using davici with edge-triggered epoll events. I would sometimes get two events before I could read them, and it looks like davici_read() would process one event only and return 0. But also, if there are no events left, davici_read() returns 0. It seems like either davici_read() should process events until EAGAIN, or else it should return EAGAIN if there are no events to process, so that I can call davici_read() repeatedly until EAGAIN.

Feature request: API to unload single certificate from strongswan

Currently, there is no davici API to remove just a single certificate from strongSwan.
The only way is to clear all credentials (clear-creds command) which unloads all certificates and private keys from strongswan, and then load the ones you actually want.
Refer to How to unload a particular certificate from strongswan.

This is a limitation, because when a certificate is unloaded, all traffic must be re-started, even is the certificate is not being used at all.

Is it possible to improve davici library to get rid of this limitation ?

Thanks in advance,
Alex

Running the test suite in parallel causes flaky test behavior

Running the test suite in parallel (using make -j16 check) causes tests to randomly fail.

The log files of the failing tests contain this error:

event.tst: tester.c:79: tester_create: Assertion `bind(t->pfd[FD_LISTEN].fd, (struct sockaddr*)&addr, len) == 0' failed.
FAIL event.tst (exit status: 134)

As far as I could debug the issue, this may be caused by multiple tests trying to bind to the same unix socket /tmp/test.vici, as defined in tester_create, line 64. A possible solution might be to use a different unix socket per test.

davici_queue_streamed - unit test example generates VICI errors in strongswan.log

I am working on a davici based application that implements a "list-sas" command using the process structure found in the unit test stream.c:

  1. davici_connect_unix
  2. davici_new_cmd
  3. davici_queue_streamed
  4. runio
  5. davici_disconnect

When invoked, I am seeing VICI errors in strongswan.log when there are no security associations:

  • 10[CFG] vici header: read error: Connection reset by peer
  • 10[CFG] vici header: write error: Broken pipe

Strongswan 5.6.2
davici 1.3 + Davici GitHub isprint() patch

On tracing this streamed process, davici_queue_streamed creates three requests DAVICI_CMD_REQUEST, DAVICI_EVENT_REGISTER, DAVICI_EVENT_UNREGISTER but runio processing fails to remove DAVICI_EVENT_UNREGISTER before closing the connection - davici encounters a DAVICI_END condition that closes the connection before StrongSwan can send the last part of the message.

It feels like the example code is a cutdown version of the process that works for testing but fails when used as a template in real code because the DAVICI_END condition is prematurely generated before the entire response message has been received.

Are there any other code examples that implement davici_queue_streamed in a way that can be scaled for production code?

  • There is almost no documentation that describes how applications should implement davici based interfaces.
  • The VICI protocol web page describes the message elements but not the message segments sent by StrongSwan.

My best guess (so far) at the cause is that the request should include SECTION_START and SECTION END so that the connection is not closed early, and that the errors are indicative of StrongSwan being unable to send the final part of the message.

How to get ipsec information correctly

I want to achieve the result of swanctl --list-sas, the code to get the return value is null

`static int query_list_sa(struct dispatch_data *dd)
{
struct davici_request *r;
int err;

err = davici_new_cmd("list-sas", &r);
if (err < 0)
{
return err;
}
log_info("%s %d", FILE, LINE);

// davici_kvf(r, "noblock", "%s", "no");
err = davici_queue(dd->c, r, list_sa_cb, dd);
if (err < 0)
{
return err;
}
log_info("%s %d", FILE, LINE);
dd->pending++;
return 0;
}`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.