10 Commits
v1.3 ... v1.4

Author SHA1 Message Date
7e58423269 Update dependencies 2024-04-21 00:38:30 +02:00
2657aae847 Template fix 2024-04-21 00:26:15 +02:00
13cb85ac5a Added an opt-in to looking up own IP-Address 2024-04-21 00:00:04 +02:00
1a973e09a0 cargo update 2024-04-20 21:47:06 +02:00
f799927f90 Cargo update 2024-03-17 22:02:20 +01:00
8695f0026f lib-humus is now on crates.io 2024-02-11 14:15:13 +01:00
3b552dba8a Downgrade clap to 4.4.18 to support "older" rust versions 2024-02-11 12:38:33 +01:00
1ce60d8291 to_trust_resolver_config() -> to_hickory_resolver_config() 2024-02-11 11:52:33 +01:00
b5097b5a03 cargo update 2024-02-11 11:51:23 +01:00
610842abac Remove unused import 2024-02-11 11:51:08 +01:00
9 changed files with 372 additions and 324 deletions

621
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -7,14 +7,14 @@ authors = ["Slatian <baschdel@disroot.org>"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
lib-humus = { version="0.2", features=["axum-view+cookie"], git="https://codeberg.org/slatian/lib-humus.git" } lib-humus = { version="0.2", features=["axum-view+cookie"] }
axum = { version = "0.7", features = ["macros"] } axum = { version = "0.7", features = ["macros"] }
axum-extra = { version = "0.9", features = ["cookie", "typed-header"] } axum-extra = { version = "0.9", features = ["cookie", "typed-header"] }
axum-client-ip = "0.5" axum-client-ip = "0.6"
clap = { version = "4", features = ["derive"] } clap = { version = "4.5", features = ["derive"] }
governor = "0.6" governor = "0.6"
idna = "0.4" idna = "0.5"
lazy_static = "1.4.0" lazy_static = "1.4.0"
parking_lot = "0.12" parking_lot = "0.12"
regex = "1.10" regex = "1.10"
@ -26,6 +26,6 @@ tower = "0.4"
tower-http = { version = "0.5", features = ["fs"] } tower-http = { version = "0.5", features = ["fs"] }
hickory-proto = "0.24" hickory-proto = "0.24"
hickory-resolver = { version = "0.24", features = ["dns-over-rustls","dns-over-https","dns-over-quic","native-certs"] } hickory-resolver = { version = "0.24", features = ["dns-over-rustls","dns-over-https","dns-over-quic","native-certs"] }
maxminddb = "0.23" maxminddb = "0.24"
mime = "0.3" mime = "0.3"
http = "1.0" http = "1.1"

View File

@ -86,7 +86,7 @@ impl Into<Protocol> for DnsProtocol {
} }
impl DnsResolverConfig { impl DnsResolverConfig {
pub fn to_trust_resolver_config( pub fn to_hickory_resolver_config(
&self &self
) -> HickoryResolverConfig { ) -> HickoryResolverConfig {
let mut resolver = HickoryResolverConfig::new(); let mut resolver = HickoryResolverConfig::new();

View File

@ -6,7 +6,7 @@ use std::num::NonZeroU32;
mod dns; mod dns;
pub use crate::config::dns::{DnsConfig, DnsProtocol, DnsResolverConfig}; pub use crate::config::dns::{DnsConfig, DnsResolverConfig};
#[derive(Deserialize, Default, Clone)] #[derive(Deserialize, Default, Clone)]
pub struct EchoIpServiceConfig { pub struct EchoIpServiceConfig {

View File

@ -67,6 +67,7 @@ pub struct SettingsQuery {
format: Option<ResponseFormat>, format: Option<ResponseFormat>,
lang: Option<String>, lang: Option<String>,
dns: Option<String>, dns: Option<String>,
dns_self_lookup: Option<bool>,
} }
#[derive(Deserialize, Serialize, Clone)] #[derive(Deserialize, Serialize, Clone)]
@ -82,6 +83,7 @@ pub struct IpResult {
location: Option<LocationResult>, location: Option<LocationResult>,
ip_info: AddressInfo, ip_info: AddressInfo,
used_dns_resolver: Option<Arc<str>>, used_dns_resolver: Option<Arc<str>>,
reverse_dns_disabled_for_privacy: bool,
} }
// We need this one to hide the partial lookup field when irelevant // We need this one to hide the partial lookup field when irelevant
@ -227,7 +229,7 @@ async fn main() {
for (key, resolver_config) in &config.dns.resolver { for (key, resolver_config) in &config.dns.resolver {
println!("Initalizing {} resolver ...", key); println!("Initalizing {} resolver ...", key);
let resolver = TokioAsyncResolver::tokio( let resolver = TokioAsyncResolver::tokio(
resolver_config.to_trust_resolver_config(), resolver_config.to_hickory_resolver_config(),
Default::default() Default::default()
); );
dns_resolver_map.insert(key.clone(), resolver); dns_resolver_map.insert(key.clone(), resolver);
@ -357,6 +359,7 @@ async fn settings_query_middleware(
lang: query.lang.unwrap_or("en".to_string()), lang: query.lang.unwrap_or("en".to_string()),
available_dns_resolvers: derived_config.dns_resolver_selectables, available_dns_resolvers: derived_config.dns_resolver_selectables,
dns_resolver_id: dns_resolver_id, dns_resolver_id: dns_resolver_id,
dns_disable_self_lookup: !query.dns_self_lookup.unwrap_or(false),
}); });
next.run(req).await next.run(req).await
} }
@ -400,7 +403,7 @@ async fn handle_default_route(
State(arc_state): State<Arc<ServiceSharedState>>, State(arc_state): State<Arc<ServiceSharedState>>,
Extension(settings): Extension<QuerySettings>, Extension(settings): Extension<QuerySettings>,
user_agent_header: Option<TypedHeader<headers::UserAgent>>, user_agent_header: Option<TypedHeader<headers::UserAgent>>,
SecureClientIp(address): SecureClientIp SecureClientIp(client_ip): SecureClientIp
) -> Response { ) -> Response {
let state = Arc::clone(&arc_state); let state = Arc::clone(&arc_state);
@ -411,12 +414,20 @@ async fn handle_default_route(
search_query, search_query,
false, false,
settings, settings,
state state,
&client_ip
).await; ).await;
} }
} }
let result = get_ip_result(&address, &settings.lang, &"default".into(), &state).await; let result = get_ip_result(
&client_ip,
&settings.lang,
&settings.dns_resolver_id,
settings.dns_disable_self_lookup,
&client_ip,
&state,
).await;
let user_agent: Option<String> = match user_agent_header { let user_agent: Option<String> = match user_agent_header {
Some(TypedHeader(user_agent)) => Some(user_agent.to_string()), Some(TypedHeader(user_agent)) => Some(user_agent.to_string()),
@ -438,6 +449,7 @@ async fn handle_search_request(
this_should_have_been_an_ip: bool, this_should_have_been_an_ip: bool,
settings: QuerySettings, settings: QuerySettings,
arc_state: Arc<ServiceSharedState>, arc_state: Arc<ServiceSharedState>,
client_ip: &IpAddr,
) -> Response { ) -> Response {
let mut search_query = search_query.trim().to_string(); let mut search_query = search_query.trim().to_string();
@ -474,7 +486,7 @@ async fn handle_search_request(
// Try to interpret as an IP-Address // Try to interpret as an IP-Address
if let Ok(address) = search_query.parse() { if let Ok(address) = search_query.parse() {
return handle_ip_request(address, settings, arc_state).await; return handle_ip_request(address, settings, arc_state, client_ip).await;
} }
// Fall back to treating it as a hostname // Fall back to treating it as a hostname
@ -522,11 +534,12 @@ async fn handle_ip_route_with_path(
Extension(settings): Extension<QuerySettings>, Extension(settings): Extension<QuerySettings>,
State(arc_state): State<Arc<ServiceSharedState>>, State(arc_state): State<Arc<ServiceSharedState>>,
extract::Path(query): extract::Path<String>, extract::Path(query): extract::Path<String>,
SecureClientIp(client_ip): SecureClientIp
) -> Response { ) -> Response {
if let Ok(address) = query.parse() { if let Ok(address) = query.parse() {
return handle_ip_request(address, settings, arc_state).await return handle_ip_request(address, settings, arc_state, &client_ip).await
} else { } else {
return handle_search_request(query, true, settings, arc_state).await; return handle_search_request(query, true, settings, arc_state, &client_ip).await;
} }
} }
@ -534,6 +547,7 @@ async fn handle_ip_request(
address: IpAddr, address: IpAddr,
settings: QuerySettings, settings: QuerySettings,
arc_state: Arc<ServiceSharedState>, arc_state: Arc<ServiceSharedState>,
client_ip: &IpAddr,
) -> Response { ) -> Response {
let state = Arc::clone(&arc_state); let state = Arc::clone(&arc_state);
@ -541,6 +555,8 @@ async fn handle_ip_request(
&address, &address,
&settings.lang, &settings.lang,
&settings.dns_resolver_id, &settings.dns_resolver_id,
settings.dns_disable_self_lookup,
client_ip,
&state).await; &state).await;
state.templating_engine.render_view( state.templating_engine.render_view(
@ -553,9 +569,19 @@ async fn get_ip_result(
address: &IpAddr, address: &IpAddr,
lang: &String, lang: &String,
dns_resolver_name: &Arc<str>, dns_resolver_name: &Arc<str>,
dns_disable_self_lookup: bool,
client_ip: &IpAddr,
state: &ServiceSharedState, state: &ServiceSharedState,
) -> IpResult { ) -> IpResult {
let mut reverse_dns_disabled_for_privacy = false;
if state.config.dns.allow_reverse_lookup {
if address == client_ip && dns_disable_self_lookup {
reverse_dns_disabled_for_privacy = true;
}
}
let ip_info = AddressInfo::new(&address); let ip_info = AddressInfo::new(&address);
if !(ip_info.scope == AddressScope::Global || ip_info.scope == AddressScope::Shared) || ip_info.cast != AddressCast::Unicast { if !(ip_info.scope == AddressScope::Global || ip_info.scope == AddressScope::Shared) || ip_info.cast != AddressCast::Unicast {
@ -567,6 +593,7 @@ async fn get_ip_result(
location: None, location: None,
ip_info: ip_info, ip_info: ip_info,
used_dns_resolver: None, used_dns_resolver: None,
reverse_dns_disabled_for_privacy: reverse_dns_disabled_for_privacy,
} }
} }
} }
@ -574,7 +601,7 @@ async fn get_ip_result(
// do reverse lookup // do reverse lookup
let mut hostname: Option<String> = None; let mut hostname: Option<String> = None;
let mut used_dns_resolver: Option<Arc<str>> = None; let mut used_dns_resolver: Option<Arc<str>> = None;
if state.config.dns.allow_reverse_lookup { if state.config.dns.allow_reverse_lookup && !reverse_dns_disabled_for_privacy {
if let Some(dns_resolver) = &state.dns_resolvers.get(dns_resolver_name) { if let Some(dns_resolver) = &state.dns_resolvers.get(dns_resolver_name) {
hostname = simple_dns::reverse_lookup(&dns_resolver, &address).await; hostname = simple_dns::reverse_lookup(&dns_resolver, &address).await;
used_dns_resolver = Some(dns_resolver_name.clone()); used_dns_resolver = Some(dns_resolver_name.clone());
@ -605,6 +632,7 @@ async fn get_ip_result(
location: location_result, location: location_result,
ip_info: ip_info, ip_info: ip_info,
used_dns_resolver: used_dns_resolver, used_dns_resolver: used_dns_resolver,
reverse_dns_disabled_for_privacy: reverse_dns_disabled_for_privacy,
} }
} }

View File

@ -17,6 +17,7 @@ pub struct QuerySettings {
pub lang: String, pub lang: String,
pub available_dns_resolvers: Vec<Selectable>, pub available_dns_resolvers: Vec<Selectable>,
pub dns_resolver_id: Arc<str>, pub dns_resolver_id: Arc<str>,
pub dns_disable_self_lookup: bool,
} }
#[derive(Deserialize, Serialize, Clone)] #[derive(Deserialize, Serialize, Clone)]

View File

@ -17,8 +17,8 @@
<a href="{{ self::dig_link(extra=extra, name=name) }}">{% if prefix %}{{ prefix }} {% endif %}{% if fqdn or name=="." %}{{ name }}{% else %}{{ name | trim_end_matches(pat=".") }}{% endif %}</a> <a href="{{ self::dig_link(extra=extra, name=name) }}">{% if prefix %}{{ prefix }} {% endif %}{% if fqdn or name=="." %}{{ name }}{% else %}{{ name | trim_end_matches(pat=".") }}{% endif %}</a>
{% endmacro dig %} {% endmacro dig %}
{% macro ip(extra, ip, text=false) %} {% macro ip(extra, ip, text=false, with_self_lookup=false) %}
<a href="{{ extra.base_url }}/ip/{{ ip | urlencode_strict | replace(from="%2e", to=".") | replace(from="%3a", to=":") | safe }}"><code>{% if text %}{{ text }}{% else %}{{ ip }}{% endif %}</code></a> <a href="{{ extra.base_url }}/ip/{{ ip | urlencode_strict | replace(from="%2e", to=".") | replace(from="%3a", to=":") | safe }}{% if with_self_lookup %}?dns_self_lookup=true{% endif %}"><code>{% if text %}{{ text }}{% else %}{{ ip }}{% endif %}</code></a>
{% endmacro dig %} {% endmacro dig %}
{% macro breadcrumb_domain(extra, name) %} {% macro breadcrumb_domain(extra, name) %}

View File

@ -18,6 +18,9 @@
{% if r.hostname %} {% if r.hostname %}
<dt>Hostname</dt> <dt>Hostname</dt>
<dd>{{ helper::dig(extra=extra, name=r.hostname) }}</dd> <dd>{{ helper::dig(extra=extra, name=r.hostname) }}</dd>
{% elif r.reverse_dns_disabled_for_privacy %}
<dt>Hostname</dt>
<dd>Lookup disabled by default: {{ helper::ip(ip=r.address, extra=extra, text="enable", with_self_lookup=true)}}</dd>
{% endif %} {% endif %}
{% if r.asn %} {% if r.asn %}
<dt><abbr="Autonomous System Number">ASN</abbr></dt> <dt><abbr="Autonomous System Number">ASN</abbr></dt>

View File

@ -13,12 +13,19 @@
* Type of Address: {{ helper::ip_info(ip_info=r.ip_info) }} * Type of Address: {{ helper::ip_info(ip_info=r.ip_info) }}
{% if r.hostname -%} {% if r.hostname -%}
* Hostname: {{ r.hostname }} * Hostname: {{ r.hostname }}
{%- elif r.reverse_dns_disabled_for_privacy %}
* Hostname: Lookup disabled by default
{%- endif %} {%- endif %}
{% if r.asn -%} {% if r.asn -%}
* ASN: AS{{ r.asn.asn }} * ASN: AS{{ r.asn.asn }}
* AS Name: {{r.asn.name}} * AS Name: {{r.asn.name}}
{%- endif -%} {%- endif -%}
{%- if r.reverse_dns_disabled_for_privacy %}
=> /ip/{{ data.result.address }}?dns_self_lookup=true Do a reverse DNS lookup
{% endif %}
{%- if r.location %} {%- if r.location %}
## Geolocation ## Geolocation