Skip to content

Commit

Permalink
Added config validation
Browse files Browse the repository at this point in the history
  • Loading branch information
NiklasVousten committed Nov 29, 2024
1 parent 9b55904 commit 3d4aedd
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 12 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com"
trust_nx_responses = false
```

## Validation
The config can be validated by running the following command.

`cargo run -- --validate`

This only validates the config, block- and allowlists, and does not start the DNS server. If the validation fails, the program exits with the error code `1`.

## DNSSEC Issues
Due to an upstream issue of [hickory-dns](https://github.com/hickory-dns/hickory-dns/issues/2429), non DNSSEC sites will not be resolved if `validate = true`.
Only DNSSEC capable sites will be resolved with this setting.
Expand Down
6 changes: 4 additions & 2 deletions src/blocklist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ impl BlockList {

// block list
for url in adlist {
let (raw_list, mut list_errors) = get_file(url, restore_from_cache).await;
let (raw_list, mut list_errors) =
get_file(url, restore_from_cache, true).await;
match raw_list {
None => {
error!("skipp list {url}");
Expand Down Expand Up @@ -141,7 +142,8 @@ impl BlockList {
// allow list
for url in allow_list {
info!("load allow list");
let (raw_list, mut list_errors) = get_file(url, restore_from_cache).await;
let (raw_list, mut list_errors) =
get_file(url, restore_from_cache, true).await;
match raw_list {
None => error!("skipp list {url}"),
Some(raw_list) => {
Expand Down
76 changes: 66 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,16 @@ fn load_cert_and_key(
Ok((certificates, key))
}

/// load a text file from url and cache it.
/// If restore_from_cache is true only the cache is used.
/// Return None if an Err has occure.
async fn get_file(url: &Url, restore_from_cache: bool) -> (Option<String>, String) {
/// Load a text file from url and cache it.
/// If restore_from_cache is true, only the cache is used.
/// The first return value is the file content.
/// It will be None if an error has occured.
/// The second value is a combined error message.
async fn get_file(
url: &Url,
restore_from_cache: bool,
cache_file: bool
) -> (Option<String>, String) {
if url.scheme() == "file" {
let path = url.path();
info!("load file {path:?}");
Expand Down Expand Up @@ -281,11 +287,13 @@ async fn get_file(url: &Url, restore_from_cache: bool) -> (Option<String>, Strin
.error_for_status()?
.text()
.await?;
if let Err(err) = write(&path, &resp)
.await
.with_context(|| format!("failed to save to {path:?}"))
{
error!("{err:?}");
if cache_file {
if let Err(err) = write(&path, &resp)
.await
.with_context(|| format!("failed to save to {path:?}"))
{
error!("{err:?}");
}
}
Ok(resp)
}
Expand Down Expand Up @@ -493,6 +501,19 @@ fn main() {
Lazy::force(&CONFIG_PATH);
Lazy::force(&LIST_DIR);

let config = load_config();

if std::env::args().any(|x| x == "--validate") {
if !async_validate_config(config) {
error!("Config validation failed!");
std::process::exit(1);
}
} else {
async_main(config);
}
}

fn load_config() -> Config {
info!("load config from {:?}", &*CONFIG_PATH);
let config = fs::read(&*CONFIG_PATH)
.with_context(|| format!("Failed to read {:?}", CONFIG_PATH.as_path()))
Expand All @@ -501,7 +522,42 @@ fn main() {
.with_context(|| "Failed to deserialize config")
.unwrap_or_else(|err| panic!("{err:?}"));
debug!("{:#?}", config);
async_main(config);

config
}

#[tokio::main]
async fn async_validate_config(config: Config) -> bool {
let mut validated = true;
//Allow List
for list in config.blocklist.allow_list {
let (file_content, error_message) = get_file(&list, false, false).await;
if let Some(content) = file_content {
if let Err(err) = parser::Blocklist::parse(list.path(), &content) {
error!("{}", err.msg());
validated = false;
}
} else {
error!("{error_message}");
validated = false;
}
}

//Block List
for list in config.blocklist.lists {
let (file_content, error_message) = get_file(&list, false, false).await;
if let Some(content) = file_content {
if let Err(err) = parser::Blocklist::parse(list.path(), &content) {
error!("{}", err.msg());
validated = false;
}
} else {
error!("{error_message}");
validated = false;
}
}

validated
}

#[cfg(test)]
Expand Down

0 comments on commit 3d4aedd

Please sign in to comment.