Switch to AAAA records

This commit is contained in:
Brian Picciano 2023-05-15 18:23:53 +02:00
parent 774fbe06da
commit c1b6d982ef
6 changed files with 33 additions and 36 deletions

View File

@ -1,4 +1,4 @@
export DOMIPLY_PASSPHRASE=foobar export DOMIPLY_PASSPHRASE=foobar
export DOMIPLY_ORIGIN_STORE_GIT_DIR_PATH=/tmp/domiply_dev_env/origin/git export DOMIPLY_ORIGIN_STORE_GIT_DIR_PATH=/tmp/domiply_dev_env/origin/git
export DOMIPLY_DOMAIN_CHECKER_TARGET_CNAME=domiply.example.com export DOMIPLY_DOMAIN_CHECKER_TARGET_AAAA=::1
export DOMIPLY_DOMAIN_CONFIG_STORE_DIR_PATH=/tmp/domiply_dev_env/domain/config export DOMIPLY_DOMAIN_CONFIG_STORE_DIR_PATH=/tmp/domiply_dev_env/domain/config

View File

@ -1,4 +1,5 @@
use std::error::Error; use std::error::Error;
use std::net;
use std::str::FromStr; use std::str::FromStr;
use std::sync; use std::sync;
@ -13,17 +14,14 @@ pub enum NewDNSCheckerError {
#[error("invalid resolver address")] #[error("invalid resolver address")]
InvalidResolverAddress, InvalidResolverAddress,
#[error("invalid target CNAME")]
InvalidTargetCNAME,
#[error(transparent)] #[error(transparent)]
Unexpected(Box<dyn Error>), Unexpected(Box<dyn Error>),
} }
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum CheckDomainError { pub enum CheckDomainError {
#[error("target CNAME not set")] #[error("target AAAA not set")]
TargetCNAMENotSet, TargetAAAANotSet,
#[error("challenge token not set")] #[error("challenge token not set")]
ChallengeTokenNotSet, ChallengeTokenNotSet,
@ -33,7 +31,7 @@ pub enum CheckDomainError {
} }
pub struct DNSChecker { pub struct DNSChecker {
target_cname: Name, target_aaaa: net::Ipv6Addr,
// TODO we should use some kind of connection pool here, I suppose // TODO we should use some kind of connection pool here, I suppose
client: tokio::sync::Mutex<AsyncClient>, client: tokio::sync::Mutex<AsyncClient>,
@ -41,7 +39,7 @@ pub struct DNSChecker {
pub fn new( pub fn new(
tokio_runtime: sync::Arc<tokio::runtime::Runtime>, tokio_runtime: sync::Arc<tokio::runtime::Runtime>,
target_cname: domain::Name, target_aaaa: net::Ipv6Addr,
resolver_addr: &str, resolver_addr: &str,
) -> Result<DNSChecker, NewDNSCheckerError> { ) -> Result<DNSChecker, NewDNSCheckerError> {
let resolver_addr = resolver_addr let resolver_addr = resolver_addr
@ -57,7 +55,7 @@ pub fn new(
tokio_runtime.spawn(bg); tokio_runtime.spawn(bg);
Ok(DNSChecker { Ok(DNSChecker {
target_cname: target_cname.inner, target_aaaa,
client: tokio::sync::Mutex::new(client), client: tokio::sync::Mutex::new(client),
}) })
} }
@ -70,13 +68,13 @@ impl DNSChecker {
) -> Result<(), CheckDomainError> { ) -> Result<(), CheckDomainError> {
let domain = &domain.inner; let domain = &domain.inner;
// check that the CNAME is installed correctly on the domain // check that the AAAA is installed correctly on the domain
{ {
let response = match self let response = match self
.client .client
.lock() .lock()
.await .await
.query(domain.clone(), DNSClass::IN, RecordType::CNAME) .query(domain.clone(), DNSClass::IN, RecordType::AAAA)
.await .await
{ {
Ok(res) => res, Ok(res) => res,
@ -86,14 +84,14 @@ impl DNSChecker {
let records = response.answers(); let records = response.answers();
if records.len() != 1 { if records.len() != 1 {
return Err(CheckDomainError::TargetCNAMENotSet); return Err(CheckDomainError::TargetAAAANotSet);
} }
// if the single record isn't a CNAME, or it's not the target CNAME, then return // if the single record isn't a AAAA, or it's not the target AAAA, then return
// TargetCNAMENotSet // TargetAAAANAMENotSet
match records[0].data() { match records[0].data() {
Some(RData::CNAME(remote_cname)) if remote_cname == &self.target_cname => (), Some(RData::AAAA(remote_aaaa)) if remote_aaaa == &self.target_aaaa => (),
_ => return Err(CheckDomainError::TargetCNAMENotSet), _ => return Err(CheckDomainError::TargetAAAANotSet),
} }
} }

View File

@ -72,8 +72,8 @@ pub enum SyncWithConfigError {
#[error("already in progress")] #[error("already in progress")]
AlreadyInProgress, AlreadyInProgress,
#[error("target CNAME not set")] #[error("target AAAA not set")]
TargetCNAMENotSet, TargetAAAANotSet,
#[error("challenge token not set")] #[error("challenge token not set")]
ChallengeTokenNotSet, ChallengeTokenNotSet,
@ -96,7 +96,7 @@ impl From<origin::store::SyncError> for SyncWithConfigError {
impl From<checker::CheckDomainError> for SyncWithConfigError { impl From<checker::CheckDomainError> for SyncWithConfigError {
fn from(e: checker::CheckDomainError) -> SyncWithConfigError { fn from(e: checker::CheckDomainError) -> SyncWithConfigError {
match e { match e {
checker::CheckDomainError::TargetCNAMENotSet => SyncWithConfigError::TargetCNAMENotSet, checker::CheckDomainError::TargetAAAANotSet => SyncWithConfigError::TargetAAAANotSet,
checker::CheckDomainError::ChallengeTokenNotSet => { checker::CheckDomainError::ChallengeTokenNotSet => {
SyncWithConfigError::ChallengeTokenNotSet SyncWithConfigError::ChallengeTokenNotSet
} }

View File

@ -14,7 +14,7 @@ use std::sync;
#[command(version)] #[command(version)]
#[command(about = "A domiply to another dimension")] #[command(about = "A domiply to another dimension")]
struct Cli { struct Cli {
#[arg(long, default_value_t = SocketAddr::from_str("127.0.0.1:3030").unwrap(), env = "DOMIPLY_HTTP_LISTEN_ADDR")] #[arg(long, default_value_t = SocketAddr::from_str("[::]:3030").unwrap(), env = "DOMIPLY_HTTP_LISTEN_ADDR")]
http_listen_addr: SocketAddr, http_listen_addr: SocketAddr,
#[arg(long, required = true, env = "DOMIPLY_PASSPHRASE")] #[arg(long, required = true, env = "DOMIPLY_PASSPHRASE")]
@ -23,8 +23,8 @@ struct Cli {
#[arg(long, required = true, env = "DOMIPLY_ORIGIN_STORE_GIT_DIR_PATH")] #[arg(long, required = true, env = "DOMIPLY_ORIGIN_STORE_GIT_DIR_PATH")]
origin_store_git_dir_path: path::PathBuf, origin_store_git_dir_path: path::PathBuf,
#[arg(long, required = true, env = "DOMIPLY_DOMAIN_CHECKER_TARGET_CNAME")] #[arg(long, required = true, env = "DOMIPLY_DOMAIN_CHECKER_TARGET_AAAA")]
domain_checker_target_cname: domiply::domain::Name, domain_checker_target_aaaa: std::net::Ipv6Addr,
#[arg(long, default_value_t = String::from("1.1.1.1:53"), env = "DOMIPLY_DOMAIN_CHECKER_RESOLVER_ADDR")] #[arg(long, default_value_t = String::from("1.1.1.1:53"), env = "DOMIPLY_DOMAIN_CHECKER_RESOLVER_ADDR")]
domain_checker_resolver_addr: String, domain_checker_resolver_addr: String,
@ -67,7 +67,7 @@ fn main() {
let domain_checker = domiply::domain::checker::new( let domain_checker = domiply::domain::checker::new(
tokio_runtime.clone(), tokio_runtime.clone(),
config.domain_checker_target_cname.clone(), config.domain_checker_target_aaaa,
&config.domain_checker_resolver_addr, &config.domain_checker_resolver_addr,
) )
.expect("domain checker initialized"); .expect("domain checker initialized");
@ -80,7 +80,7 @@ fn main() {
let service = domiply::service::new( let service = domiply::service::new(
manager, manager,
config.domain_checker_target_cname, config.domain_checker_target_aaaa,
config.passphrase, config.passphrase,
); );

View File

@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
use std::convert::Infallible; use std::convert::Infallible;
use std::future::Future; use std::future::Future;
use std::net;
use std::sync; use std::sync;
use crate::domain; use crate::domain;
@ -16,19 +17,19 @@ type SvcResponse = Result<Response<String>, String>;
#[derive(Clone)] #[derive(Clone)]
pub struct Service<'svc> { pub struct Service<'svc> {
domain_manager: sync::Arc<dyn domain::manager::Manager>, domain_manager: sync::Arc<dyn domain::manager::Manager>,
target_cname: domain::Name, target_aaaa: net::Ipv6Addr,
passphrase: String, passphrase: String,
handlebars: handlebars::Handlebars<'svc>, handlebars: handlebars::Handlebars<'svc>,
} }
pub fn new<'svc, 'mgr>( pub fn new<'svc, 'mgr>(
domain_manager: sync::Arc<dyn domain::manager::Manager>, domain_manager: sync::Arc<dyn domain::manager::Manager>,
target_cname: domain::Name, target_aaaa: net::Ipv6Addr,
passphrase: String, passphrase: String,
) -> Service<'svc> { ) -> Service<'svc> {
Service { Service {
domain_manager, domain_manager,
target_cname, target_aaaa,
passphrase, passphrase,
handlebars: self::http_tpl::get().expect("Retrieved Handlebars templates"), handlebars: self::http_tpl::get().expect("Retrieved Handlebars templates"),
} }
@ -161,7 +162,7 @@ impl<'svc> Service<'svc> {
struct Response { struct Response {
domain: domain::Name, domain: domain::Name,
flat_config: util::FlatConfig, flat_config: util::FlatConfig,
target_cname: domain::Name, target_aaaa: net::Ipv6Addr,
challenge_token: String, challenge_token: String,
} }
@ -181,14 +182,12 @@ impl<'svc> Service<'svc> {
} }
}; };
let target_cname = self.target_cname.clone();
return self.render_page( return self.render_page(
"/domain_init.html", "/domain_init.html",
&Response { &Response {
domain: args.domain, domain: args.domain,
flat_config: config.into(), flat_config: config.into(),
target_cname: target_cname, target_aaaa: self.target_aaaa,
challenge_token: config_hash, challenge_token: config_hash,
}, },
); );
@ -223,7 +222,7 @@ impl<'svc> Service<'svc> {
Err(domain::manager::SyncWithConfigError::InvalidURL) => Some("Fetching the git repository failed, please double check that you input the correct URL.".to_string()), Err(domain::manager::SyncWithConfigError::InvalidURL) => Some("Fetching the git repository failed, please double check that you input the correct URL.".to_string()),
Err(domain::manager::SyncWithConfigError::InvalidBranchName) => Some("The git repository does not have a branch of the given name, please double check that you input the correct name.".to_string()), Err(domain::manager::SyncWithConfigError::InvalidBranchName) => Some("The git repository does not have a branch of the given name, please double check that you input the correct name.".to_string()),
Err(domain::manager::SyncWithConfigError::AlreadyInProgress) => Some("The configuration of your domain is still in progress, please refresh in a few minutes.".to_string()), Err(domain::manager::SyncWithConfigError::AlreadyInProgress) => Some("The configuration of your domain is still in progress, please refresh in a few minutes.".to_string()),
Err(domain::manager::SyncWithConfigError::TargetCNAMENotSet) => Some("The CNAME record is not set correctly on the domain. Please double check that you put the correct value on the record. If the value is correct, then most likely the updated records have not yet propagated. In this case you can refresh in a few minutes to try again.".to_string()), Err(domain::manager::SyncWithConfigError::TargetAAAANotSet) => Some("The AAAA record is not set correctly on the domain. Please double check that you put the correct value on the record. If the value is correct, then most likely the updated records have not yet propagated. In this case you can refresh in a few minutes to try again.".to_string()),
Err(domain::manager::SyncWithConfigError::ChallengeTokenNotSet) => Some("The TXT record is not set correctly on the domain. Please double check that you put the correct value on the record. If the value is correct, then most likely the updated records have not yet propagated. In this case you can refresh in a few minutes to try again.".to_string()), Err(domain::manager::SyncWithConfigError::ChallengeTokenNotSet) => Some("The TXT record is not set correctly on the domain. Please double check that you put the correct value on the record. If the value is correct, then most likely the updated records have not yet propagated. In this case you can refresh in a few minutes to try again.".to_string()),
Err(domain::manager::SyncWithConfigError::Unexpected(e)) => Some(format!("An unexpected error occurred: {e}")), Err(domain::manager::SyncWithConfigError::Unexpected(e)) => Some(format!("An unexpected error occurred: {e}")),
}; };

View File

@ -1,12 +1,12 @@
<h2>Configure DNS</h2> <h2>Configure DNS</h2>
<p>Next you will need to configure your DNS server to point to Domiply. There are <p>Next you will need to configure your DNS server to point to Domiply. There
two entries you will need to add:</p> are two entries you will need to add:</p>
<ul> <ul>
<li> <li>
A <code>CNAME {{ data.domain }}</code> entry with the value A <code>AAAA {{ data.domain }}</code> entry with the value
<code>{{ data.target_cname }}</code> <code>{{ data.target_aaaa }}</code>
</li> </li>
<li> <li>
A <code>TXT _domiply_challenge.{{ data.domain }}</code> entry with the value A <code>TXT _domiply_challenge.{{ data.domain }}</code> entry with the value