diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 04303aa..35eb1dd 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,6 +2,5 @@
-
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index a4bbbd1..ba13516 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2469,7 +2469,7 @@ dependencies = [
[[package]]
name = "tfclient"
-version = "0.1.1"
+version = "0.1.2"
dependencies = [
"base64 0.21.0",
"base64-serde",
diff --git a/tfclient/Cargo.toml b/tfclient/Cargo.toml
index e58450c..5ce8753 100644
--- a/tfclient/Cargo.toml
+++ b/tfclient/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "tfclient"
-version = "0.1.1"
+version = "0.1.2"
edition = "2021"
description = "An open-source reimplementation of a Defined Networking-compatible client"
license = "GPL-3.0-or-later"
diff --git a/tfclient/config.example.toml b/tfclient/config.example.toml
new file mode 100644
index 0000000..ca5e9a9
--- /dev/null
+++ b/tfclient/config.example.toml
@@ -0,0 +1,7 @@
+# The port that the tfclient daemon should listen on for JSON RPC requests.
+listen_port = 8157
+
+# Set this to true in order to disable automatic callbacks back to the API server.
+# Use this if you are using an API server which you do not completley trust.
+# If this is enabled, you'll need to run `tfclient --update` to manually update your client configuration.
+disable_automatic_config_updates = false
\ No newline at end of file
diff --git a/tfclient/src/apiworker.rs b/tfclient/src/apiworker.rs
index 4246e93..3b2a1de 100644
--- a/tfclient/src/apiworker.rs
+++ b/tfclient/src/apiworker.rs
@@ -17,6 +17,7 @@ use crate::nebulaworker::NebulaWorkerMessage;
pub enum APIWorkerMessage {
Shutdown,
Enroll { code: String },
+ Update,
Timer
}
@@ -33,7 +34,7 @@ pub fn apiworker_main(_config: TFClientConfig, instance: String, url: String, tx
info!("recv on command socket: shutdown, stopping");
break;
},
- APIWorkerMessage::Timer => {
+ APIWorkerMessage::Timer | APIWorkerMessage::Update => {
info!("updating config");
let mut cdata = match load_cdata(&instance) {
Ok(c) => c,
diff --git a/tfclient/src/config.rs b/tfclient/src/config.rs
index 517a09b..9fd2927 100644
--- a/tfclient/src/config.rs
+++ b/tfclient/src/config.rs
@@ -18,7 +18,9 @@ fn default_port() -> u16 { DEFAULT_PORT }
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TFClientConfig {
#[serde(default = "default_port")]
- pub listen_port: u16
+ pub listen_port: u16,
+ #[serde(default = "bool_false")]
+ pub disable_automatic_config_updates: bool
}
#[derive(Serialize, Deserialize, Clone)]
@@ -33,7 +35,8 @@ pub fn create_config(instance: &str) -> Result<(), Box> {
fs::create_dir_all(get_config_dir(instance).ok_or("Unable to load config dir")?)?;
info!("Copying default config file to config directory...");
let config = TFClientConfig {
- listen_port: DEFAULT_PORT
+ listen_port: DEFAULT_PORT,
+ disable_automatic_config_updates: false,
};
let config_str = toml::to_string(&config)?;
fs::write(get_config_file(instance).ok_or("Unable to load config dir")?, config_str)?;
diff --git a/tfclient/src/daemon.rs b/tfclient/src/daemon.rs
index 6f59054..6cbba58 100644
--- a/tfclient/src/daemon.rs
+++ b/tfclient/src/daemon.rs
@@ -95,10 +95,23 @@ pub fn daemon_main(name: String, server: String) {
});
info!("Starting timer thread...");
- let timer_transmitter = transmitter.clone();
- let timer_thread = thread::spawn(move || {
- timer_main(timer_transmitter, rx_timer);
- });
+ if !config.disable_automatic_config_updates {
+ let timer_transmitter = transmitter.clone();
+ let timer_thread = thread::spawn(move || {
+ timer_main(timer_transmitter, rx_timer);
+ });
+ 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");
+ } else {
+ info!("automatic config updates have been disabled - not starting timer thread");
+ }
info!("Starting socket worker thread...");
let name_socket = name.clone();
@@ -126,16 +139,6 @@ 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(_) => (),
diff --git a/tfclient/src/main.rs b/tfclient/src/main.rs
index 4c0adfe..e8848e1 100644
--- a/tfclient/src/main.rs
+++ b/tfclient/src/main.rs
@@ -123,6 +123,13 @@ enum Commands {
#[clap(short, long)]
/// Enrollment code used to enroll this node
code: String,
+ },
+
+ /// Manually trigger a config update. It's useful to use this in combination with the `disable_automatic_config_updates` option.
+ Update {
+ #[clap(short, long, default_value = "tfclient")]
+ /// Service name specified on install
+ name: String,
}
}
@@ -247,6 +254,23 @@ fn main() {
std::process::exit(1);
}
};
+ },
+ Commands::Update { name } => {
+ info!("Loading config...");
+ let config = match load_config(&name) {
+ Ok(cfg) => cfg,
+ Err(e) => {
+ error!("Error loading configuration: {}", e);
+ std::process::exit(1);
+ }
+ };
+ match socketclient::update(&config) {
+ Ok(_) => (),
+ Err(e) => {
+ error!("Error sending update request: {}", e);
+ std::process::exit(1);
+ }
+ };
}
}
}
diff --git a/tfclient/src/socketclient.rs b/tfclient/src/socketclient.rs
index 62e0449..addb9ff 100644
--- a/tfclient/src/socketclient.rs
+++ b/tfclient/src/socketclient.rs
@@ -50,6 +50,49 @@ pub fn enroll(code: &str, config: &TFClientConfig) -> Result<(), Box>
Ok(())
}
+pub fn update(config: &TFClientConfig) -> Result<(), Box> {
+ info!("Connecting to local command socket...");
+ let mut stream = TcpStream::connect(SocketAddr::new(IpAddr::from([127, 0, 0, 1]), config.listen_port))?;
+ let stream2 = stream.try_clone()?;
+ let mut reader = BufReader::new(&stream2);
+
+ info!("Sending Hello...");
+ stream.write_all(&ctob(JsonMessage::Hello {
+ version: JSON_API_VERSION,
+ }))?;
+ info!("Waiting for hello...");
+ let msg = read_msg(&mut reader)?;
+ match msg {
+ JsonMessage::Hello { .. } => {
+ info!("Server sent hello, connection established")
+ }
+ JsonMessage::Goodbye { reason } => {
+ error!("Disconnected by server. Reason: {:?}", reason);
+ return Err("Disconnected by server".into());
+ }
+ _ => {
+ error!("Server returned unexpected message: {:?}", msg);
+ error!("Sending goodbye and exiting");
+ stream.write_all(&ctob(JsonMessage::Goodbye {
+ reason: DisconnectReason::UnexpectedMessageType,
+ }))?;
+ return Err("Unexpected message type by server".into());
+ }
+ }
+
+ info!("Sending enroll request...");
+ stream.write_all(&ctob(JsonMessage::Update {}))?;
+
+ info!("Sending disconnect...");
+ stream.write_all(&ctob(JsonMessage::Goodbye {
+ reason: DisconnectReason::Done,
+ }))?;
+
+ info!("Told tfclient daemon to trigger a configuration update. Check tfclient's logs to see if this was successful.");
+
+ Ok(())
+}
+
fn read_msg(reader: &mut BufReader<&TcpStream>) -> Result> {
let mut str = String::new();
reader.read_line(&mut str)?;
diff --git a/tfclient/src/socketworker.rs b/tfclient/src/socketworker.rs
index a87ec21..498e53c 100644
--- a/tfclient/src/socketworker.rs
+++ b/tfclient/src/socketworker.rs
@@ -241,6 +241,12 @@ fn senthello_handle(client: &mut Client, transmitter: &ThreadMessageSender, comm
info!("Client sent enroll with code {}", code);
info!("Sending enroll request to apiworker");
transmitter.api_thread.send(APIWorkerMessage::Enroll { code }).unwrap();
+ },
+
+ JsonMessage::Update {} => {
+ info!("Client sent update request.");
+ info!("Telling apiworker to update configuration");
+ transmitter.api_thread.send(APIWorkerMessage::Update).unwrap();
}
_ => {
@@ -290,7 +296,9 @@ pub enum JsonMessage {
#[serde(rename = "enroll")]
Enroll {
code: String
- }
+ },
+ #[serde(rename = "update")]
+ Update {}
}
#[derive(Serialize, Deserialize, Debug)]