Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ set(LWIP_CONTRIB_FREERTOS_DIR "${LWIP_DIR}/contrib/ports/freertos")
# link target — only the header-configured packs below do.
# https://docs.cososo.co.uk/solid-syslog/getting-started/#path-a--cmake-consumer
# Pinned to a commit until there is a release tag to pin to.
set(SOLIDSYSLOG_PLATFORMS "LwipRaw;Atomics;FreeRtos;FatFs" CACHE STRING "" FORCE)
set(SOLIDSYSLOG_PLATFORMS "LwipRaw;Atomics;FreeRtos;FatFs;MbedTls" CACHE STRING "" FORCE)

# Compile-time limits. Every tunable is #ifndef-guarded, so this file only needs
# the ones this device wants changed.
Expand Down Expand Up @@ -171,7 +171,7 @@ target_include_directories(baseline PRIVATE
# library, or context struct sizes diverge between consumer and library.
target_compile_definitions(baseline PRIVATE MBEDTLS_USER_CONFIG_FILE=${MBEDTLS_USER_CONFIG_HEADER})

target_link_libraries(baseline PRIVATE mbedtls mbedx509 mbedcrypto SolidSyslog SolidSyslog::LwipRaw SolidSyslog::FreeRtos SolidSyslog::FatFs)
target_link_libraries(baseline PRIVATE mbedtls mbedx509 mbedcrypto SolidSyslog SolidSyslog::LwipRaw SolidSyslog::FreeRtos SolidSyslog::FatFs SolidSyslog::MbedTls)

target_link_options(baseline PRIVATE
-mcpu=cortex-m3 -mthumb
Expand Down
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ It builds on a baseline that simulates the sort of device you might be adding th
measures itself: see [docs/baseline.md](docs/baseline.md) for what the baseline is, how the
figures are made, and how to run it.

## This stage — Origin address
## This stage — TLS

`origin` gains the `ip` PARAM, read from the same interface address `HOSTNAME` reports. A relay or
NAT between the device and the collector rewrites what the collector observes; this is what the
device says about itself, and it survives the hop.
Records are encrypted in transit, and the collector is authenticated before anything is sent to it.
The sender wraps its TCP stream in mbedTLS, moves to 6514, and checks the collector against the
trust anchor the device already holds.

Until now the audit trail crossed the network in cleartext — readable, and alterable, by anything
on the path.

<!-- STAGE-COST:START (generated by scripts/gen-cost-table.py — do not edit by hand) -->

**Cost above baseline: Flash +12,388 B, RAM +7,384 B.**
**Cost above baseline: Flash +13,076 B, RAM +35,664 B.**

<!-- STAGE-COST:END -->

Expand Down Expand Up @@ -47,6 +50,7 @@ committed as [`run-report.md`](run-report.md), and rewritten by every stage.
| Larger cap | headroom for the grown record, so full-width counters cannot push it into truncation | +11,980 | +9,440 |
| Smaller ring | most of the cap rise given back, now the store rather than the ring holds a backlog | +11,980 | +7,384 |
| Origin address | the device's own address in the record, which a relay or NAT between it and the collector cannot rewrite | +12,388 | +7,384 |
| TLS | a collector the device authenticates, and records no longer readable on the wire | +13,076 | +35,664 |

*Deltas are bytes above the baseline, which is itself Flash 350,308 B, RAM 111,192 B.*

Expand Down
4 changes: 2 additions & 2 deletions app/AppConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* it. Whatever deepens a seam grows it here and is charged for it. The reported
* figure is high-water usage, which does not depend on the allocation. */
#define LOG_TASK_STACK_WORDS (configMINIMAL_STACK_SIZE * 4U)
#define SERVICE_TASK_STACK_WORDS (configMINIMAL_STACK_SIZE * 4U)
#define SERVICE_TASK_STACK_WORDS (configMINIMAL_STACK_SIZE * 16U)
#define LOG_TASK_PRIORITY (tskIDLE_PRIORITY + 1U)
#define SERVICE_TASK_PRIORITY (tskIDLE_PRIORITY + 1U)

Expand All @@ -30,6 +30,6 @@
* headroom, not spare capacity: buffer_alloc hands out contiguous space, so a
* buffer only a little over the peak fails on fragmentation rather than on
* capacity. Applied again wherever more is asked of mbedTLS. */
#define SIMULATED_APP_MBEDTLS_HEAP_BYTES (32 * 1024)
#define SIMULATED_APP_MBEDTLS_HEAP_BYTES (53 * 1024)

#endif /* APP_CONFIG_H */
3 changes: 2 additions & 1 deletion app/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ static void HarnessTask(void* parameters)
* before the figures are taken. What arrived is the collector's word. */
bool logged = LogTask_EmitOnce(5000U);
(void) printf("[device] first record logged: %s\n", logged ? "yes" : "FAILED");
vTaskDelay(pdMS_TO_TICKS(500U));
/* Long enough for the TLS negotiation, not just the send. */
vTaskDelay(pdMS_TO_TICKS(3000U));

(void) Measure_Report();

Expand Down
20 changes: 16 additions & 4 deletions app/syslog/Syslog.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
/* See Syslog.h.
*
* A TCP stream over lwIP behind a circular buffer: Log enqueues and returns, and
* the service task drains and sends. The mutex is what makes those two sides
* A TLS stream over lwIP TCP behind a circular buffer: Log enqueues and returns,
* and the service task drains and sends. The mutex is what makes those two sides
* safe on different tasks.
*
* Unlike a header field, an SD PARAM has no NILVALUE: an unset one is omitted
* entirely rather than written as "-". */

#include "Syslog.h"

#include "DeviceCertStore.h"

#include "SolidSyslogBlockStore.h"
#include "SolidSyslogCircularBuffer.h"
#include "SolidSyslogConfig.h"
Expand All @@ -23,6 +25,7 @@
#include "SolidSyslogLwipRawMarshal.h"
#include "SolidSyslogLwipRawResolver.h"
#include "SolidSyslogLwipRawTcpStream.h"
#include "SolidSyslogMbedTlsStream.h"
#include "SolidSyslogMetaSd.h"
#include "SolidSyslogOriginSd.h"
#include "SolidSyslogSdValue.h"
Expand All @@ -47,7 +50,7 @@
* the resolver numeric-only — no DNS, so no LWIP_DNS and no DNS resolver
* component to compile. */
#define SYSLOG_COLLECTOR_HOST "10.0.2.2"
#define SYSLOG_COLLECTOR_PORT ((uint16_t) 5601U)
#define SYSLOG_COLLECTOR_PORT ((uint16_t) 6514U)

/* Absorbs records logged while the service task is busy sending. Many devices can
* reduce this further: the store holds the backlog, so the ring only has to cover
Expand Down Expand Up @@ -134,11 +137,20 @@ void Syslog_Start(void)

struct SolidSyslogLwipRawTcpStreamConfig tcpConfig = {.Sleep = SyslogSleep};

/* ServerName must match the name in the collector's certificate. */
struct SolidSyslogMbedTlsStreamConfig tlsConfig = {
.Transport = SolidSyslogLwipRawTcpStream_Create(&tcpConfig),
.Sleep = SyslogSleep,
.Rng = DeviceCertStore_Rng(),
.CaChain = DeviceCertStore_CaChain(),
.ServerName = SYSLOG_COLLECTOR_HOST,
};

/* No EndpointVersion — this collector never moves, so the sender resolves
* once and pins it. */
struct SolidSyslogStreamSenderConfig senderConfig = {
.Resolver = SolidSyslogLwipRawResolver_Create(),
.Stream = SolidSyslogLwipRawTcpStream_Create(&tcpConfig),
.Stream = SolidSyslogMbedTlsStream_Create(&tlsConfig),
.Address = SolidSyslogLwipRawAddress_Create(),
.Endpoint = CollectorEndpoint,
};
Expand Down
1 change: 1 addition & 0 deletions measurements/stages.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ origin Origin the device named in the record itself, not inferred from the sourc
cap-rise Larger cap headroom for the grown record, so full-width counters cannot push it into truncation
buffer-halve Smaller ring most of the cap rise given back, now the store rather than the ring holds a backlog
origin-ip Origin address the device's own address in the record, which a relay or NAT between it and the collector cannot rewrite
tls TLS a collector the device authenticates, and records no longer readable on the wire
13 changes: 13 additions & 0 deletions measurements/tls.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# tls figures (bytes) — captured by scripts/run.sh (CAPTURE=1).
# The device reads measurements/Baseline.csv as its frozen baseline and reports current-minus-Baseline.
flash_text,362736
flash_data,648
static_bss,146208
heap_used,4440
mbedtls_peak,36056
mbedtls_free,18216
lwip_mem_free,7576
lwip_pbufs_free,13
stack_log,832
stack_service,3852
stack_harness,2848
34 changes: 17 additions & 17 deletions run-report.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# solid-syslog-example — run (origin-ip)
# solid-syslog-example — run (tls)

## Device (self-measured)

Expand All @@ -10,16 +10,16 @@
[device] first record logged: yes
[report] --- SolidSyslog cost above baseline (simulated existing application) ---
[report] key,current,baseline,used_above_baseline
[report] flash_text,362056,349992,12064
[report] flash_data,640,316,324
[report] static_bss,117936,110876,7060
[report] flash_text,362736,349992,12744
[report] flash_data,648,316,332
[report] static_bss,146208,110876,35332
[report] heap_used,4440,4440,0
[report] mbedtls_peak,21280,21332,-52
[report] mbedtls_free,11488,11436,52
[report] mbedtls_peak,36056,21332,14724
[report] mbedtls_free,18216,11436,6780
[report] lwip_mem_free,7576,7576,0
[report] lwip_pbufs_free,13,14,-1
[report] stack_log,832,120,712
[report] stack_service,1044,52,992
[report] stack_service,3852,52,3800
[report] stack_harness,2848,2840,8
[report] --- end ---
[device] ready
Expand All @@ -29,7 +29,7 @@

```text
text data bss dec hex filename
362048 648 117936 480632 75578 /w/build/baseline-cross/baseline.elf
362728 656 146208 509592 7c698 /w/build/baseline-cross/baseline.elf
```

## Listeners (proved before the device ran)
Expand All @@ -47,23 +47,23 @@
## Collector (syslog-ng) received

```text
wire <134>1 2026-07-29T10:10:44.420000Z 10.0.2.15 solid-syslog-example - BOOT [meta sequenceId="1" sysUpTime="242"][timeQuality tzKnown="1" isSynced="0"][origin software="solid-syslog-example" swVersion="0.1.0" enterpriseId="32473" ip="10.0.2.15"] device started
parsed PRIORITY=134 TIMESTAMP=2026-07-29T10:10:44+00:00 HOSTNAME=10.0.2.15 APP_NAME=solid-syslog-example PROCID= MSGID=BOOT STRUCTURED_DATA=[meta sequenceId="1" sysUpTime="242"][timeQuality tzKnown="1" isSynced="0"][origin software="solid-syslog-example" swVersion="0.1.0" enterpriseId="32473" ip="10.0.2.15"] MSG=device started
wire <134>1 2026-07-29T10:34:01.430000Z 10.0.2.15 solid-syslog-example - BOOT [meta sequenceId="1" sysUpTime="243"][timeQuality tzKnown="1" isSynced="0"][origin software="solid-syslog-example" swVersion="0.1.0" enterpriseId="32473" ip="10.0.2.15"] device started
parsed PRIORITY=134 TIMESTAMP=2026-07-29T10:34:01+00:00 HOSTNAME=10.0.2.15 APP_NAME=solid-syslog-example PROCID= MSGID=BOOT STRUCTURED_DATA=[meta sequenceId="1" sysUpTime="243"][timeQuality tzKnown="1" isSynced="0"][origin software="solid-syslog-example" swVersion="0.1.0" enterpriseId="32473" ip="10.0.2.15"] MSG=device started
```

## Self-check (vs measurements/origin-ip.csv)
## Self-check (vs measurements/tls.csv)

```text
OK flash_text: 362056 (expected 362056, Δ0)
OK flash_data: 640 (expected 640, Δ0)
OK static_bss: 117936 (expected 117936, Δ0)
OK flash_text: 362736 (expected 362736, Δ0)
OK flash_data: 648 (expected 648, Δ0)
OK static_bss: 146208 (expected 146208, Δ0)
OK heap_used: 4440 (expected 4440, Δ0)
OK mbedtls_peak: 21280 (expected 21280, Δ0)
OK mbedtls_free: 11488 (expected 11488, Δ0)
OK mbedtls_peak: 36056 (expected 36056, Δ0)
OK mbedtls_free: 18216 (expected 18216, Δ0)
OK lwip_mem_free: 7576 (expected 7576, Δ0)
OK lwip_pbufs_free: 13 (expected 13, Δ0)
OK stack_log: 832 (expected 832, Δ0)
OK stack_service: 1044 (expected 1044, Δ0)
OK stack_service: 3852 (expected 3852, Δ0)
OK stack_harness: 2848 (expected 2848, Δ0)
```

Expand Down
Loading