11 Commits

12 changed files with 125 additions and 112 deletions

24
Cargo.lock generated
View File

@ -281,9 +281,9 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "cc"
version = "1.0.81"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0"
checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
dependencies = [
"libc",
]
@ -1344,18 +1344,18 @@ dependencies = [
[[package]]
name = "pin-project"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842"
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c"
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
@ -1364,9 +1364,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
checksum = "2c516611246607d0c04186886dbb3a754368ef82c79e9827a802c6d836dd111c"
[[package]]
name = "pin-utils"
@ -1707,18 +1707,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.181"
version = "1.0.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d3e73c93c3240c0bda063c239298e633114c69a888c3e37ca8bb33f343e9890"
checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.181"
version = "1.0.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be02f6cb0cd3a5ec20bbcfbcbd749f57daddb1a0882dc2e46a6c236c90b977ed"
checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
dependencies = [
"proc-macro2",
"quote",

View File

@ -72,7 +72,7 @@ This configuration option will not be exposed over the webinterface.
By default echoip-slatecave uses the system configuration for dns like most other programs.
In case this is undesired one can difable it by setting `enable_system_resolver` to false.
In case this is undesired one can disable it by setting `enable_system_resolver` to false.
```toml
[dns]
@ -90,10 +90,6 @@ In case you want to use the system resolver and customize it.
`system_resolver_weight`
: Equivalent to the `weight` of a custom resolver, default: 1000
### `search`
This is for a work in progress feature that allows confiuring search domains for all custom dns resolvers.
### Custom resolvers
It is possible to confgure custom resolvers in plce of or in addition to the default system resolver.

View File

@ -67,9 +67,9 @@ The default configuration is pretty liberal so that the average human probably w
## TODO
* [ ] Investigate why search isn't working for global TLDs
* [ ] Add a way to configure just the dns server addresses and derive the port from the protocol.
* [ ] Add an about page for the system resolver
* [ ] Expose DNS responses from the additional on the web interface
## License

View File

@ -28,9 +28,6 @@ allow_reverse_lookup = true
# that end with one of these suffixes don't exist
hidden_suffixes = [".com"]
# doesn't really work 🙁
search = ["org","net"]
[geoip]
# Path to geoip databses
# Currently only the mmdb format is supported
@ -116,7 +113,7 @@ tls_dns_name = "cloudflare-dns.com"
[dns.resolver.google]
display_name = "Google"
info_url = "https://www.cloudflare.com/dns/"
info_url = "https://developers.google.com/speed/public-dns/docs/using"
aliases = ["goo","8888"]
weight = 440

View File

@ -1,6 +1,5 @@
use serde::{Deserialize,Serialize};
use trust_dns_resolver::config::Protocol;
use trust_dns_resolver::Name;
use std::collections::HashMap;
use std::net::SocketAddr;
@ -11,7 +10,6 @@ pub struct DnsConfig {
pub allow_forward_lookup: bool,
pub allow_reverse_lookup: bool,
pub hidden_suffixes: Vec<String>,
pub search: Vec<String>,
pub resolver: HashMap<String,DnsResolverConfig>,
pub enable_system_resolver: bool,
@ -40,8 +38,6 @@ pub struct DnsResolverConfig {
#[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>,
#[serde(skip_serializing)] //Don't leak our bind address to the outside
@ -65,7 +61,6 @@ impl Default for DnsConfig {
allow_reverse_lookup: false,
hidden_suffixes: Vec::new(),
resolver: Default::default(),
search: Vec::new(),
enable_system_resolver: true,
system_resolver_name: "System".to_string(),
@ -89,8 +84,7 @@ impl Into<Protocol> for DnsProtocol {
impl DnsResolverConfig {
pub fn to_trust_resolver_config(
&self,
additional_search: &Vec<String>,
&self
) -> trust_dns_resolver::config::ResolverConfig {
let mut resolver = trust_dns_resolver::config::ResolverConfig::new();
for server in &self.servers {
@ -103,16 +97,10 @@ impl DnsResolverConfig {
bind_addr: self.bind_address,
});
}
for search in &self.search {
if let Ok(name) = Name::from_str_relaxed(search) {
resolver.add_search(name);
}
}
for search in additional_search {
if let Ok(name) = Name::from_str_relaxed(search) {
resolver.add_search(name);
}
}
// Not configuring domain search here because searching
// on the resolver level is a bad idea unless we are
// taling about the system resolver which we
// can't tell what to do (which is good!)
return resolver;
}
}

View File

@ -22,6 +22,7 @@ use serde::{Deserialize,Serialize};
use tera::Tera;
use tower::ServiceBuilder;
use tower_http::services::ServeDir;
use trust_dns_resolver::Name;
use trust_dns_resolver::TokioAsyncResolver;
use tokio::signal::unix::{
@ -258,7 +259,7 @@ async fn main() {
for (key, resolver_config) in &config.dns.resolver {
println!("Initalizing {} resolver ...", key);
let resolver = TokioAsyncResolver::tokio(
resolver_config.to_trust_resolver_config(&config.dns.search),
resolver_config.to_trust_resolver_config(),
Default::default()
).unwrap();
dns_resolver_map.insert(key.clone(), resolver);
@ -679,25 +680,26 @@ async fn get_dig_result(
let name = &dig_query.trim().trim_end_matches(".").to_string();
let idna_name = IdnaName::from_string(&name);
if let Some(dns_resolver) = &state.dns_resolvers.get(dns_resolver_name) {
if let Ok(domain_name) = Name::from_str_relaxed(name.to_owned()+".") {
if match_domain_hidden_list(&name, &state.config.dns.hidden_suffixes) {
// Try to hide the fact that we didn't do dns resolution at all
// We resolve example.org as basic avoidance of timing sidechannels.
// WARNING: this timing sidechannel avoidance is very crude.
simple_dns::lookup(
&dns_resolver,
&("example.org.".to_string()),
&Name::from_ascii("example.org.").expect("Static Dummy Name"),
do_full_lookup).await;
DigResult {
return DigResult {
records: DnsLookupResult{ nxdomain: true , ..Default::default() },
idn: idna_name,
partial_lookup: !do_full_lookup,
used_dns_resolver: dns_resolver_name.clone(),
}
} else {
DigResult {
return DigResult {
records: simple_dns::lookup(
&dns_resolver,
&(idna_name.idn.clone().unwrap_or(name.to_owned())+"."),
&domain_name,
do_full_lookup).await,
idn: idna_name,
partial_lookup: !do_full_lookup,
@ -705,6 +707,21 @@ async fn get_dig_result(
}
}
} else {
return Default::default();
return DigResult {
records: DnsLookupResult{
invalid_name: true,
.. Default::default()
},
.. Default::default()
}
}
} else {
return DigResult {
records: DnsLookupResult{
unkown_resolver: true,
.. Default::default()
},
.. Default::default()
}
}
}

View File

@ -15,6 +15,7 @@ use trust_dns_resolver::{
error::ResolveError,
error::ResolveErrorKind,
lookup::Lookup,
Name,
TokioAsyncResolver,
};
@ -41,6 +42,8 @@ pub struct DnsLookupResult {
pub dns_error: bool,
pub nxdomain: bool,
pub timeout: bool,
pub invalid_name: bool,
pub unkown_resolver: bool,
}
#[derive(serde::Deserialize, serde::Serialize, Clone, PartialEq)]
@ -171,8 +174,14 @@ pub fn integrate_lookup_result(dig_result: &mut DnsLookupResult, lookup_result:
RecordType::TXT => set_default_if_none(&mut dig_result.txt),
_ => { /* This should not happen */ },
};
for record in lookup.iter() {
add_record_to_lookup_result(dig_result, record);
let name = lookup.query().name();
for record in lookup.record_iter() {
if name == record.name() {
if let Some(data) = record.data() {
add_record_to_lookup_result(dig_result, data);
}
}
//TODO: handle additional responses
}
},
Err(e) => {
@ -210,7 +219,7 @@ pub fn integrate_lookup_result(dig_result: &mut DnsLookupResult, lookup_result:
// records will be fetched.
pub async fn lookup(
resolver: &TokioAsyncResolver,
name: &String,
name: &Name,
do_full_lookup: bool,
) -> DnsLookupResult {
let (
@ -219,10 +228,10 @@ pub async fn lookup(
cname_lookup_res,
aname_lookup_res
) = join!(
resolver.lookup(name, RecordType::A),
resolver.lookup(name, RecordType::AAAA),
resolver.lookup(name, RecordType::CNAME),
resolver.lookup(name, RecordType::ANAME),
resolver.lookup(name.clone(), RecordType::A),
resolver.lookup(name.clone(), RecordType::AAAA),
resolver.lookup(name.clone(), RecordType::CNAME),
resolver.lookup(name.clone(), RecordType::ANAME),
);
// initlize an empty lookup result
@ -243,12 +252,12 @@ pub async fn lookup(
srv_lookup_res,
txt_lookup_res
) = join!(
resolver.lookup(name, RecordType::MX),
resolver.lookup(name, RecordType::NS),
resolver.lookup(name, RecordType::SOA),
resolver.lookup(name, RecordType::CAA),
resolver.lookup(name, RecordType::SRV),
resolver.lookup(name, RecordType::TXT),
resolver.lookup(name.clone(), RecordType::MX),
resolver.lookup(name.clone(), RecordType::NS),
resolver.lookup(name.clone(), RecordType::SOA),
resolver.lookup(name.clone(), RecordType::CAA),
resolver.lookup(name.clone(), RecordType::SRV),
resolver.lookup(name.clone(), RecordType::TXT),
);
integrate_lookup_result(&mut dig_result, mx_lookup_res);

View File

@ -26,8 +26,16 @@
<section>
<h2>DNS Records</h2>
{% if r.nxdomain %}
<p class="error box">Our DNS-Server claims that this domain doesn't exist, there shouldn't be any results.</p>
{% set show_nonpresent = true %}
{% if r.unkown_resolver %}
<p class="error box">The resolver you chose is not one of the available ones, if you can reproduce this error by just using the UI <a href="https://codeberg.org/slatian/service.echoip-slatecave/issues/new">please report it</a>.</p>
{% set show_nonpresent = false %}
{% elif r.invalid_name %}
<p class="error box">This domain name does not conform to <a href="https://www.rfc-editor.org/info/std3">the dns specification (std3)</a> rules and was therefore not resolved.</p>
{% set show_nonpresent = false %}
{% elif r.nxdomain %}
<p class="error box">The DNS-Server claims that this domain doesn't exist, there shouldn't be any results.</p>
{% set show_nonpresent = false %}
{% elif r.timeout %}
<p class="error box">There was at least one timeout error while resolving this domain, the results below are incomplete.</p>
{% elif r.other_error %}
@ -66,7 +74,7 @@
<li>{{ helper::ip(extra=extra, ip=address) }}</li>
{% endfor %}
</ul>
{% elif not r.nxdomain %}
{% elif show_nonpresent %}
<p>No <code>A</code> (IPv4) Records.</p>
{% endif %}
@ -77,7 +85,7 @@
<li>{{ helper::ip(extra=extra, ip=address) }}</li>
{% endfor %}
</ul>
{% elif not r.nxdomain %}
{% elif show_nonpresent %}
<p>No <code>AAAA</code> (IPv6) Records.</p>
{% endif %}
@ -90,7 +98,7 @@
<li>{{ helper::dig(extra=extra, name=mx.exchange, fqdn=true, prefix=mx.preference) }}</li>
{% endfor %}
</ul>
{% elif not r.nxdomain %}
{% elif show_nonpresent %}
<p id="mx">No <code>MX</code> (Mail Exchange) records.</p>
{% endif %}
@ -116,7 +124,7 @@
</dl></li>
{% endfor %}
</ul>
{% elif not r.nxdomain %}
{% elif show_nonpresent %}
<p id="soa">No <code>SOA</code> records.</p>
{% endif %}
@ -129,7 +137,7 @@
<li>{{ helper::dig(extra=extra, name=ns) }}</li>
{% endfor %}
</ul>
{% elif not r.nxdomain %}
{% elif show_nonpresent %}
<p id="ns">No <code>NS</code> (Name Server) records.</p>
{% endif %}
@ -141,7 +149,7 @@
<li><code>{{caa}}</code></li>
{% endfor %}
</ul>
{% elif not r.nxdomain %}
{% elif show_nonpresent %}
<p id="caa">No <code>CAA</code> (<a target="_blank" href="https://de.wikipedia.org/wiki/DNS_Certification_Authority_Authorization">Certification Authority Authorization</a>) records.</p>
{% endif %}
@ -152,7 +160,7 @@
<li><code>{{txt}}</code></li>
{% endfor %}
</ul>
{% elif not r.nxdomain %}
{% elif show_nonpresent %}
<p id="txt">No <code>TXT</code> records.</p>
{% endif %}
@ -172,7 +180,7 @@
</dl></li>
{% endfor %}
</ul>
{% elif not r.nxdomain %}
{% elif show_nonpresent %}
<p id="srv">No <code>SRV</code> records.</p>
<p><code>SRV</code> or Service records usually live on their own subdomains like {{ helper::dig(extra=extra, name="_xmpp-client._tcp."~data.query) }}.
{% endif %}

View File

@ -2,7 +2,8 @@
{% block path %}dig/{{ data.query | urlencode_strict }}{% endblock %}
{% block content -%}
{% set r = data.result.records %}
{%- block content -%}
# dig {{data.query}} via {{ data.result.used_dns_resolver }}
{% if data.result.idn -%}
@ -25,7 +26,16 @@ Your IDN would decode to
{% set r = data.result.records -%}
## DNS Records
{% if r.nxdomain %}
{% if r.unkown_resolver %}
{%- set show_nonpresent = false %}
The resolver you chose is not one of the available ones.
=> {{ extra.base_url }}/dns_resolver
{% elif r.invalid_name %}
{%- set show_nonpresent = false %}
This domain name does not conform to the dns specification (std3) rules and was therefore not resolved.
=> https://www.rfc-editor.org/info/std3
{% elif r.nxdomain %}
{%- set show_nonpresent = false %}
Our DNS-Server claims that this domain doesn't exist, there shouldn't be any results.
{%- elif r.timeout -%}
There was at least one timeout error while resolving this domain, the results below are incomplete.
@ -61,7 +71,7 @@ A (IPv4) records:
{% for address in r.a -%}
* {{ address }}
{% endfor %}
{%- elif not r.nxdomain %}
{%- elif show_nonpresent %}
No A (IPv4) Records.
{% endif -%}
@ -70,7 +80,7 @@ AAAA (IPv6) records:
{% for address in r.aaaa -%}
* {{ address }}
{% endfor %}
{%- elif not r.nxdomain %}
{%- elif show_nonpresent %}
No AAAA (IPv6) Records.
{% endif -%}
@ -81,7 +91,7 @@ MX (Mail Exchange) records:
{% for mx in r.mx | sort(attribute="preference") | reverse -%}
* {{ mx.preference }} {{ mx.exchange }}
{% endfor %}
{%- elif not r.nxdomain %}
{%- elif show_nonpresent %}
No MX (Mail Exchange) records.
{% endif %}
@ -96,7 +106,7 @@ SOA (Source Of Authority) records:
* expire: {{soa.expire / 3600 | round(precision=2)}}h
* minimum: {{soa.minimum / 60 | round(precision=2)}}m TTL
{% endfor %}
{%- elif not r.nxdomain %}
{%- elif show_nonpresent %}
No SOA (Source Of Authority) records.
{% endif %}
@ -105,7 +115,7 @@ NS (Name Server) records:
{% for ns in r.ns -%}
* {{ns}}
{% endfor %}
{%- elif not r.nxdomain %}
{%- elif show_nonpresent %}
No NS (Name Server) records.
{% endif %}
@ -114,7 +124,7 @@ CAA (Certification Authority Authorization) records:
{% for caa in r.caa -%}
* {{caa}}
{% endfor %}
{%- elif not r.nxdomain %}
{%- elif show_nonpresent %}
No CAA (Certification Authority Authorization) records.
{% endif %}
@ -123,7 +133,7 @@ TXT records:
{% for txt in r.txt -%}
* {{txt}}
{% endfor %}
{%- elif not r.nxdomain %}
{%- elif show_nonpresent %}
No TXT records.
{% endif %}
@ -135,7 +145,7 @@ SRV records:
* Port: {{srv.port}}
* Target: {{srv.target}}
{% endfor %}
{%- elif not r.nxdomain %}
{%- elif show_nonpresent %}
No SRV records.
SRV or Service records usually live on their own subdomains like {{ "_xmpp-client._tcp."~data.query }}.

View File

@ -31,12 +31,6 @@
<dd>{{ helper::dig(extra=extra, name=c.tls_dns_name) }}</dd>
{%- endif %}
{%- if c.search | length > 0 %}
<dt>Search</dt>
{%- for s in c.search %}
<dd>{{s}}</dd>
{%- endfor %}
{%- endif %}
</dl>
{%- if c.info_url %}
<p class="button-paragraph"><a href="{{c.info_url}}">More about the {{c.display_name}} DNS Server <small>(external link)</small></a></p>

View File

@ -16,14 +16,6 @@ Protocol: {{ c.protocol }}
{%-if c.tls_dns_name %}
DNS Name: {{ c.tls_dns_name }}
{%- endif %}
{%- if c.search | length == 1 %}
Search: {{ c.search | first }}
{%- elif c.search | length > 1 %}
Search:
{%- for s in c.search %}
* {{s}}
{%- endfor %}
{%- endif %}
{%- if c.aliases | length == 1 %}
Alias: {{ c.aliases | first }}
{%- elif c.aliases | length > 1 %}

View File

@ -380,6 +380,8 @@ a:visited {
color: var(--page-link-visited);
}
a.sitename { display: inline-block; }
h1, a.sitename {
margin: var(--heading-mg);
padding: var(--heading-pad);