From b381261ceadc3a6d2a881f61a4817573cbad6f7a Mon Sep 17 00:00:00 2001
From: Andrew Rioux
Date: Thu, 30 Jan 2025 20:59:14 -0500
Subject: [PATCH] feat: added most beacon DS and listener CRUD
---
Cargo.lock | 33 +++
sparse-server/Cargo.toml | 2 +
.../migrations/20250130040842_add_beacons.sql | 121 ++++++++++
sparse-server/src/app.rs | 20 +-
sparse-server/src/beacon_handler.rs | 10 +
sparse-server/src/beacons.rs | 54 +++++
sparse-server/src/beacons/categories.rs | 13 +
sparse-server/src/beacons/commands.rs | 10 +
sparse-server/src/beacons/configs.rs | 10 +
sparse-server/src/beacons/instances.rs | 10 +
sparse-server/src/beacons/listeners.rs | 226 ++++++++++++++++++
sparse-server/src/beacons/templates.rs | 10 +
sparse-server/src/lib.rs | 10 +-
sparse-server/src/main.rs | 16 +-
sparse-server/src/users.rs | 2 +-
sparse-server/src/webserver.rs | 6 +-
sparse-server/style/_beacons.scss | 38 +++
sparse-server/style/_main.scss | 11 +
sparse-server/style/beacons/_categories.scss | 0
sparse-server/style/beacons/_commands.scss | 0
sparse-server/style/beacons/_configs.scss | 0
sparse-server/style/beacons/_instances.scss | 0
sparse-server/style/beacons/_listeners.scss | 14 ++
sparse-server/style/beacons/_templates.scss | 0
sparse-server/style/main.scss | 5 +
unix-loader/src/abi.h | 4 +-
26 files changed, 599 insertions(+), 26 deletions(-)
create mode 100644 sparse-server/migrations/20250130040842_add_beacons.sql
create mode 100644 sparse-server/src/beacon_handler.rs
create mode 100644 sparse-server/src/beacons.rs
create mode 100644 sparse-server/src/beacons/categories.rs
create mode 100644 sparse-server/src/beacons/commands.rs
create mode 100644 sparse-server/src/beacons/configs.rs
create mode 100644 sparse-server/src/beacons/instances.rs
create mode 100644 sparse-server/src/beacons/listeners.rs
create mode 100644 sparse-server/src/beacons/templates.rs
create mode 100644 sparse-server/style/_beacons.scss
create mode 100644 sparse-server/style/beacons/_categories.scss
create mode 100644 sparse-server/style/beacons/_commands.scss
create mode 100644 sparse-server/style/beacons/_configs.scss
create mode 100644 sparse-server/style/beacons/_instances.scss
create mode 100644 sparse-server/style/beacons/_listeners.scss
create mode 100644 sparse-server/style/beacons/_templates.scss
diff --git a/Cargo.lock b/Cargo.lock
index fecdbcd..b09152d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2191,6 +2191,16 @@ dependencies = [
"tokio-stream",
]
+[[package]]
+name = "pem"
+version = "3.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae"
+dependencies = [
+ "base64",
+ "serde",
+]
+
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
@@ -2430,6 +2440,19 @@ dependencies = [
"getrandom",
]
+[[package]]
+name = "rcgen"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2"
+dependencies = [
+ "pem",
+ "ring",
+ "rustls-pki-types",
+ "time",
+ "yasna",
+]
+
[[package]]
name = "reactive_graph"
version = "0.1.4"
@@ -2971,6 +2994,7 @@ dependencies = [
"leptos_meta",
"leptos_router",
"pbkdf2",
+ "rcgen",
"rpassword",
"serde",
"sha2",
@@ -4291,6 +4315,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
+[[package]]
+name = "yasna"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
+dependencies = [
+ "time",
+]
+
[[package]]
name = "yoke"
version = "0.7.5"
diff --git a/sparse-server/Cargo.toml b/sparse-server/Cargo.toml
index 0be0c2b..250d7f6 100644
--- a/sparse-server/Cargo.toml
+++ b/sparse-server/Cargo.toml
@@ -39,6 +39,7 @@ sha2 = { version = "0.10", optional = true }
hex = { version = "0.4", optional = true }
serde = "1.0"
cfg-if = "1.0.0"
+rcgen = { version = "0.13.2", optional = true }
[features]
hydrate = ["leptos/hydrate", "chrono/wasmbind"]
@@ -60,6 +61,7 @@ ssr = [
"dep:pbkdf2",
"dep:sha2",
"dep:hex",
+ "dep:rcgen",
"leptos/ssr",
"leptos_meta/ssr",
"leptos_router/ssr",
diff --git a/sparse-server/migrations/20250130040842_add_beacons.sql b/sparse-server/migrations/20250130040842_add_beacons.sql
new file mode 100644
index 0000000..24efdea
--- /dev/null
+++ b/sparse-server/migrations/20250130040842_add_beacons.sql
@@ -0,0 +1,121 @@
+CREATE TABLE beacon_listener (
+ listener_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+
+ port int NOT NULL,
+ public_ip varchar NOT NULL,
+ domain_name varchar NOT NULL,
+ certificate varchar NOT NULL,
+ privkey varchar NOT NULL
+);
+
+CREATE TABLE beacon_config (
+ config_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+
+ mode text check (mode in ('single', 'regular', 'random', 'cron')),
+
+ regular_interval int,
+
+ random_min_time int,
+ random_max_time int,
+
+ cron_schedule varchar
+);
+
+CREATE TABLE beacon_category (
+ category_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+ category_name varchar NOT NULL
+);
+
+CREATE TABLE beacon_template (
+ template_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+ template_name varchar NOT NULL,
+ operating_system varchar NOT NULL,
+ config_id int NOT NULL,
+ listener_id int NOT NULL,
+
+ source_ip varchar NOT NULL,
+ source_mac varchar,
+ source_mode text check (source_mode in ('host', 'custom')),
+ source_netmask int,
+ source_gateway varchar,
+
+ FOREIGN KEY (config_id) REFERENCES beacon_config
+ FOREIGN KEY (listener_id) REFERENCES beacon_listener
+);
+
+CREATE TABLE beacon_instance (
+ beacon_id varchar PRIMARY KEY NOT NULL,
+ template_id int NOT NULL,
+ peer_ip varchar NOT NULL,
+ nickname varchar NOT NULL,
+
+ cwd varchar NOT NULL,
+ operating_system varchar NOT NULL,
+ beacon_userent varchar NOT NULL,
+ hostname varchar NOT NULL,
+
+ FOREIGN KEY (template_id) REFERENCES beacon_template
+);
+
+CREATE TABLE beacon_category_assignment (
+ category_id int,
+ beacon_id varchar,
+
+ PRIMARY KEY (category_id, beacon_id),
+
+ FOREIGN KEY (category_id) REFERENCES beacon_category,
+ FOREIGN KEY (beacon_id) REFERENCES beacon_instance
+);
+
+CREATE TABLE beacon_config_assignment (
+ config_id int,
+ beacon_id varchar,
+
+ PRIMARY KEY (config_id, beacon_id),
+
+ FOREIGN KEY (config_id) REFERENCES beacon_config,
+ FOREIGN KEY (beacon_id) REFERENCES beacon_instance
+);
+
+CREATE TABLE beacon_command (
+ command_id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+
+ cmd_type text check (cmd_type in ('update', 'exec', 'install', 'upload', 'download', 'reload_config', 'chdir', 'ls')),
+
+ exec_command varchar,
+
+ install_target varchar,
+
+ upload_src varchar,
+ upload_dest varchar,
+
+ download_path varchar,
+
+ config_id int,
+
+ FOREIGN KEY (config_id) REFERENCES beacon_config
+);
+
+CREATE TABLE beacon_command_invocation (
+ beacon_id varchar NOT NULL,
+ command_id int NOT NULL,
+
+ invoker_id int NOT NULL,
+
+ invocation_date int,
+ invocation_result varchar,
+
+ PRIMARY KEY (beacon_id, command_id),
+
+ FOREIGN KEY (command_id) REFERENCES beacon_command,
+ FOREIGN KEY (beacon_id) REFERENCES beacon_instance,
+ FOREIGN KEY (invoker_id) REFERENCES users
+);
+
+CREATE TABLE beacon_checkin (
+ beacon_id varchar NOT NULL,
+
+ checkin_date int,
+
+ FOREIGN KEY (beacon_id) REFERENCES beacon_instance
+);
diff --git a/sparse-server/src/app.rs b/sparse-server/src/app.rs
index 460a589..a3423cd 100644
--- a/sparse-server/src/app.rs
+++ b/sparse-server/src/app.rs
@@ -1,7 +1,7 @@
use leptos::prelude::*;
use leptos_meta::{provide_meta_context, MetaTags, Stylesheet, Title};
use leptos_router::{
- components::{A, Route, Router, Routes},
+ components::{A, ParentRoute, Route, Router, Routes},
hooks::use_query_map,
path
};
@@ -30,12 +30,8 @@ pub struct User {
#[server]
pub async fn me() -> Result
+ }/>
+
diff --git a/sparse-server/src/beacon_handler.rs b/sparse-server/src/beacon_handler.rs
new file mode 100644
index 0000000..0e78f38
--- /dev/null
+++ b/sparse-server/src/beacon_handler.rs
@@ -0,0 +1,10 @@
+use std::{
+ collections::HashMap,
+ sync::{Arc, RwLock},
+};
+
+use tokio::task::JoinHandle;
+
+pub type BeaconListenerHandle = JoinHandle<()>;
+
+pub type BeaconListenerMap = Arc>>;
diff --git a/sparse-server/src/beacons.rs b/sparse-server/src/beacons.rs
new file mode 100644
index 0000000..3e12803
--- /dev/null
+++ b/sparse-server/src/beacons.rs
@@ -0,0 +1,54 @@
+use leptos::prelude::*;
+use leptos_router::{components::A, nested_router::Outlet};
+
+mod categories;
+mod commands;
+mod configs;
+mod instances;
+mod listeners;
+mod templates;
+
+pub use categories::CategoriesView;
+pub use commands::CommandsView;
+pub use configs::ConfigsView;
+pub use instances::InstancesView;
+pub use listeners::ListenersView;
+pub use templates::TemplatesView;
+
+#[component]
+pub fn BeaconView() -> impl IntoView {
+ #[cfg(feature = "hydrate")]
+ Effect::new(move || {
+ let user = expect_context::>>();
+ if user.get().is_none() {
+ let navigate = leptos_router::hooks::use_navigate();
+ navigate("/login?next=beacons", Default::default());
+ }
+ });
+
+ view! {
+
+
+
+
+
+ }
+}
+
+#[component]
+pub fn BeaconSidebar() -> impl IntoView {
+ view! {
+
+ }
+}
diff --git a/sparse-server/src/beacons/categories.rs b/sparse-server/src/beacons/categories.rs
new file mode 100644
index 0000000..3f5daa6
--- /dev/null
+++ b/sparse-server/src/beacons/categories.rs
@@ -0,0 +1,13 @@
+use leptos::prelude::*;
+
+#[component]
+pub fn CategoriesView() -> impl IntoView {
+ view! {
+
+ }
+}
diff --git a/sparse-server/src/beacons/commands.rs b/sparse-server/src/beacons/commands.rs
new file mode 100644
index 0000000..7614124
--- /dev/null
+++ b/sparse-server/src/beacons/commands.rs
@@ -0,0 +1,10 @@
+use leptos::prelude::*;
+
+#[component]
+pub fn CommandsView() -> impl IntoView {
+ view! {
+
+
+
+ }
+}
diff --git a/sparse-server/src/beacons/configs.rs b/sparse-server/src/beacons/configs.rs
new file mode 100644
index 0000000..87a07d8
--- /dev/null
+++ b/sparse-server/src/beacons/configs.rs
@@ -0,0 +1,10 @@
+use leptos::prelude::*;
+
+#[component]
+pub fn ConfigsView() -> impl IntoView {
+ view! {
+
+
+
+ }
+}
diff --git a/sparse-server/src/beacons/instances.rs b/sparse-server/src/beacons/instances.rs
new file mode 100644
index 0000000..4cae020
--- /dev/null
+++ b/sparse-server/src/beacons/instances.rs
@@ -0,0 +1,10 @@
+use leptos::prelude::*;
+
+#[component]
+pub fn InstancesView() -> impl IntoView {
+ view! {
+
+
+
+ }
+}
diff --git a/sparse-server/src/beacons/listeners.rs b/sparse-server/src/beacons/listeners.rs
new file mode 100644
index 0000000..c80ddd2
--- /dev/null
+++ b/sparse-server/src/beacons/listeners.rs
@@ -0,0 +1,226 @@
+use std::net::Ipv4Addr;
+
+use leptos::{either::Either, prelude::*};
+use serde::{Serialize, Deserialize};
+#[cfg(feature = "ssr")]
+use {
+ sqlx::SqlitePool,
+ leptos::server_fn::error::NoCustomError,
+ crate::{db::user, beacon_handler::BeaconListenerMap},
+ rcgen::{generate_simple_self_signed, CertifiedKey},
+};
+
+#[cfg(feature = "ssr")]
+struct DbListener {
+ listener_id: i64,
+ port: i64,
+ public_ip: String,
+ domain_name: String
+}
+
+#[derive(Clone, Serialize, Deserialize)]
+pub struct PubListener {
+ listener_id: i64,
+ port: i64,
+ public_ip: String,
+ domain_name: String,
+ active: bool
+}
+
+#[server]
+pub async fn get_listeners() -> Result, ServerFnError> {
+ let user = user::get_auth_session().await?;
+
+ if user.is_none() {
+ return Err(ServerFnError::::ServerError("You are not signed in!".to_owned()));
+ }
+
+ let db = expect_context::();
+ let beacon_handles = expect_context::();
+
+ let listeners = sqlx::query_as!(
+ DbListener,
+ "SELECT listener_id, port, public_ip, domain_name FROM beacon_listener"
+ )
+ .fetch_all(&db)
+ .await?;
+
+ let Ok(beacon_handles_handle) = beacon_handles.read() else {
+ return Err(ServerFnError::::ServerError("".to_string()));
+ };
+
+ Ok(listeners
+ .into_iter()
+ .map(|b| PubListener {
+ listener_id: b.listener_id,
+ port: b.port,
+ public_ip: b.public_ip,
+ domain_name: b.domain_name,
+ active: beacon_handles_handle
+ .get(&b.listener_id)
+ .map(|h| !h.is_finished())
+ .unwrap_or(false)
+ })
+ .collect())
+}
+
+#[server]
+pub async fn add_listener(public_ip: String, port: i16, domain_name: String) -> Result<(), ServerFnError> {
+ let user = user::get_auth_session().await?;
+
+ if user.is_none() {
+ return Err(ServerFnError::::ServerError("You are not signed in!".to_owned()));
+ }
+
+ if public_ip.parse::().is_err() {
+ return Err(ServerFnError::::ServerError("Unable to parse public IP address".to_owned()));
+ }
+
+ let subject_alt_names = vec![public_ip.to_string(), domain_name.clone()];
+ let CertifiedKey { cert, key_pair } = tokio::task::spawn_blocking(|| {
+ generate_simple_self_signed(subject_alt_names)
+ }).await??;
+
+ let db = expect_context::();
+
+ let public_ip = public_ip.to_string();
+ let cert = cert.pem().to_string();
+ let key_pair = key_pair.serialize_pem().to_string();
+
+ sqlx::query!(
+ "INSERT INTO beacon_listener (port, public_ip, domain_name, certificate, privkey) VALUES (?, ?, ?, ?, ?)",
+ port,
+ public_ip,
+ domain_name,
+ cert,
+ key_pair
+ )
+ .execute(&db)
+ .await?;
+
+ Ok(())
+}
+
+#[server]
+pub async fn start_listener(listener_id: i64) -> Result<(), ServerFnError> {
+ unimplemented!()
+}
+
+#[component]
+pub fn ListenersView() -> impl IntoView {
+ let add_listener = ServerAction::::new();
+
+ let listeners = Resource::new(
+ move || add_listener.version().get(),
+ |_| async { get_listeners().await }
+ );
+
+ view! {
+
+ }
+}
+
+#[component]
+fn DisplayListeners(listener_resource: Resource, ServerFnError>>, listeners: Vec) -> impl IntoView {
+ let (error_msg, set_error_msg) = signal(None);
+ let start_listener_action = Action::new(move |&id: &i64| async move {
+ match start_listener(id).await {
+ Ok(()) => {
+ listener_resource.refetch();
+ }
+ Err(e) => {
+ set_error_msg(Some(e.to_string()));
+ }
+ }
+ });
+
+ let listeners_view = listeners
+ .iter()
+ .map(|listener| view! {
+
+ {listener.listener_id}
+ ": "
+ {listener.domain_name.clone()}
+ " ("
+ {listener.public_ip.clone()}
+ ":"
+ {listener.port}
+ ")"
+ {match listener.active {
+ true => Either::Left(view! {
+ "active!"
+ }),
+ false => Either::Right(view! {
+
+ })
+ }}
+
+ })
+ .collect_view();
+
+ view! {
+ {move || error_msg
+ .get()
+ .map(|err| view! {
+
+ "Error starting listener: "
+ {err}
+
+ })}
+
+ }
+}
diff --git a/sparse-server/src/beacons/templates.rs b/sparse-server/src/beacons/templates.rs
new file mode 100644
index 0000000..4c8118e
--- /dev/null
+++ b/sparse-server/src/beacons/templates.rs
@@ -0,0 +1,10 @@
+use leptos::prelude::*;
+
+#[component]
+pub fn TemplatesView() -> impl IntoView {
+ view! {
+
+
+
+ }
+}
diff --git a/sparse-server/src/lib.rs b/sparse-server/src/lib.rs
index 422c291..9a0ab05 100644
--- a/sparse-server/src/lib.rs
+++ b/sparse-server/src/lib.rs
@@ -1,10 +1,10 @@
pub mod app;
-
-pub mod users;
-
-pub mod error;
-
+#[cfg(feature = "ssr")]
+pub mod beacon_handler;
+pub mod beacons;
pub mod db;
+pub mod error;
+pub mod users;
#[cfg(feature = "hydrate")]
#[wasm_bindgen::prelude::wasm_bindgen]
diff --git a/sparse-server/src/main.rs b/sparse-server/src/main.rs
index 10a9fc0..c31383c 100644
--- a/sparse-server/src/main.rs
+++ b/sparse-server/src/main.rs
@@ -1,5 +1,5 @@
#[cfg(feature = "ssr")]
-pub(crate) mod beacons {
+pub(crate) mod beacon_binaries {
#[allow(dead_code)]
pub const LINUX_BEACON: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_LINUX"));
#[allow(dead_code)]
@@ -15,16 +15,15 @@ pub(crate) mod beacons {
#[cfg(feature = "ssr")]
mod cli;
-
#[cfg(feature = "ssr")]
mod webserver;
-
+#[cfg(feature = "ssr")]
+mod beacons;
#[cfg(feature = "ssr")]
pub mod users;
-
pub mod error;
-
pub mod db;
+pub mod beacon_handler;
#[cfg(feature = "ssr")]
#[tokio::main]
@@ -56,7 +55,7 @@ async fn main() -> anyhow::Result {
let db_exists = std::fs::metadata(&db_location);
- let run_init = if let Err(e) = db_exists {
+ if let Err(e) = db_exists {
if !options.init_ok {
tracing::error!("Database doesn't exist, and initialization not allowed!");
tracing::error!("{:?}", e);
@@ -64,10 +63,7 @@ async fn main() -> anyhow::Result {
}
tracing::info!("Database doesn't exist, readying initialization");
- true
- } else {
- false
- };
+ }
let pool = SqlitePool::connect_with(
SqliteConnectOptions::from_str(&format!("sqlite://{}", db_location.to_string_lossy()))?
diff --git a/sparse-server/src/users.rs b/sparse-server/src/users.rs
index b081d0a..256ea4c 100644
--- a/sparse-server/src/users.rs
+++ b/sparse-server/src/users.rs
@@ -255,7 +255,7 @@ pub fn UserView() -> impl IntoView {
let user = expect_context::>>();
if user.get().is_none() {
let navigate = leptos_router::hooks::use_navigate();
- navigate("/login?next=/users", Default::default());
+ navigate("/login?next=users", Default::default());
}
});
diff --git a/sparse-server/src/webserver.rs b/sparse-server/src/webserver.rs
index 278b3e6..4e7679a 100644
--- a/sparse-server/src/webserver.rs
+++ b/sparse-server/src/webserver.rs
@@ -12,6 +12,7 @@ pub async fn serve_web(management_address: SocketAddrV4, _bind_address: SocketAd
let conf = get_configuration(None).unwrap();
let leptos_options = conf.leptos_options;
let routes = generate_route_list(App);
+ let beacon_listeners = crate::beacon_handler::BeaconListenerMap::default();
let compression_layer = tower_http::compression::CompressionLayer::new()
.gzip(true)
@@ -23,7 +24,10 @@ pub async fn serve_web(management_address: SocketAddrV4, _bind_address: SocketAd
.leptos_routes_with_context(
&leptos_options,
routes,
- move || provide_context(db.clone()),
+ move || {
+ provide_context(std::sync::Arc::clone(&beacon_listeners));
+ provide_context(db.clone())
+ },
{
let leptos_options = leptos_options.clone();
move || shell(leptos_options.clone())
diff --git a/sparse-server/style/_beacons.scss b/sparse-server/style/_beacons.scss
new file mode 100644
index 0000000..87037e9
--- /dev/null
+++ b/sparse-server/style/_beacons.scss
@@ -0,0 +1,38 @@
+@use 'beacons/listeners';
+@use 'beacons/configs';
+@use 'beacons/categories';
+@use 'beacons/templates';
+@use 'beacons/instances';
+@use 'beacons/commands';
+
+main.beacons {
+ display: grid;
+ grid-template-columns: 120px 1fr;
+ padding: 0;
+
+ aside.beacon-menu {
+ border-right: 1px solid #2e2e59;
+
+ ul {
+ list-style-type: none;
+ padding: 0;
+ margin: 0;
+ }
+
+ li a, li a:visited {
+ display: inline-block;
+ padding: 10px;
+
+ color: white;
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+}
+
+aside.beacons {
+
+}
diff --git a/sparse-server/style/_main.scss b/sparse-server/style/_main.scss
index 9f02515..f259186 100644
--- a/sparse-server/style/_main.scss
+++ b/sparse-server/style/_main.scss
@@ -1,3 +1,14 @@
main.main {
}
+
+main.login {
+ form {
+ display: grid;
+ grid-template-columns: 125px 200px;
+
+ input, label {
+ margin: 10px;
+ }
+ }
+}
diff --git a/sparse-server/style/beacons/_categories.scss b/sparse-server/style/beacons/_categories.scss
new file mode 100644
index 0000000..e69de29
diff --git a/sparse-server/style/beacons/_commands.scss b/sparse-server/style/beacons/_commands.scss
new file mode 100644
index 0000000..e69de29
diff --git a/sparse-server/style/beacons/_configs.scss b/sparse-server/style/beacons/_configs.scss
new file mode 100644
index 0000000..e69de29
diff --git a/sparse-server/style/beacons/_instances.scss b/sparse-server/style/beacons/_instances.scss
new file mode 100644
index 0000000..e69de29
diff --git a/sparse-server/style/beacons/_listeners.scss b/sparse-server/style/beacons/_listeners.scss
new file mode 100644
index 0000000..6c8543f
--- /dev/null
+++ b/sparse-server/style/beacons/_listeners.scss
@@ -0,0 +1,14 @@
+main.beacons div.listeners {
+ form {
+ margin: 10px;
+ }
+
+ fieldset {
+ display: grid;
+ grid-template-columns: 300px 200px;
+
+ input, label {
+ margin: 10px;
+ }
+ }
+}
diff --git a/sparse-server/style/beacons/_templates.scss b/sparse-server/style/beacons/_templates.scss
new file mode 100644
index 0000000..e69de29
diff --git a/sparse-server/style/main.scss b/sparse-server/style/main.scss
index 967db27..b7f1bcf 100644
--- a/sparse-server/style/main.scss
+++ b/sparse-server/style/main.scss
@@ -1,5 +1,10 @@
@use '_users';
@use '_main';
+@use '_beacons';
+
+* {
+ box-sizing: border-box;
+}
html, body {
font-family: sans-serif;
diff --git a/unix-loader/src/abi.h b/unix-loader/src/abi.h
index 00091cd..1924c24 100644
--- a/unix-loader/src/abi.h
+++ b/unix-loader/src/abi.h
@@ -10,10 +10,12 @@ typedef struct {
typedef union SourceIp {
struct {
char mode; // set to 0
+ char source_mac[6];
ipaddr_t source_ip;
} use_host_networking;
struct {
char mode; // set to 1
+ char source_mac[6];
unsigned short netmask;
ipaddr_t source_ip;
ipaddr_t gateway;
@@ -25,8 +27,6 @@ typedef struct Parameters {
SourceIp_t source_ip;
unsigned short destination_port;
unsigned short pubkey_cert_size;
- unsigned short privkey_size;
- unsigned short privkey_cert_size;
unsigned short beacon_name_length;
unsigned short domain_name_length;
char pubkey_cert[1024];