Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Implement defender metrics #70

Merged
merged 22 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7fc002b
Initial structure of defender metrics
KennethKnudsen97 Dec 23, 2024
ae63c48
metric structure and tests
KennethKnudsen97 Dec 27, 2024
f28e3d1
generic custom metric
KennethKnudsen97 Jan 2, 2025
d76a514
Change Custom metric to use references
KennethKnudsen97 Jan 6, 2025
f631a8c
aws types with references
KennethKnudsen97 Jan 6, 2025
a58a660
impl tuple for Version
KennethKnudsen97 Jan 6, 2025
09ef37a
remove timestamp as argument for function in custom metric
KennethKnudsen97 Jan 6, 2025
817caf7
include aws metrics and use bon crate for building metric struct
KennethKnudsen97 Jan 6, 2025
825e5a0
error handling
KennethKnudsen97 Jan 14, 2025
2707cd7
error handling
KennethKnudsen97 Jan 16, 2025
8418ee6
error handling
KennethKnudsen97 Jan 21, 2025
3f9fe06
Merge branch 'feature/async' into feature/defender_metrics
KennethKnudsen97 Jan 21, 2025
042db28
feature flag for cbor and temp fix for Header serialize
KennethKnudsen97 Feb 3, 2025
0089ca9
smal changes
KennethKnudsen97 Feb 4, 2025
985ca38
String list example
KennethKnudsen97 Feb 5, 2025
ca5f8ce
Metric integration test
KennethKnudsen97 Feb 5, 2025
092ea92
Update src/defender_metrics/data_types.rs
KennethKnudsen97 Feb 7, 2025
bcdab34
Cargo clippy and unit test
KennethKnudsen97 Feb 7, 2025
fcce0f3
Merge branch 'feature/defender_metrics' of github.com:BlackbirdHQ/rus…
KennethKnudsen97 Feb 7, 2025
b1e6c35
cargo clippy fix
KennethKnudsen97 Feb 7, 2025
fa66a9c
fixed unit test and version serialization
KennethKnudsen97 Feb 7, 2025
caec287
fix test
KennethKnudsen97 Feb 7, 2025
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
5 changes: 3 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.allTargets": true,
"rust-analyzer.cargo.features": ["log"],
"rust-analyzer.cargo.target": "x86_64-unknown-linux-gnu"
"rust-analyzer.cargo.target": "x86_64-unknown-linux-gnu",

}
13 changes: 9 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ embassy-futures = "0.1"

log = { version = "0.4", default-features = false, optional = true }
defmt = { version = "0.3", optional = true }
bon = { version = "3.3.2", default-features = false }

[dev-dependencies]
native-tls = { version = "0.2" }
Expand All @@ -62,16 +63,19 @@ tokio = { version = "1.33", default-features = false, features = [
] }
tokio-native-tls = { version = "0.3.1" }
embassy-futures = { version = "0.1.0" }
embassy-time = { version = "0.4", features = ["log", "std", "generic-queue"] }
embassy-time = { version = "0.4", features = ["log", "std", "generic-queue-8"] }
embedded-io-adapters = { version = "0.6.0", features = ["tokio-1"] }

ecdsa = { version = "0.16", features = ["pkcs8", "pem"] }
p256 = "0.13"
pkcs8 = { version = "0.10", features = ["encryption", "pem"] }
hex = { version = "0.4.3", features = ["alloc"] }


[features]
default = ["ota_mqtt_data", "provision_cbor"]
default = ["ota_mqtt_data", "metric_cbor", "provision_cbor"]

metric_cbor = ["dep:minicbor", "dep:minicbor-serde"]

provision_cbor = ["dep:minicbor", "dep:minicbor-serde"]

Expand All @@ -89,5 +93,6 @@ defmt = [
]
log = ["dep:log", "embedded-mqtt/log"]

# [patch."ssh://[email protected]/FactbirdHQ/embedded-mqtt"]
# embedded-mqtt = { path = "../embedded-mqtt" }

[patch."ssh://git@github.com/FactbirdHQ/embedded-mqtt"]
embedded-mqtt = { path = "../embedded-mqtt" }
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[toolchain]
channel = "nightly-2024-07-17"
channel = "nightly-2024-09-06"
components = ["rust-src", "rustfmt", "llvm-tools"]
targets = [
"x86_64-unknown-linux-gnu",
Expand Down
81 changes: 81 additions & 0 deletions src/defender_metrics/aws_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use serde::Serialize;

#[derive(Debug, Serialize)]
pub struct TcpConnections<'a> {
#[serde(rename = "ec")]
pub established_connections: Option<&'a EstablishedConnections<'a>>,
}

#[derive(Debug, Serialize)]
pub struct EstablishedConnections<'a> {
#[serde(rename = "cs")]
pub connections: Option<&'a [&'a Connection<'a>]>,

#[serde(rename = "t")]
pub total: Option<u64>,
}

#[derive(Debug, Serialize)]
pub struct Connection<'a> {
#[serde(rename = "rad")]
pub remote_addr: &'a str,

/// Port number, must be >= 0
#[serde(rename = "lp")]
pub local_port: Option<u16>,

/// Interface name
#[serde(rename = "li")]
pub local_interface: Option<&'a str>,
}

#[derive(Debug, Serialize)]
pub struct ListeningTcpPorts<'a> {
#[serde(rename = "pts")]
pub ports: Option<&'a [&'a TcpPort<'a>]>,

#[serde(rename = "t")]
pub total: Option<u64>,
}

#[derive(Debug, Serialize)]
pub struct TcpPort<'a> {
#[serde(rename = "pt")]
pub port: u16,

#[serde(rename = "if")]
pub interface: Option<&'a str>,
}

#[derive(Debug, Serialize)]
pub struct ListeningUdpPorts<'a> {
#[serde(rename = "pts")]
pub ports: Option<&'a [&'a UdpPort<'a>]>,

#[serde(rename = "t")]
pub total: Option<u64>,
}

#[derive(Debug, Serialize)]
pub struct UdpPort<'a> {
#[serde(rename = "pt")]
pub port: u16,

#[serde(rename = "if")]
pub interface: Option<&'a str>,
}

#[derive(Debug, Serialize)]
pub struct NetworkStats {
#[serde(rename = "bi")]
pub bytes_in: Option<u64>,

#[serde(rename = "bo")]
pub bytes_out: Option<u64>,

#[serde(rename = "pi")]
pub packets_in: Option<u64>,

#[serde(rename = "po")]
pub packets_out: Option<u64>,
}
95 changes: 95 additions & 0 deletions src/defender_metrics/data_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use core::fmt::Display;

use bon::Builder;
use embassy_time::Instant;
use serde::{ser::SerializeStruct, Serialize};

use super::aws_types::{ListeningTcpPorts, ListeningUdpPorts, NetworkStats, TcpConnections};

#[derive(Debug, Serialize, Builder)]
pub struct Metric<'a, C: Serialize> {
#[serde(rename = "hed")]
pub header: Header,

#[serde(rename = "met")]
pub metrics: Option<Metrics<'a>>,

#[serde(rename = "cmet")]
pub custom_metrics: Option<C>,
}

#[derive(Debug, Serialize)]
pub struct Metrics<'a> {
listening_tcp_ports: Option<ListeningTcpPorts<'a>>,
listening_udp_ports: Option<ListeningUdpPorts<'a>>,
network_stats: Option<NetworkStats>,
tcp_connections: Option<TcpConnections<'a>>,
}

#[derive(Debug)]
pub struct Header {
/// Monotonically increasing value. Epoch timestamp recommended.
// #[serde(rename = "rid")]
KennethKnudsen97 marked this conversation as resolved.
Show resolved Hide resolved
pub report_id: i64,

/// Version in Major.Minor format.
// #[serde(rename = "v")]
pub version: Version,
}

impl Serialize for Header {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut serializer = serializer.serialize_struct("Header", 2)?;

serializer.serialize_field("rid", &self.report_id)?;
serializer.serialize_field("version", "1.0")?;
KennethKnudsen97 marked this conversation as resolved.
Show resolved Hide resolved

serializer.end()
}
}

impl Default for Header {
fn default() -> Self {
Self {
report_id: Instant::now().as_millis() as i64,
version: Default::default(),
}
}
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum CustomMetric<'a> {
Number(i64),
NumberList(&'a [u64]),
StringList(&'a [&'a str]),
IpList(&'a [&'a str]),
}

/// Format is `Version(Majo, Minor)`
KennethKnudsen97 marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Debug)]
pub struct Version(u8, u8);

impl Serialize for Version {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.collect_str(&self)
}
}

impl Display for Version {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}.{}", self.0, self.1,)
}
}

impl Default for Version {
fn default() -> Self {
Self(1, 0)
}
}
KennethKnudsen97 marked this conversation as resolved.
Show resolved Hide resolved
29 changes: 29 additions & 0 deletions src/defender_metrics/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ErrorResponse<'a> {
#[serde(rename = "thingName")]
pub thing_name: &'a str,
pub status: &'a str,
#[serde(rename = "statusDetails")]
pub status_details: StatusDetails<'a>,
pub timestamp: i64,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StatusDetails<'a> {
#[serde(rename = "ErrorCode")]
pub error_code: MetricError,
#[serde(rename = "ErrorMessage")]
pub error_message: Option<&'a str>,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MetricError {
Malformed,
InvalidPayload,
Throttled,
MissingHeader,
Other,
}
Loading
Loading