Configurable multiple dns resolvers

This commit is contained in:
Slatian 2023-08-04 00:00:21 +02:00
parent cd8c0455dc
commit 104a072fd6
7 changed files with 441 additions and 100 deletions

277
Cargo.lock generated
View File

@ -77,7 +77,7 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -87,7 +87,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -245,6 +245,12 @@ version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.4.0"
@ -344,6 +350,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
@ -385,7 +401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d"
dependencies = [
"cfg-if",
"hashbrown",
"hashbrown 0.14.0",
"lock_api",
"once_cell",
"parking_lot_core",
@ -462,7 +478,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -595,6 +611,15 @@ dependencies = [
"slab",
]
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
dependencies = [
"byteorder",
]
[[package]]
name = "generic-array"
version = "0.14.7"
@ -664,6 +689,31 @@ dependencies = [
"smallvec",
]
[[package]]
name = "h2"
version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap 1.9.3",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.0"
@ -861,6 +911,16 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "2.0.0"
@ -868,7 +928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.14.0",
]
[[package]]
@ -879,7 +939,7 @@ checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
dependencies = [
"socket2 0.5.3",
"widestring",
"windows-sys",
"windows-sys 0.48.0",
"winreg",
]
@ -906,7 +966,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -1057,7 +1117,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -1112,6 +1172,12 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -1302,6 +1368,59 @@ version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quinn"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b435e71d9bfa0d8889927231970c51fb89c58fa63bffcab117c9c7a41e5ef8f"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"fxhash",
"quinn-proto",
"quinn-udp",
"rustls",
"thiserror",
"tokio",
"tracing",
"webpki",
]
[[package]]
name = "quinn-proto"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fce546b9688f767a57530652488420d419a8b1f44a478b451c3d1ab6d992a55"
dependencies = [
"bytes",
"fxhash",
"rand",
"ring",
"rustls",
"rustls-native-certs",
"rustls-pemfile 0.2.1",
"slab",
"thiserror",
"tinyvec",
"tracing",
"webpki",
]
[[package]]
name = "quinn-udp"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b07946277141531aea269befd949ed16b2c85a780ba1043244eda0969e538e54"
dependencies = [
"futures-util",
"libc",
"quinn-proto",
"socket2 0.4.9",
"tokio",
"tracing",
]
[[package]]
name = "quote"
version = "1.0.31"
@ -1429,7 +1548,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -1444,6 +1563,27 @@ dependencies = [
"webpki",
]
[[package]]
name = "rustls-native-certs"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
dependencies = [
"openssl-probe",
"rustls-pemfile 1.0.2",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-pemfile"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9"
dependencies = [
"base64 0.13.1",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.2"
@ -1474,6 +1614,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
dependencies = [
"windows-sys 0.42.0",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@ -1490,6 +1639,29 @@ dependencies = [
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "serde"
version = "1.0.171"
@ -1630,7 +1802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
dependencies = [
"libc",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -1756,7 +1928,7 @@ dependencies = [
"signal-hook-registry",
"socket2 0.4.9",
"tokio-macros",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -1792,6 +1964,7 @@ dependencies = [
"futures-sink",
"pin-project-lite",
"tokio",
"tracing",
]
[[package]]
@ -1821,7 +1994,7 @@ version = "0.19.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
dependencies = [
"indexmap",
"indexmap 2.0.0",
"serde",
"serde_spanned",
"toml_datetime",
@ -1921,18 +2094,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26"
dependencies = [
"async-trait",
"bytes",
"cfg-if",
"data-encoding",
"enum-as-inner",
"futures-channel",
"futures-io",
"futures-util",
"h2",
"http",
"idna 0.2.3",
"ipnet",
"lazy_static",
"quinn",
"rand",
"rustls",
"rustls-pemfile",
"rustls-pemfile 1.0.2",
"smallvec",
"thiserror",
"tinyvec",
@ -1941,6 +2118,7 @@ dependencies = [
"tracing",
"url",
"webpki",
"webpki-roots",
]
[[package]]
@ -2262,6 +2440,21 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
@ -2277,51 +2470,93 @@ version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
@ -2344,5 +2579,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys",
"windows-sys 0.48.0",
]

View File

@ -22,5 +22,5 @@ toml = "0.7"
tower = "0.4"
tower-http = { version = "0.4", features = ["fs"] }
trust-dns-proto = "0.22"
trust-dns-resolver = { version = "0.22", features = ["dns-over-rustls"] }
trust-dns-resolver = { version = "0.22", features = ["dns-over-rustls","dns-over-https","dns-over-quic"] }
maxminddb = "0.23"

View File

@ -61,3 +61,8 @@ burst = 15
#Note: The ratelimit is implemented using the governor crate
[dns.resolver.digitalcourage]
display_name = "Digitalcourage 3"
servers = ["5.9.164.112:853","[2a01:4f8:251:554::2]:853"]
protocol = "Tls"
tls_dns_name = "dns3.digitalcourage.de"

99
src/config/dns.rs Normal file
View File

@ -0,0 +1,99 @@
use serde::{Deserialize,Serialize};
use trust_dns_resolver::config::Protocol;
use trust_dns_resolver::Name;
use std::collections::HashMap;
use std::net::SocketAddr;
#[derive(Deserialize, Clone)]
pub struct DnsConfig {
pub allow_forward_lookup: bool,
pub allow_reverse_lookup: bool,
pub hidden_suffixes: Vec<String>,
#[serde(default="default_dns_resolver_name")]
pub default_resolver: String,
pub resolver: HashMap<String,DnsResolverConfig>,
}
#[derive(Deserialize, Serialize, Clone)]
pub enum DnsProtocol {
Udp,
Tcp,
Tls,
Https,
Quic,
}
pub fn default_dns_resolver_name() -> String {
"default".to_string()
}
#[derive(Deserialize, Serialize, Clone)]
pub struct DnsResolverConfig {
pub display_name: String,
#[serde(default="zero")]
pub weight: i32,
pub servers: Vec<SocketAddr>,
#[serde(default)]
pub search: Vec<String>,
pub protocol: DnsProtocol,
pub tls_dns_name: Option<String>,
pub bind_address: Option<SocketAddr>,
#[serde(default="default_true")]
pub trust_nx_responses: bool,
}
fn zero() -> i32 {
return 0;
}
fn default_true() -> bool {
return true;
}
impl Default for DnsConfig {
fn default() -> Self {
DnsConfig {
allow_forward_lookup: true,
allow_reverse_lookup: false,
hidden_suffixes: Vec::new(),
default_resolver: "default".to_string(),
resolver: Default::default(),
}
}
}
impl Into<Protocol> for DnsProtocol {
fn into(self) -> Protocol {
match self {
Self::Udp => Protocol::Udp,
Self::Tcp => Protocol::Tcp,
Self::Tls => Protocol::Tls,
Self::Https => Protocol::Https,
Self::Quic => Protocol::Quic,
}
}
}
impl DnsResolverConfig {
pub fn to_trust_resolver_config(&self) -> trust_dns_resolver::config::ResolverConfig {
let mut resolver = trust_dns_resolver::config::ResolverConfig::new();
for server in &self.servers {
resolver.add_name_server(trust_dns_resolver::config::NameServerConfig{
socket_addr: *server,
protocol: self.protocol.clone().into(),
tls_dns_name: self.tls_dns_name.clone(),
trust_nx_responses: self.trust_nx_responses,
tls_config: None,
bind_addr: self.bind_address,
});
}
for search in &self.search {
if let Ok(name) = Name::from_str_relaxed(search) {
resolver.add_search(name);
}
}
return resolver;
}
}

View File

@ -1,8 +1,14 @@
use axum_client_ip::SecureClientIpSource;
use serde::Deserialize;
use std::net::SocketAddr;
use std::num::NonZeroU32;
#[derive(serde::Deserialize, Default, Clone)]
mod dns;
pub use crate::config::dns::{DnsConfig, DnsProtocol, DnsResolverConfig};
#[derive(Deserialize, Default, Clone)]
pub struct EchoIpServiceConfig {
pub server: ServerConfig,
pub dns: DnsConfig,
@ -11,7 +17,7 @@ pub struct EchoIpServiceConfig {
pub ratelimit: RatelimitConfig,
}
#[derive(serde::Deserialize, Clone)]
#[derive(Deserialize, Clone)]
pub struct ServerConfig {
pub listen_on: SocketAddr,
pub ip_header: SecureClientIpSource,
@ -20,33 +26,27 @@ pub struct ServerConfig {
pub static_location: Option<String>,
}
#[derive(serde::Deserialize, Clone)]
pub struct DnsConfig {
pub allow_forward_lookup: bool,
pub allow_reverse_lookup: bool,
pub hidden_suffixes: Vec<String>,
//Future Idea: allow custom resolver
}
#[derive(serde::Deserialize, Clone)]
#[derive(Deserialize, Clone)]
pub struct GeoIpConfig {
pub asn_database: Option<String>,
pub location_database: Option<String>,
}
#[derive(serde::Deserialize, Clone)]
#[derive(Deserialize, Clone)]
pub struct TemplateConfig {
pub template_location: String,
pub extra_config: Option<String>,
pub text_user_agents: Vec<String>,
}
#[derive(serde::Deserialize, Clone)]
#[derive(Deserialize, Clone)]
pub struct RatelimitConfig {
pub per_minute: NonZeroU32,
pub burst: NonZeroU32,
}
impl Default for ServerConfig {
fn default() -> Self {
ServerConfig {
@ -58,16 +58,6 @@ impl Default for ServerConfig {
}
}
impl Default for DnsConfig {
fn default() -> Self {
DnsConfig {
allow_forward_lookup: true,
allow_reverse_lookup: false,
hidden_suffixes: Vec::new(),
}
}
}
impl Default for GeoIpConfig {
fn default() -> Self {
GeoIpConfig {
@ -95,3 +85,4 @@ impl Default for RatelimitConfig {
}
}
}

View File

@ -18,14 +18,11 @@ use axum_client_ip::SecureClientIp;
use clap::Parser;
use lazy_static::lazy_static;
use regex::Regex;
use serde::{Deserialize,Serialize};
use tera::Tera;
use tower::ServiceBuilder;
use tower_http::services::ServeDir;
use trust_dns_resolver::{
TokioAsyncResolver,
// config::ResolverOpts,
// config::ResolverConfig,
};
use trust_dns_resolver::TokioAsyncResolver;
use tokio::signal::unix::{
signal,
@ -62,28 +59,26 @@ use crate::templating_engine::{
use crate::ipinfo::{AddressCast,AddressInfo,AddressScope};
#[derive(serde::Deserialize, serde::Serialize, Clone)]
#[derive(Deserialize, Serialize, Clone)]
pub struct SettingsQuery {
format: Option<ResponseFormat>,
lang: Option<String>,
dns: Option<String>,
}
#[derive(serde::Deserialize, serde::Serialize, Clone)]
#[derive(Clone, Serialize)]
pub struct QuerySettings {
#[serde(skip)]
template: TemplateSettings,
dns_resolver_id: String,
}
#[derive(Deserialize, Serialize, Clone)]
pub struct SearchQuery {
query: Option<String>,
}
pub fn default_dns_name() -> String {
"default".to_string()
}
#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub struct ResolverQuery {
#[serde(default="default_dns_name")]
dns: String,
}
#[derive(serde::Deserialize, serde::Serialize, Clone)]
#[derive(Serialize, Clone)]
pub struct IpResult {
address: IpAddr,
hostname: Option<String>,
@ -95,7 +90,7 @@ pub struct IpResult {
// We need this one to hide the partial lookup field when irelevant
pub fn not(b: &bool) -> bool { !b }
#[derive(serde::Deserialize, serde::Serialize, Default, Clone)]
#[derive(Serialize, Default, Clone)]
pub struct DigResult {
records: simple_dns::DnsLookupResult,
#[serde(skip_serializing_if = "IdnaName::was_ascii")]
@ -239,7 +234,7 @@ async fn main() {
// Initalize DNS resolver with os defaults
println!("Initalizing dns resolver ...");
println!("Using System configuration ...");
println!("Initalizing System resolver ...");
let res = TokioAsyncResolver::tokio_from_system_conf();
//let res = TokioAsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default());
let dns_resolver = match res {
@ -269,6 +264,15 @@ async fn main() {
let mut dns_resolver_map: HashMap<String,TokioAsyncResolver> = HashMap::new();
for (key, resolver_config) in &config.dns.resolver {
println!("Initalizing {} resolver ...", key);
let resolver = TokioAsyncResolver::tokio(
resolver_config.to_trust_resolver_config(),
Default::default()
).unwrap();
dns_resolver_map.insert(key.clone(), resolver);
}
dns_resolver_map.insert("default".to_string(), dns_resolver);
dns_resolver_map.insert("quad9".to_string(), quad9_resolver);
dns_resolver_map.insert("google".to_string(), google_resolver);
@ -327,7 +331,7 @@ async fn main() {
config.ratelimit.per_minute, config.ratelimit.burst))
.layer(middleware::from_fn(ratelimit::rate_limit_middleware))
.layer(Extension(config))
.layer(middleware::from_fn(format_and_language_middleware))
.layer(middleware::from_fn(settings_query_middleware))
)
;
@ -340,7 +344,7 @@ async fn main() {
}
async fn format_and_language_middleware<B>(
async fn settings_query_middleware<B>(
Query(query): Query<SettingsQuery>,
Extension(config): Extension<config::EchoIpServiceConfig>,
user_agent_header: Option<TypedHeader<headers::UserAgent>>,
@ -361,9 +365,12 @@ async fn format_and_language_middleware<B>(
}
}
// Add the request settings extension
req.extensions_mut().insert(TemplateSettings{
format: format.unwrap_or(ResponseFormat::TextHtml),
lang: query.lang.unwrap_or("en".to_string()),
req.extensions_mut().insert(QuerySettings{
template: TemplateSettings{
format: format.unwrap_or(ResponseFormat::TextHtml),
lang: query.lang.unwrap_or("en".to_string()),
},
dns_resolver_id: query.dns.unwrap_or(config.dns.default_resolver),
});
next.run(req).await
}
@ -404,9 +411,8 @@ async fn user_agent_handler(
async fn handle_default_route(
Query(search_query): Query<SearchQuery>,
Query(resolver_settings): Query<ResolverQuery>,
State(arc_state): State<Arc<ServiceSharedState>>,
Extension(settings): Extension<TemplateSettings>,
Extension(settings): Extension<QuerySettings>,
user_agent_header: Option<TypedHeader<headers::UserAgent>>,
SecureClientIp(address): SecureClientIp
) -> Response {
@ -419,13 +425,12 @@ async fn handle_default_route(
search_query,
false,
settings,
resolver_settings,
state
).await;
}
}
let result = get_ip_result(&address, &settings.lang, &"default".to_string(), &state).await;
let result = get_ip_result(&address, &settings.template.lang, &"default".to_string(), &state).await;
let user_agent: Option<String> = match user_agent_header {
Some(TypedHeader(user_agent)) => Some(user_agent.to_string()),
@ -433,7 +438,7 @@ async fn handle_default_route(
};
state.templating_engine.render_view(
&settings,
&settings.template,
&View::Index{
result: result,
user_agent: user_agent,
@ -445,15 +450,16 @@ async fn handle_default_route(
async fn handle_search_request(
search_query: String,
this_should_have_been_an_ip: bool,
settings: TemplateSettings,
resolver_settings: ResolverQuery,
settings: QuerySettings,
arc_state: Arc<ServiceSharedState>,
) -> Response {
let search_query = search_query.trim();
let mut search_query = search_query.trim().to_string();
let mut settings = settings;
lazy_static!{
static ref ASN_REGEX: Regex = Regex::new(r"^[Aa][Ss][Nn]?\s*(\d{1,7})$").unwrap();
static ref VIA_REGEX: Regex = Regex::new(r"[Vv][Ii][Aa]\s+(\S+)").unwrap();
}
//If someone asked for an asn, give an asn answer
@ -462,22 +468,31 @@ async fn handle_search_request(
// Render a dummy template that can at least link to other pages
let state = Arc::clone(&arc_state);
return state.templating_engine.render_view(
&settings,
&settings.template,
&View::Asn{asn: asn},
).await
}
}
if let Some(via_cap) = VIA_REGEX.captures(&search_query) {
if let Some(via) = via_cap.get(1).map(|c| c.as_str().to_string()) {
let state = Arc::clone(&arc_state);
if state.dns_resolvers.contains_key(&via) {
settings.dns_resolver_id = via;
}
}
search_query = VIA_REGEX.replace(&search_query,"").trim().to_string();
}
// Try to interpret as an IP-Address
if let Ok(address) = search_query.parse() {
return handle_ip_request(address, settings, resolver_settings, arc_state).await;
return handle_ip_request(address, settings, arc_state).await;
}
// Fall back to treating it as a hostname
return handle_dig_request(
search_query.to_string(),
search_query,
settings,
resolver_settings,
arc_state,
!this_should_have_been_an_ip,
).await
@ -485,34 +500,32 @@ async fn handle_search_request(
}
async fn handle_ip_route_with_path(
Extension(settings): Extension<TemplateSettings>,
Extension(settings): Extension<QuerySettings>,
State(arc_state): State<Arc<ServiceSharedState>>,
Query(resolver_settings): Query<ResolverQuery>,
extract::Path(query): extract::Path<String>,
) -> Response {
if let Ok(address) = query.parse() {
return handle_ip_request(address, settings, resolver_settings, arc_state).await
return handle_ip_request(address, settings, arc_state).await
} else {
return handle_search_request(query, true, settings, resolver_settings, arc_state).await;
return handle_search_request(query, true, settings, arc_state).await;
}
}
async fn handle_ip_request(
address: IpAddr,
settings: TemplateSettings,
resolver_settings: ResolverQuery,
settings: QuerySettings,
arc_state: Arc<ServiceSharedState>,
) -> Response {
let state = Arc::clone(&arc_state);
let result = get_ip_result(
&address,
&settings.lang,
&resolver_settings.dns,
&settings.template.lang,
&settings.dns_resolver_id,
&state).await;
state.templating_engine.render_view(
&settings,
&settings.template,
&View::Ip{result: result}
).await
}
@ -580,18 +593,16 @@ async fn get_ip_result(
}
async fn handle_dig_route_with_path(
Query(resolver_settings): Query<ResolverQuery>,
Extension(settings): Extension<TemplateSettings>,
Extension(settings): Extension<QuerySettings>,
State(arc_state): State<Arc<ServiceSharedState>>,
extract::Path(name): extract::Path<String>,
) -> Response {
return handle_dig_request(name, settings, resolver_settings, arc_state, true).await
return handle_dig_request(name, settings, arc_state, true).await
}
async fn handle_dig_request(
dig_query: String,
settings: TemplateSettings,
resolver_settings: ResolverQuery,
settings: QuerySettings,
arc_state: Arc<ServiceSharedState>,
do_full_lookup: bool,
) -> Response {
@ -600,13 +611,13 @@ async fn handle_dig_request(
let dig_result = get_dig_result(
&dig_query,
&resolver_settings.dns,
&settings.dns_resolver_id,
&state,
do_full_lookup
).await;
state.templating_engine.render_view(
&settings,
&settings.template,
&View::Dig{ query: dig_query, result: dig_result}
).await

View File

@ -58,7 +58,7 @@ pub struct TemplateSettings {
/* The echoip view */
#[derive(serde::Deserialize, serde::Serialize, Clone)]
#[derive(serde::Serialize, Clone)]
#[serde(untagged)]
pub enum View {
Asn { asn: u32 },
@ -116,10 +116,10 @@ impl Engine {
_ => text.into_response(),
}
Err(e) => {
println!("There was an error while rendering template {template_name}: {e:?}");
println!("There was an error while rendering template {}: {e:?}", view.template_name());
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Template error in {template_name}, contact owner or see logs.\n")
format!("Template error in {}, contact owner or see logs.\n", view.template_name())
).into_response()
}
}