summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md57
-rw-r--r--src/bin/server.rs43
-rw-r--r--src/config/environment.rs2
-rw-r--r--src/config/file.rs2
-rw-r--r--src/config/mod.rs71
-rw-r--r--src/error.rs2
6 files changed, 96 insertions, 81 deletions
diff --git a/README.md b/README.md
index fc8f83e..d369aef 100644
--- a/README.md
+++ b/README.md
@@ -6,12 +6,11 @@
**Roughenough** is a [Roughtime](https://roughtime.googlesource.com/roughtime) secure time
synchronization client and server implementation in Rust.
-The server and client are functionally complete and at feature parity with the reference
-C++ and Golang implementations.
+Roughenough's server and client are functionally complete and
+at feature parity with the reference C++ and Golang implementations.
-Requires latest stable Rust to compile. Areas for improvement remain,
-see [limitations](#limitations) below. Contributions are welcome, see
-[CONTRIBUTING](../master/CONTRIBUTING.md) for instructions.
+Requires latest stable Rust to compile. Contribution welcome, see
+[CONTRIBUTING](../master/CONTRIBUTING.md) for instructions and [limitations](#limitations) for areas that could use attention.
## Links
* [Roughenough Github repo](https://github.com/int08h/roughenough)
@@ -82,9 +81,26 @@ $ cp target/release/server /usr/local/bin
$ /usr/local/bin/server /path/to/config.file
```
-### Configuration File
+### Server Configuration
-The server is configured via a YAML file:
+There are two (mutually exclusive) ways to configure the Roughenough server:
+
+1. A YAML file, or
+2. Environment variables
+
+The server accepts the following configuration parameters:
+
+YAML Key | Environment Variable | Necessity | Description
+--- | --- | --- | ---
+`interface` | `ROUGHENOUGH_INTERFACE` | Required | IP address or interface name for listening to client requests
+`port` | `ROUGHENOUGH_PORT` | Required | UDP port to listen for requests
+`seed` | `ROUGHENOUGH_SEED` | Required | A 32-byte hexadecimal value used to generate the server's long-term key pair. **This is a secret value and must be un-guessable**, treat it with care.
+`batch_size` | `ROUGHENOUGH_BATCH_SIZE` | Optional | The maximum number of requests to process in one batch. All nonces in a batch are used to build a Merkle tree, the root of which is signed. Default is `64` requests per batch.
+`status_interval` | `ROUGHENOUGH_STATUS_INTERVAL` | Optional | Number of _seconds_ between each logged status update. Default is `600` seconds (10 minutes).
+
+#### YAML Configuration
+
+The table above lists the YAML keys available in the config file. An example:
```yaml
interface: 127.0.0.1
@@ -92,19 +108,22 @@ port: 8686
seed: f61075c988feb9cb700a4a6a3291bfbc9cab11b9c9eca8c802468eb38a43d7d3
```
-Where:
+Provide the config file as the single command-line argument to the Roughenough server binary:
-* **`interface`** - [Mandatory] IP address or interface name for listening to client requests
-* **`port`** - [Mandatory] UDP port to listen for requests
-* **`seed`** - [Mandatory] A 32-byte hexadecimal value used to generate the server's long-term
- key pair. **This is a secret value and must be un-guessable**,
- treat it with care.
-* **`batch_size`** - [Optional] The maximum number of requests to process in one batch. All nonces
- in a batch are used to build a Merkle tree, the root of which
- is signed. Default is 64 requests per batch.
-* **`status_interval`** - [Optional] Number of _seconds_ between each logged status update.
- Default is 600 seconds (10 minutes).
+```bash
+$ /path/to/server /path/to/config.yaml
+```
+
+#### Environment Configuration
+
+Roughenough can be configured via the `ROUGHENOUGH_*` [environment variables](https://12factor.net/config) listed in the table above. Example:
+```bash
+$ export ROUGHENOUGH_INTERFACE=127.0.0.1
+$ export ROUGHENOUGH_PORT=8686
+$ export ROUGHENOUGH_SEED=f61075c988feb9cb700a4a6a3291bfbc9cab11b9c9eca8c802468eb38a43d7d3
+$ /path/to/server
+```
### Stopping the Server
@@ -114,7 +133,7 @@ Use Ctrl-C or `kill` the process.
Roughtime features not implemented by the server:
-* On-line key rotation. The server must be restarted to generate a new delegated key.
+* On-line (while server is running) key rotation. The server must be restarted to generate a new delegated key.
* The Rougheough server depends on the host's time source to comply with the smeared leap-second
requirement of the Roughtime protocol. A Roughenough server sourcing time from
[Google's public NTP servers](https://developers.google.com/time/) would produce compliant
diff --git a/src/bin/server.rs b/src/bin/server.rs
index 4e6ec45..13a7026 100644
--- a/src/bin/server.rs
+++ b/src/bin/server.rs
@@ -54,7 +54,7 @@ use mio_extras::timer::Timer;
use byteorder::{LittleEndian, WriteBytesExt};
use roughenough::config;
-use roughenough::config::{EnvironmentConfig, FileConfig, ServerConfig};
+use roughenough::config::ServerConfig;
use roughenough::keys::{LongTermKey, OnlineKey};
use roughenough::merkle::MerkleTree;
use roughenough::{Error, RtMessage, Tag};
@@ -103,12 +103,7 @@ fn nonce_from_request(buf: &[u8], num_bytes: usize) -> Result<&[u8], Error> {
}
}
-
-fn polling_loop(
- config: &Box<ServerConfig>,
- online_key: &mut OnlineKey,
- cert_bytes: &[u8],
-) {
+fn polling_loop(config: &Box<ServerConfig>, online_key: &mut OnlineKey, cert_bytes: &[u8]) {
let response_counter = AtomicUsize::new(0);
let keep_running = Arc::new(AtomicBool::new(true));
let kr = keep_running.clone();
@@ -252,35 +247,20 @@ pub fn main() {
let mut args = env::args();
if args.len() != 2 {
- error!("Usage: server /path/to/config.file|ENV");
+ error!("Usage: server <ENV|/path/to/config.yaml>");
process::exit(1);
}
- let config: Box<ServerConfig> = {
- let arg1 = args.nth(1).unwrap();
- if &arg1 == "ENV" {
- match EnvironmentConfig::new() {
- Ok(cfg) => Box::new(cfg),
- Err(e) => {
- error!("{:?}", e);
- process::exit(1)
- }
- }
- } else {
- match FileConfig::new(&arg1) {
- Ok(cfg) => Box::new(cfg),
- Err(e) => {
- error!("{:?}", e);
- process::exit(1)
- }
- }
- }
+ let arg1 = args.nth(1).unwrap();
+ let config = match config::make_config(&arg1) {
+ Err(e) => {
+ error!("{:?}", e);
+ process::exit(1)
+ },
+ Ok(ref cfg) if !config::is_valid_config(&cfg) => process::exit(1),
+ Ok(cfg) => cfg,
};
- if !config::is_valid_config(&config) {
- process::exit(2);
- }
-
let mut online_key = OnlineKey::new();
let mut long_term_key = LongTermKey::new(config.seed());
let cert_bytes = long_term_key.make_cert(&online_key).encode().unwrap();
@@ -296,4 +276,3 @@ pub fn main() {
info!("Done.");
process::exit(0);
}
-
diff --git a/src/config/environment.rs b/src/config/environment.rs
index 7ebe588..5053517 100644
--- a/src/config/environment.rs
+++ b/src/config/environment.rs
@@ -18,9 +18,9 @@ use std::env;
use std::net::SocketAddr;
use std::time::Duration;
-use Error;
use config::ServerConfig;
use config::{DEFAULT_BATCH_SIZE, DEFAULT_STATUS_INTERVAL};
+use Error;
///
/// Obtain a Roughenough server configuration ([ServerConfig](trait.ServerConfig.html))
diff --git a/src/config/file.rs b/src/config/file.rs
index 8aa8ca2..e93ee99 100644
--- a/src/config/file.rs
+++ b/src/config/file.rs
@@ -20,9 +20,9 @@ use std::net::SocketAddr;
use std::time::Duration;
use yaml_rust::YamlLoader;
-use Error;
use config::ServerConfig;
use config::{DEFAULT_BATCH_SIZE, DEFAULT_STATUS_INTERVAL};
+use Error;
///
/// Read a Roughenough server configuration ([ServerConfig](trait.ServerConfig.html))
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 02ab941..983338c 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -28,9 +28,11 @@ use std::net::SocketAddr;
use std::time::Duration;
mod file;
+
pub use self::file::FileConfig;
mod environment;
+
pub use self::environment::EnvironmentConfig;
use Error;
@@ -44,26 +46,21 @@ pub const DEFAULT_STATUS_INTERVAL: Duration = Duration::from_secs(600);
///
/// Specifies parameters needed to configure a Roughenough server.
///
-/// Parameters labeled "**Required**" must are always be provided and have no default value.
-/// Parameters labeled "**Optional**" provide default values that can be overridden.
-///
-/// * **`interface`** - [Required] IP address or interface name for listening to client requests
-/// * **`port`** - [Required] UDP port to listen for requests
-/// * **`seed`** - [Required] A 32-byte hexadecimal value used to generate the server's long-term
-/// key pair. **This is a secret value and must be un-guessable**,
-/// treat it with care.
-/// * **`batch_size`** - [Optional] The maximum number of requests to process in one batch. All
-/// nonces in a batch are used to build a Merkle tree, the root of which
-/// is signed.
-/// Defaults to [DEFAULT_BATCH_SIZE](constant.DEFAULT_BATCH_SIZE.html)
-/// * **`status_interval`** - [Optional] Amount of time between each logged status update.
-/// Defaults to [DEFAULT_STATUS_INTERVAL](constant.DEFAULT_STATUS_INTERVAL.html)
+/// Parameters labeled "**Required**" must always be provided and have no default value
+/// while those labeled "**Optional**" provide default values that can be overridden.
///
-/// Implementations of this trait obtain a valid configuration from different back-
-/// end sources.
+/// YAML Key | Environment Variable | Necessity | Description
+/// --- | --- | --- | ---
+/// `interface` | `ROUGHENOUGH_INTERFACE` | Required | IP address or interface name for listening to client requests
+/// `port` | `ROUGHENOUGH_PORT` | Required | UDP port to listen for requests
+/// `seed` | `ROUGHENOUGH_SEED` | Required | A 32-byte hexadecimal value used to generate the server's long-term key pair. **This is a secret value and must be un-guessable**, treat it with care.
+/// `batch_size` | `ROUGHENOUGH_BATCH_SIZE` | Optional | The maximum number of requests to process in one batch. All nonces in a batch are used to build a Merkle tree, the root of which is signed. Defaults to [DEFAULT_BATCH_SIZE](constant.DEFAULT_BATCH_SIZE.html) requests per batch.
+/// `status_interval` | `ROUGHENOUGH_STATUS_INTERVAL` | Optional | Number of _seconds_ between each logged status update. Default value is [DEFAULT_STATUS_INTERVAL](constant.DEFAULT_STATUS_INTERVAL.html).
///
-/// See:
-/// * [FileConfig](struct.FileConfig.html)
+/// Implementations of this trait obtain a valid configuration from different back-end
+/// sources. See:
+/// * [FileConfig](struct.FileConfig.html) - configure via a YAML file
+/// * [EnvironmentConfig](struct.EnvironmentConfig.html) - configure via environment vars
///
pub trait ServerConfig {
/// [Required] IP address or interface name to listen for client requests
@@ -90,6 +87,26 @@ pub trait ServerConfig {
fn socket_addr(&self) -> Result<SocketAddr, Error>;
}
+///
+/// Factory function to create a `ServerConfig` trait object based on the provided `arg`
+///
+pub fn make_config(arg: &str) -> Result<Box<ServerConfig>, Error> {
+ if arg == "ENV" {
+ match EnvironmentConfig::new() {
+ Ok(cfg) => Ok(Box::new(cfg)),
+ Err(e) => Err(e),
+ }
+ } else {
+ match FileConfig::new(arg) {
+ Ok(cfg) => Ok(Box::new(cfg)),
+ Err(e) => Err(e),
+ }
+ }
+}
+
+///
+/// Validate configuration settings
+///
pub fn is_valid_config(cfg: &Box<ServerConfig>) -> bool {
let mut is_valid = true;
@@ -101,13 +118,6 @@ pub fn is_valid_config(cfg: &Box<ServerConfig>) -> bool {
error!("interface is missing");
is_valid = false;
}
- match cfg.socket_addr() {
- Err(e) => {
- error!("{}:{}: {:?}", cfg.interface(), cfg.port(), e);
- is_valid = false;
- }
- _ => ()
- }
if cfg.seed().is_empty() {
error!("seed value is missing");
is_valid = false;
@@ -121,6 +131,15 @@ pub fn is_valid_config(cfg: &Box<ServerConfig>) -> bool {
is_valid = false;
}
+ if is_valid {
+ match cfg.socket_addr() {
+ Err(e) => {
+ error!("failed to create socket {}:{} {:?}", cfg.interface(), cfg.port(), e);
+ is_valid = false;
+ }
+ _ => (),
+ }
+ }
+
is_valid
}
-
diff --git a/src/error.rs b/src/error.rs
index 49102a4..b681f33 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -58,5 +58,3 @@ impl From<std::io::Error> for Error {
Error::EncodingFailure(err)
}
}
-
-