1

Config loading

This commit is contained in:
Evan Pratten 2023-07-14 12:21:40 -04:00
parent c76325b42b
commit 4baae22c25
7 changed files with 153 additions and 19 deletions

@ -1,23 +1,29 @@
[package]
name = "<crate_name>"
name = "protomask"
version = "0.1.0"
authors = ["Evan Pratten <ewpratten@gmail.com>"]
edition = "2021"
description = "<description>"
documentation = "https://docs.rs/<crate_name>"
readme = "README.md"
homepage = "https://github.com/ewpratten/<repo_name>"
repository = "https://github.com/ewpratten/<repo_name>"
homepage = "https://github.com/ewpratten/protomask"
repository = "https://github.com/ewpratten/protomask"
license = "GPL-3.0"
keywords = []
categories = []
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"] }
clap = { version = "4.3.11", features = ["derive"] }
serde = { version = "1.0.171", features = ["derive"] }
ipnet = { version = "2.8.0", features = ["serde"] }
toml = "0.7.6"
log = "0.4.19"
fern = "0.6.2"
serde_path_to_error = "0.1.13"
thiserror = "1.0.43"
colored = "2.0.4"
[[bin]]
name = "<crate_name>"
name = "protomask"
path = "src/main.rs"

@ -1,8 +1,8 @@
# <repo_name>
[![Crates.io](https://img.shields.io/crates/v/<crate_name>)](https://crates.io/crates/<crate_name>)
[![Docs.rs](https://docs.rs/<crate_name>/badge.svg)](https://docs.rs/<crate_name>)
[![Build](https://github.com/Ewpratten/<repo_name>/actions/workflows/build.yml/badge.svg)](https://github.com/Ewpratten/<repo_name>/actions/workflows/build.yml)
[![Clippy](https://github.com/Ewpratten/<repo_name>/actions/workflows/clippy.yml/badge.svg)](https://github.com/Ewpratten/<repo_name>/actions/workflows/clippy.yml)
# protomask
[![Crates.io](https://img.shields.io/crates/v/protomask)](https://crates.io/crates/protomask)
[![Docs.rs](https://docs.rs/protomask/badge.svg)](https://docs.rs/protomask)
[![Build](https://github.com/Ewpratten/protomask/actions/workflows/build.yml/badge.svg)](https://github.com/Ewpratten/protomask/actions/workflows/build.yml)
[![Clippy](https://github.com/Ewpratten/protomask/actions/workflows/clippy.yml/badge.svg)](https://github.com/Ewpratten/protomask/actions/workflows/clippy.yml)
repo description
@ -12,5 +12,5 @@ repo description
This crate can be installed via `cargo` with:
```sh
cargo install <crate_name>
cargo install protomask
```

22
protomask.toml Normal file

@ -0,0 +1,22 @@
# Example configuration file for protomask
# Options for configuring the NAT64 interface
[interface]
# A list of IPv4 prefixes to use as the NAT64 pool
# The first address of the pool will be assigned to protomask itself (for ICMP messaging)
pool = ["192.0.2.0/24"]
# The IPv6 prefix to use for the NAT64 interface.
prefix = "64:ff9b::/96"
# A unique IPv6 address to use for ICMP messaging
# This will also serve DNS64
icmpv6_address = "2001:db8:1::1"
# Rules for controlling address mapping
[rules]
# A static mapping of IPv4 and IPv6 addresses
# These addresses will be exclusively reserved, and not used in the general pool
static_map = [
{ v4 = "192.0.2.2", v6 = "2001:db8:1::2" }
]

15
src/cli.rs Normal file

@ -0,0 +1,15 @@
use std::path::PathBuf;
use clap::Parser;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
/// Path to the config file
pub config_file: PathBuf,
/// Enable verbose logging
#[clap(short, long)]
pub verbose: bool,
}

67
src/config.rs Normal file

@ -0,0 +1,67 @@
use std::{
net::{Ipv4Addr, Ipv6Addr},
path::Path,
};
use colored::Colorize;
use ipnet::{Ipv4Net, Ipv6Net};
/// Interface config
#[derive(Debug, serde::Deserialize)]
pub struct InterfaceConfig {
/// Ipv4 pool
pub pool: Vec<Ipv4Net>,
/// IPv6 prefix
pub prefix: Ipv6Net,
/// IPv6 router addr
pub icmpv6_address: Ipv6Addr,
}
/// A static mapping rule
#[derive(Debug, serde::Deserialize)]
pub struct AddressMappingRule {
/// IPv4 address
pub v4: Ipv4Addr,
/// IPv6 address
pub v6: Ipv6Addr,
}
/// Rules config
#[derive(Debug, serde::Deserialize)]
pub struct RulesConfig {
/// Static mapping rules
pub static_map: Vec<AddressMappingRule>,
}
/// Representation of the `protomask.toml` config file
#[derive(Debug, serde::Deserialize)]
pub struct Config {
/// Interface config
pub interface: InterfaceConfig,
/// Rules config
pub rules: RulesConfig,
}
impl Config {
/// Load the config from a file
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, std::io::Error> {
// Load the file
let file_contents = std::fs::read_to_string(path)?;
// Build the deserializer
let deserializer = toml::Deserializer::new(&file_contents);
// Parse
match serde_path_to_error::deserialize(deserializer) {
Ok(config) => Ok(config),
Err(e) => {
eprintln!(
"Failed to parse config file due to:\n {}\n at {}",
e.inner().message().bright_red(),
e.path().to_string().bright_cyan()
);
std::process::exit(1);
}
}
}
}

@ -1,2 +0,0 @@
#![doc = include_str!("../README.md")]
#![deny(unsafe_code)]

@ -1,4 +1,30 @@
use clap::Parser;
use config::Config;
pub fn main(){
}
mod config;
mod cli;
#[tokio::main]
pub async fn main() {
// Parse CLI args
let args = cli::Args::parse();
// Set up logging
fern::Dispatch::new()
.format(|out, message, record| out.finish(format_args!("{}: {}", record.level(), message)))
.level(match args.verbose {
true => log::LevelFilter::Debug,
false => log::LevelFilter::Info,
})
.chain(std::io::stdout())
.apply()
.unwrap();
if args.verbose {
log::debug!("Verbose logging enabled");
}
// Parse the config file
let config = Config::load(args.config_file).unwrap();
}