Librasta & Libsci
A C implementation of the RaSTA protocol stack
|
In this tutorial, you will learn how to deploy and use the RaSTA C library. This tutorial is written for Linux. If you are using another operating system, the commands should be similar.
The following dependencies are required for building the RaSTA library and binaries:
libcunit1-dev
or similar)ENABLE_RASTA_OPAQUE
is enabled: libsodium (packages libsodium-dev
and pkgconf
or similar)ENABLE_RASTA_TLS
is enabled: WolfSSL (package wolfssl
or similar).BUILD_RASTA_GRPC_BRIDGE
is enabled: gRPC (package grpc
or similar)We tested with WolfSSL version 5.2.0-stable and gRPC version 1.47.0. For other versions, we cannot guarantee that you will be able to build the library.
For debug purposes (if you want to dissect recorded TLS traffic with Wireshark), it can be useful to enable the secret callback of WolfSSL, which gives you access to the TLS connection secrets. For this, WolfSSL needs to be built manually with the configuration flags --enable-dtls --enable-debug --enable-certgen --enable-tls13 CFLAGS="-DHAVE_SECRET_CALLBACK" --enable-opensslextra
.
We provide a number of build options, of which the following are the most important:
BUILD_DOCUMENTATION
: use Doxygen to build an HTML documentation for the libraryBUILD_LOCAL_EXAMPLES
: build the examples described in part 2BUILD_RASTA_GRPC_BRIDGE
: build the RaSTA/gRPC bridge described in part 2ENABLE_RASTA_TLS
: include the TLS and DTLS transport implementations in the library that will be builtENABLE_RASTA_OPAQUE
: include the Kex/OPAQUE implementation in the library that will be builtFor the actual build process, we use CMake (>= 3.18). With the following commands, you can build the library and binaries:
You will get one library file for each transport implementation you selected (TCP/UDP/TLS/DTLS), named librasta_{protocol}.so
. To install the library files on the system, you may use make install
, if needed (might need root privileges).
Note that on ARM systems, our default MD4 implementation does not work correctly, so you should use OpenSSL/libcrypto
as a replacement. In this case, enable USE_OPENSSL
.
The RaSTA C library comes with some simple examples to show the use of the library. The following examples are included:
r
to start in server (receiver) mode and s
to start in client (sender) mode. Note that these examples should be run from a folder containing the config files rasta_server_local{_tls,_dtls}.cfg
and rasta_client_local{_tls,_dtls}.cfg
.This bridge forwards messages between a RaSTA connection and a gRPC connection. It takes the following commandline arguments:
When implementing a server or client able to communicate with the bridge, you must implement (or call) the RPC Stream()
defined in rasta.proto
, which takes a stream of bytes and returns a stream of bytes, both corresponding to the data sent on the RaSTA connection. Note that you must not end this stream while your program runs and wants to send/receive data on this connection, because otherwise, the RaSTA connection will be disconnected and currently cannot be recreated without restarting the bridge.
We provide Dockerfiles to create images containing the gRPC bridge and all dependencies (see the docker/rasta_grpc_bridge
folder). There are also prebuilt images available, which can be found in the "Packages" section of the GitHub repository.
You learned to compile the sources and run the example programs, now it's time to write your own program! In this section the various functions and some other things are listed and explained.
The complete functionality of the library can be used by including rasta.h
.
Name | Description |
---|---|
rasta_lib_init_configuration | initializes a provide user_configuration with a RaSTA configuration, logger and connection configurations. |
rasta_bind /rasta_listen /rasta_accept | on the server side, these functions bind to, listen on and accept connections on the configured sockets. |
rasta_connect | on the client side, this connects to another RaSTA entity. You have to pass the ID of the remote entity as parameter. |
rasta_send | sends a message to a connected entity (connect with rasta_connect ) on the passed connection. |
rasta_recv | gets the first message (i.e. the application message that arrived first in regard to time and order in the RaSTA PDU) from the receive buffer of the passed connection. If the buffer is empty, this call will block until an application message is available. |
rasta_disconnect | sends a disconnection request to the passed RaSTA connection and closes this connection. |
rasta_cleanup | cleans up allocated ressources etc. Call this at the end of you program to avoid memory leak and some other problems (see Further Information) |
The notifications are an easy way to react to events that occur during the protocol flow. Notifications are basically function pointers which you can set. The functions will be called when the respective event occurs. The notification functions have to be assigned in an initialized handle (handle.notifications
).
Note: Notifications are currently not working (i.e., commented out in the code)!
This is a list of all available notifications.
Name | Event |
---|---|
on_receive | an application message has been received an is available in the buffer |
on_disconnection_request_received | a disconnection request has been received and the connection is closed. You can access the reason and details here! |
on_connection_state_change | the state of the connection has changed |
on_diagnostic_notification | diagnose data of the send-/retransmission layer is available |
on_redundancy_diagnostic_notification | diagnose data of the redundancy layer is available |
In general, the configuration can be specified in a configuration file. In the configuration file, the RaSTA protocol parameters as well as some miscellaneous options like logging can be configured. Every option is documented in the example config files and their meaning should be easily understandable. The only one that is a bit more tricky is RASTA_REDUNDANCY_CONNECTIONS
. This option is used to specify the network interfaces and ports where the RaSTA entity will listen on. The format is an array of strings with format IP:Port
where the IP corresponds to the IP address a network interface is bound to. If you, for whatever reason, want to listen on any interface, use 0.0.0.0
as the IP. Note that the send-behaviour in this case might not work as you expect (which interface sends the PDUs)!
If you want to get a network interfaces associated IP address by its name (e.g. eth0
), for example because the IP is assigned dynamically with DHCP, have a look at the system function getifaddrs
from ifaddrs.h
. See the Manpage for more information. However, you can't use the configuration file in this case. Use the manual configuration instead.