1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
## Introduction
The transport library provides transport services and socket API for
applications willing to communicate using the hICN protocol stack.
Overview:
- Implementation of the hICN core objects (interest, data, name..) exploiting
the API provided by [libhicn](./lib.md).
- IO modules for seamlessly connecting the application to the hicn-plugin for [VPP](https://github.com/FDio/vpp) or the
[hicn-light](./hicn-light.md) forwarder.
- Transport protocols (RAAQM, CBR, RTC)
- Transport services (authentication, integrity, segmentation, reassembly,
naming)
- Interfaces for applications (from low-level interfaces for interest-data
interaction to high level interfaces for Application Data Unit interaction)
## Build dependencies
### Ubuntu
```bash
sudo apt install libasio-dev libconfig++-dev libssl-dev
```
If you wish to use the library for connecting to the vpp hicn-plugin, you will
need to also install vpp and its libraries.
```bash
# Prevent vpp to set sysctl
export VPP_INSTALL_SKIP_SYSCTL=1
VPP_VERSION=$(cat "${VERSION_PATH}" | grep VPP_DEFAULT_VERSION | cut -d ' ' -f 2 | tr -d '"' | grep -Po '\d\d.\d\d')
curl -s https://packagecloud.io/install/repositories/fdio/${VPP_VERSION//./}/script.deb.sh | bash
curl -L https://packagecloud.io/fdio/${VPP_VERSION//./}/gpgkey | apt-key add -
sed -E -i 's/(deb.*)(\[.*\])(.*)/\1\3/g' /etc/apt/sources.list.d/fdio_${VPP_VERSION//./}.list
apt-get update
apt-get install -y \
vpp-dev \
libvppinfra-dev \
vpp-plugin-core \
vpp \
libvppinfra
```
You can get them either from from the vpp packages or the source code. Check the
[VPP wiki](https://wiki.fd.io/view/VPP) for instructions.
### macOS
We recommend to use [HomeBrew](https://brew.sh/) for installing the libasio
dependency:
```bash
brew install asio libconfig openssl@1.1
```
Since VPP does not support macOS, the IO module memif is not built.
## Build the library
The library is built by default from the main CMakeLists.txt.
If you have all the dependencies installed, including [libhicn](./lib.md),
you can also build libtransport alone:
```bash
cd libtransport
mkdir build && cd build
cmake ..
cmake --build .
```
### Compile options
The build process can be customized with the following options:
- `CMAKE_INSTALL_PREFIX`: The path where you want to install the library.
- `CMAKE_BUILD_TYPE`: The build configuration. Options: `Release`, `Debug`.
Default is `Release`.
- `ASIO_HOME`: The folder containing the libasio headers.
- `VPP_HOME`: The folder containing the installation of VPP.
An option can be set using cmake -D`OPTION`=`VALUE`.
### Install the library
For installing the library, from the cmake build folder:
```bash
cmake --build . -- install
```
## Usage
Examples on how to use the library can be found in the apps folder of the project.
In particular you can check the **hiperf** application, which demonstrates
how to use the API to interact with the hicn transport, both for consumer and producer.
### Configuration file
The transport can be configured using a configuration file. There are two ways
to tell libransport where to find the configuration file:
- programmatically - you set the configuration file path in your application:
```cpp
// Set conf file path
std::string conf_file = "/opt/hicn/etc/transport.config"
// Parse config file
transport::interface::global_config::parseConfigurationFile(conf_file);
```
- using the environment variable `TRANSPORT_CONFIG`:
```bash
export TRANSPORT_CONFIG=/opt/hicn/etc/transport.config
./hiperf -C b001::1
```
Here is an example of configuration file:
```
// Configuration for io_module
io_module = {
path = [];
name = "forwarder_module";
};
// Configuration for forwarder io_module
forwarder = {
n_threads = 1;
connectors = {
c0 = {
/* local_address and local_port are optional */
local_address = "127.0.0.1";
local_port = 33436;
remote_address = "127.0.0.1";
remote_port = 33436;
}
};
listeners = {
l0 = {
local_address = "127.0.0.1";
local_port = 33437;
}
};
};
// Logging
log = {
// Log level (INFO (0), WARNING (1), ERROR (2), FATAL (3))
minloglevel = 0;
// Verbosity level for debug logs
v= 2;
// Log to stderr
logtostderr = true;
// Get fancy colored logs
colorlogtostderr = true;
// Log messages above this level also to stderr
stderrthreshold = 2;
// Set log prefix for each line log
log_prefix = true;
// Log dir
log_dir = "/tmp";
// Log only specific modules.
// Example: "membuf=2,rtc=3"
vmodule = "";
// Max log size in MB
max_log_size = 10;
// Log rotation
stop_logging_if_full_disk = true;
};
```
## Security
hICN has built-in authentication and integrity features by either:
* Cryptographically signing all packets using an asymmetric key (like RSA) or a
symmetric one (like HMAC). The latter requires that all parties have prior
access to the same key. Beware that this method is computationally expensive
and impacts max throughput and CPU usage.
* Using manifests. Manifests are special packets that holds the digests of a
group of data packets. Only the manifest needs to be signed and authenticated;
other packets are authenticated simply by verifying that their digest is
present in a manifest.
### Per-packet signatures
To enable per-packet signature with asymmetric signing:
* On the producer, disable manifests (which are ON by default):
```cpp
producer_socket->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, 0);
```
* On the producer, instantiate an `AsymmetricSigner` object by passing either an
asymmetric pair of keys as
[EVP_KEY](https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_new.html) object
or a keystore path and password as strings:
```cpp
std::shared_ptr<Signer> signer = std::make_shared<AsymmetricSigner>("./rsa.p12", "hunter2");
```
* Pass the signer object to libtransport:
```cpp
producer_socket->setSocketOption(GeneralTransportOptions::SIGNER, signer);
```
* On the consumer, instantiate an `AsymmetricVerifer` object by passing either a
certificate as a [X509](https://www.openssl.org/docs/man1.0.2/man3/x509.html)
object, an asymmetric public key as a
[EVP_KEY](https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_new.html) object
or a certificate path as a string:
```cpp
std::shared_ptr<Verifier> verifier = std::make_shared<Verifier>("./rsa.crt");
```
* Pass the verifier object to libtransport:
```cpp
consumer_socket->setSocketOption(GeneralTransportOptions::VERIFIER, verifier);
```
To enable per-packet signature with symmetric signing, follow the above steps
replacing `AsymmetricSigner` with `SymmetricSigner` and `AsymmetricVerifer` with
`SymmetricSigner`. A `SymmetricSigner` only has one constructor which expects a
`CryptoSuite` and a passphrase. A `SymmetricVerifier` also has a single
constructor which expects a passphrase:
```cpp
std::shared_ptr<Signer> signer = std::make_shared<SymmetricSigner>(CryptoSuite::HMAC_SHA256, "hunter2");
std::shared_ptr<Verifier> verifier = std::make_shared<SymmetricVerifier>("hunter2");
```
Check [Supported crypto suites](#supported-crypto-suites) for the list of
available suites.
### Enabling manifests
* Follow steps 2-5 in [Per-packet signatures](#per-packet-signatures).
* By default, a manifest holds the digest of 30 packets. To change this value:
```cpp
producer_socket->setSocketOption(GeneralTransportOptions::MAKE_MANIFEST, 20);
```
In the case of RTC, manifests are sent after the data they contain and on the
consumer side, data packets are immediately forwarded to the application, *even
if they weren't authenticated yet via a manifest*. This is to minimize latency.
The digest of incoming data packets are kept in a buffer while waiting for
manifests to arrive. When that buffer goes above a threshold `T`, an alert is
raised by the verifier object. That threshold is computed as follows:
```
T(t) = producer_rate(t) * max_unverified_time
```
`max_unverified_time` is a consumer socket option, in milliseconds. It is set
to `2000` by default. To change it:
```cpp
consumer_socket_->setSocketOption(GeneralTransportOptions::MAX_UNVERIFIED_TIME, 4000);
```
### Handling authentication failures
When a data packet fails authentication, or when the unverified buffer is full
in the case of RTC, an alert is triggered by the verifier object. By default
libtransport aborts the connection upon reception of that alert. You may want to
intercept authentication failures in your application:
* Define a callback with arguments an `uint32_t` integer, which will be set to
the suffix of the faulty packet, and a `auth::VerificationPolicy`, which will
be set to the action suggested by the verifier object. The callback must
return another `auth::VerificationPolicy` which will be the actual action
taken by libtransport:
```cpp
auth::VerificationPolicy onAuthFailed(uint32_t suffix, auth::VerificationPolicy policy) {
std::cout << "auth failed for packet " << suffix << std::endl;
return auth::VerificationPolicy::ACCEPT;
}
```
* Give that callback to your `Verifier` object as well as a list of
`auth::VerificationPolicy` to intercept (if left empty, will be set by
default to `{ABORT, DROP}`):
```cpp
verifier->setVerificationFailedCallback(&onAuthFailed, {
auth::VerificationPolicy::ABORT,
auth::VerificationPolicy::DROP,
auth::VerificationPolicy::UNKNOWN,
});
```
### Supported crypto suites
The following `CryptoSuite` are supported by libtransport:
```
ECDSA_BLAKE2B512
ECDSA_BLAKE2S256
ECDSA_SHA256
ECDSA_SHA512
RSA_BLAKE2B512
RSA_BLAKE2S256
RSA_SHA256
RSA_SHA512
HMAC_BLAKE2B512
HMAC_BLAKE2S256
HMAC_SHA256
HMAC_SHA512
DSA_BLAKE2B512
DSA_BLAKE2S256
DSA_SHA256
DSA_SHA512
```
## Logging
Internally libtransport uses glog as logging library. If you want to have a more
verbose transport log when launching a test or an app, you can set environment
variables in this way:
```
GLOG_v=4 hiperf -S b001::/64
```
For a more exhaustive list of options, please check the instructions in the glog
[README](https://github.com/google/glog#setting-flags).
Useful options include enabling logging *per module*. Also you can compile out
useless messages in release builds.
|