start porting dnapi
This commit is contained in:
parent
05d452bc50
commit
26ef187ff3
|
@ -154,6 +154,16 @@ version = "0.21.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
|
||||
|
||||
[[package]]
|
||||
name = "base64-serde"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba368df5de76a5bea49aaf0cf1b39ccfbbef176924d1ba5db3e4135216cbe3c7"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.5.3"
|
||||
|
@ -2421,6 +2431,7 @@ name = "tfclient"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"base64-serde",
|
||||
"chrono",
|
||||
"clap",
|
||||
"ctrlc",
|
||||
|
|
|
@ -23,7 +23,7 @@ reqwest = { version = "0.11.16", features = ["blocking"] }
|
|||
base64 = "0.21.0"
|
||||
chrono = "0.4.24"
|
||||
ipnet = "2.7.1"
|
||||
|
||||
base64-serde = "0.7.0"
|
||||
|
||||
[build-dependencies]
|
||||
serde = { version = "1.0.157", features = ["derive"] }
|
||||
|
|
|
@ -1,61 +1,13 @@
|
|||
use std::error::Error;
|
||||
use base64_serde::base64_serde_type;
|
||||
use log::trace;
|
||||
use reqwest::blocking::Client;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollRequest {
|
||||
pub code: String,
|
||||
#[serde(rename = "dhPubkey")]
|
||||
pub dh_pubkey: String,
|
||||
#[serde(rename = "edPubkey")]
|
||||
pub ed_pubkey: String,
|
||||
pub timestamp: String,
|
||||
}
|
||||
const ENDPOINT_V1: &str = "/v1/dnclient";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollResponseMetadata {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollResponseOrganization {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollResponseData {
|
||||
pub config: String,
|
||||
#[serde(rename = "hostID")]
|
||||
pub host_id: String,
|
||||
pub counter: i64,
|
||||
#[serde(rename = "trustedKeys")]
|
||||
pub trusted_keys: String,
|
||||
pub organization: EnrollResponseOrganization,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollResponse {
|
||||
pub data: EnrollResponseData,
|
||||
pub metadata: EnrollResponseMetadata,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum APIResponse {
|
||||
Error(EnrollError),
|
||||
Success(EnrollResponse)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollError {
|
||||
pub errors: Vec<EnrollErrorSingular>
|
||||
}
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollErrorSingular {
|
||||
pub code: String,
|
||||
pub message: String
|
||||
}
|
||||
base64_serde_type!(Base64Standard, base64::engine::general_purpose::STANDARD);
|
||||
|
||||
pub fn enroll(server: &Url, request: &EnrollRequest) -> Result<APIResponse, Box<dyn Error>> {
|
||||
let endpoint = server.join("/v2/enroll")?;
|
||||
|
@ -68,3 +20,126 @@ pub fn enroll(server: &Url, request: &EnrollRequest) -> Result<APIResponse, Box<
|
|||
let resp = client.post(endpoint).body(text).send()?;
|
||||
Ok(resp.json()?)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct RequestV1 {
|
||||
pub version: i32,
|
||||
#[serde(rename = "hostID")]
|
||||
pub host_id: String,
|
||||
pub counter: u32,
|
||||
pub message: String,
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub signature: Vec<u8>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct RequestWrapper {
|
||||
#[serde(rename = "type")]
|
||||
pub message_type: String,
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub value: Vec<u8>,
|
||||
pub timestamp: String
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SignedResponseWrapper {
|
||||
pub data: SignedResponse
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SignedResponse {
|
||||
pub version: i32,
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub message: Vec<u8>,
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub signature: Vec<u8>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CheckForUpdateResponseWrapper {
|
||||
pub data: CheckForUpdateResponse
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CheckForUpdateResponse {
|
||||
#[serde(rename = "updateAvailable")]
|
||||
pub update_available: bool
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct DoUpdateRequest {
|
||||
#[serde(rename = "edPubkeyPEM")]
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub ed_pubkey_pem: Vec<u8>,
|
||||
#[serde(rename = "dhPubkeyPEM")]
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub dh_pubkey_pem: Vec<u8>,
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub nonce: Vec<u8>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct DoUpdateResponse {
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub config: Vec<u8>,
|
||||
pub counter: u32,
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub nonce: Vec<u8>,
|
||||
#[serde(rename = "trustedKeys")]
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub trusted_keys: Vec<u8>
|
||||
}
|
||||
|
||||
const ENROLL_ENDPOINT: &str = "/v2/enroll";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollRequest {
|
||||
pub code: String,
|
||||
#[serde(rename = "dhPubkey")]
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub dh_pubkey: Vec<u8>,
|
||||
#[serde(rename = "edPubkey")]
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub ed_pubkey: Vec<u8>,
|
||||
pub timestamp: String
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum EnrollResponse {
|
||||
Success {
|
||||
data: EnrollResponseData
|
||||
},
|
||||
Error {
|
||||
errors: APIErrors
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollResponseData {
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub config: Vec<u8>,
|
||||
#[serde(rename = "hostID")]
|
||||
pub host_id: String,
|
||||
pub counter: u32,
|
||||
#[serde(rename = "trustedKeys")]
|
||||
#[serde(with = "Base64Standard")]
|
||||
pub trusted_keys: Vec<u8>,
|
||||
pub organization: EnrollResponseDataOrg
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EnrollResponseDataOrg {
|
||||
pub id: String,
|
||||
pub name: String
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct APIError {
|
||||
pub code: String,
|
||||
pub message: String,
|
||||
pub path: Option<String>
|
||||
}
|
||||
|
||||
pub type APIErrors = Vec<APIError>;
|
|
@ -3,7 +3,6 @@ use base64::Engine;
|
|||
use chrono::Local;
|
||||
use log::{error, info, warn};
|
||||
use url::Url;
|
||||
use trifid_pki::ca::NebulaCAPool;
|
||||
use trifid_pki::cert::{serialize_ed25519_public, serialize_x25519_public};
|
||||
use trifid_pki::ed25519_dalek::{SecretKey, SigningKey};
|
||||
use trifid_pki::rand_core::OsRng;
|
||||
|
@ -14,7 +13,8 @@ use crate::daemon::ThreadMessageSender;
|
|||
|
||||
pub enum APIWorkerMessage {
|
||||
Shutdown,
|
||||
Enroll { code: String }
|
||||
Enroll { code: String },
|
||||
Timer
|
||||
}
|
||||
|
||||
pub fn apiworker_main(config: TFClientConfig, instance: String, url: String, _transmitters: ThreadMessageSender, rx: Receiver<APIWorkerMessage>) {
|
||||
|
@ -68,6 +68,22 @@ pub fn apiworker_main(config: TFClientConfig, instance: String, url: String, _tr
|
|||
info!("recv on command socket: shutdown, stopping");
|
||||
break;
|
||||
},
|
||||
APIWorkerMessage::Timer => {
|
||||
info!("updating config");
|
||||
let mut cdata = match load_cdata(&instance) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
error!("error in api worker thread: {}", e);
|
||||
error!("APIWorker exiting with error");
|
||||
return;
|
||||
}
|
||||
};
|
||||
if cdata.host_id.is_none() {
|
||||
info!("not enrolled, cannot perform config update");
|
||||
continue;
|
||||
}
|
||||
|
||||
},
|
||||
APIWorkerMessage::Enroll { code } => {
|
||||
info!("recv on command socket: enroll {}", code);
|
||||
let mut cdata = match load_cdata(&instance) {
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::config::load_config;
|
|||
use crate::main;
|
||||
use crate::nebulaworker::{nebulaworker_main, NebulaWorkerMessage};
|
||||
use crate::socketworker::{socketworker_main, SocketWorkerMessage};
|
||||
use crate::timerworker::{timer_main, TimerWorkerMessage};
|
||||
use crate::util::check_server_url;
|
||||
|
||||
pub fn daemon_main(name: String, server: String) {
|
||||
|
@ -28,11 +29,13 @@ pub fn daemon_main(name: String, server: String) {
|
|||
let (tx_api, rx_api) = mpsc::channel::<APIWorkerMessage>();
|
||||
let (tx_socket, rx_socket) = mpsc::channel::<SocketWorkerMessage>();
|
||||
let (tx_nebula, rx_nebula) = mpsc::channel::<NebulaWorkerMessage>();
|
||||
let (tx_timer, rx_timer) = mpsc::channel::<TimerWorkerMessage>();
|
||||
|
||||
let transmitter = ThreadMessageSender {
|
||||
socket_thread: tx_socket,
|
||||
api_thread: tx_api,
|
||||
nebula_thread: tx_nebula
|
||||
nebula_thread: tx_nebula,
|
||||
timer_thread: tx_timer,
|
||||
};
|
||||
|
||||
let mainthread_transmitter = transmitter.clone();
|
||||
|
@ -59,6 +62,12 @@ pub fn daemon_main(name: String, server: String) {
|
|||
error!("Error sending shutdown message to socket worker thread: {}", e);
|
||||
}
|
||||
}
|
||||
match mainthread_transmitter.timer_thread.send(TimerWorkerMessage::Shutdown) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("Error sending shutdown message to timer worker thread: {}", e);
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
|
@ -69,8 +78,6 @@ pub fn daemon_main(name: String, server: String) {
|
|||
|
||||
info!("Starting API thread...");
|
||||
|
||||
|
||||
|
||||
let config_api = config.clone();
|
||||
let transmitter_api = transmitter.clone();
|
||||
let name_api = name.clone();
|
||||
|
@ -86,6 +93,12 @@ pub fn daemon_main(name: String, server: String) {
|
|||
nebulaworker_main(config_nebula, transmitter_nebula, rx_nebula);
|
||||
});
|
||||
|
||||
info!("Starting timer thread...");
|
||||
let timer_transmitter = transmitter.clone();
|
||||
let timer_thread = thread::spawn(move || {
|
||||
timer_main(timer_transmitter, rx_timer);
|
||||
});
|
||||
|
||||
info!("Starting socket worker thread...");
|
||||
let socket_thread = thread::spawn(move || {
|
||||
socketworker_main(config, name.clone(), transmitter, rx_socket);
|
||||
|
@ -111,6 +124,16 @@ pub fn daemon_main(name: String, server: String) {
|
|||
}
|
||||
info!("API thread exited");
|
||||
|
||||
info!("Waiting for timer thread to exit...");
|
||||
match timer_thread.join() {
|
||||
Ok(_) => (),
|
||||
Err(_) => {
|
||||
error!("Error waiting for timer thread to exit.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
info!("Timer thread exited");
|
||||
|
||||
info!("Waiting for Nebula thread to exit...");
|
||||
match nebula_thread.join() {
|
||||
Ok(_) => (),
|
||||
|
@ -128,5 +151,6 @@ pub fn daemon_main(name: String, server: String) {
|
|||
pub struct ThreadMessageSender {
|
||||
pub socket_thread: Sender<SocketWorkerMessage>,
|
||||
pub api_thread: Sender<APIWorkerMessage>,
|
||||
pub nebula_thread: Sender<NebulaWorkerMessage>
|
||||
pub nebula_thread: Sender<NebulaWorkerMessage>,
|
||||
pub timer_thread: Sender<TimerWorkerMessage>
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
/// Essentially a direct port of https://github.com/DefinedNet/dnapi
|
|
@ -25,6 +25,7 @@ pub mod apiworker;
|
|||
pub mod socketworker;
|
||||
pub mod api;
|
||||
pub mod socketclient;
|
||||
pub mod timerworker;
|
||||
|
||||
pub mod nebula_bin {
|
||||
include!(concat!(env!("OUT_DIR"), "/nebula.bin.rs"));
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::apiworker::APIWorkerMessage;
|
|||
use crate::config::{load_cdata, TFClientConfig};
|
||||
use crate::daemon::ThreadMessageSender;
|
||||
use crate::nebulaworker::NebulaWorkerMessage;
|
||||
use crate::timerworker::TimerWorkerMessage;
|
||||
|
||||
pub enum SocketWorkerMessage {
|
||||
Shutdown
|
||||
|
@ -214,6 +215,12 @@ fn senthello_handle(client: &mut Client, transmitter: &ThreadMessageSender, comm
|
|||
error!("Error sending shutdown message to socket worker thread: {}", e);
|
||||
}
|
||||
}
|
||||
match transmitter.timer_thread.send(TimerWorkerMessage::Shutdown) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("Error sending shutdown message to timer worker thread: {}", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
JsonMessage::GetHostID {} => {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
use std::ops::Add;
|
||||
use std::sync::mpsc::{Receiver, TryRecvError};
|
||||
use std::time::{Duration, SystemTime};
|
||||
use log::{error, info};
|
||||
use crate::apiworker::APIWorkerMessage;
|
||||
use crate::daemon::ThreadMessageSender;
|
||||
|
||||
pub enum TimerWorkerMessage {
|
||||
Shutdown
|
||||
}
|
||||
|
||||
pub fn timer_main(tx: ThreadMessageSender, rx: Receiver<TimerWorkerMessage>) {
|
||||
let mut api_reload_timer = SystemTime::now().add(Duration::from_secs(60));
|
||||
|
||||
loop {
|
||||
match rx.try_recv() {
|
||||
Ok(msg) => {
|
||||
match msg {
|
||||
TimerWorkerMessage::Shutdown => {
|
||||
info!("recv on command socket: shutdown, stopping");
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
match e {
|
||||
TryRecvError::Empty => {}
|
||||
TryRecvError::Disconnected => {
|
||||
error!("timerworker command socket disconnected, shutting down to prevent orphaning");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if SystemTime::now().gt(&api_reload_timer) {
|
||||
info!("Timer triggered: API_RELOAD_TIMER");
|
||||
api_reload_timer = SystemTime::now().add(Duration::from_secs(60));
|
||||
match tx.api_thread.send(APIWorkerMessage::Timer) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("Error sending timer message to api worker thread: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue