mirror of
https://codeberg.org/slatian/service.echoip-slatecave.git
synced 2024-12-28 12:38:23 +01:00
All features in the config file work now 🎉
This commit is contained in:
parent
ee19071a3d
commit
d4caf1a77c
@ -1,37 +1,37 @@
|
|||||||
[server]
|
[server]
|
||||||
# What port to listen on and where request are supposed to come from
|
# What port to listen on and where request are supposed to come from
|
||||||
#listen_on: "127.0.0.1:3000"
|
listen_on = "127.0.0.1:3000"
|
||||||
|
|
||||||
# What header your reverse proxy sets that contains the real ip-address
|
# What header your reverse proxy sets that contains the real ip-address
|
||||||
# Possible Values: Every Vaiation of SecureClientIpSource in the axum_client_ip package
|
# Possible Values: Every Vaiation of SecureClientIpSource in the axum_client_ip package
|
||||||
# https://docs.rs/axum-client-ip/latest/axum_client_ip/enum.SecureClientIpSource.html
|
# https://docs.rs/axum-client-ip/latest/axum_client_ip/enum.SecureClientIpSource.html
|
||||||
#ip_header = "RightmostXForwardedFor"
|
#ip_header = "RightmostXForwardedFor"
|
||||||
# When you don't want to use a proxy server:
|
# When you don't want to use a proxy server:
|
||||||
#ip_header = "ConnectInfo"
|
ip_header = "ConnectInfo"
|
||||||
|
|
||||||
|
# Allow querying of private range ips
|
||||||
|
# enable if you want to use this service
|
||||||
|
# on your internal network for some reason
|
||||||
|
allow_private_ip_lookup = false
|
||||||
|
|
||||||
[dns]
|
[dns]
|
||||||
# Enable the /dig enpoint
|
# Enable the /dig enpoint
|
||||||
#allow_forward_lookup = true
|
allow_forward_lookup = true
|
||||||
|
|
||||||
# Enable reverse lookup, make sure to configure the hidden_suffixes
|
# Enable reverse lookup, make sure to configure the hidden_suffixes
|
||||||
# to contain your locally used domains, to prevent onformation leakage
|
# to contain your locally used domains, to prevent onformation leakage
|
||||||
#allow_reverse_lookup = false
|
allow_reverse_lookup = false
|
||||||
|
|
||||||
# Hide anything that has to do with private ip ranges
|
|
||||||
# Useful dor public services, disable if you want it
|
|
||||||
# on your internal network for some reason
|
|
||||||
#hide_private_range_ips = true
|
|
||||||
|
|
||||||
# echoip-sltecave will pretend that domains
|
# echoip-sltecave will pretend that domains
|
||||||
# that end with one of these suffixes don't exist
|
# that end with one of these suffixes don't exist
|
||||||
#hidden_suffixes = [".local"]
|
hidden_suffixes = [".local", ".box"]
|
||||||
|
|
||||||
[geoip]
|
[geoip]
|
||||||
# Path to geoip databses
|
# Path to geoip databses
|
||||||
# Currently only the mmdb format is supported
|
# Currently only the mmdb format is supported
|
||||||
# Official databases can be obtained from maxmind.com
|
# Official databases can be obtained from maxmind.com
|
||||||
#asn_database = "mmdb/GeoLite2-ASN.mmdb"
|
asn_database = "mmdb/GeoLite2-ASN.mmdb"
|
||||||
#location_database = "mmdb/GeoLite2-City.mmdb"
|
location_database = "mmdb/GeoLite2-City.mmdb"
|
||||||
|
|
||||||
# If anyone knows a free (as in freedom) groip database
|
# If anyone knows a free (as in freedom) groip database
|
||||||
# please open an issue so I can integrate it
|
# please open an issue so I can integrate it
|
||||||
@ -39,4 +39,4 @@
|
|||||||
|
|
||||||
[template]
|
[template]
|
||||||
# Path to the template directory, can contain glob patterns
|
# Path to the template directory, can contain glob patterns
|
||||||
#template_location = "templates"
|
template_location = "templates"
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
[server]
|
|
||||||
# What port to listen on and where request are supposed to come from
|
|
||||||
listen_on = "127.0.0.1:3000"
|
|
||||||
|
|
||||||
# What header your reverse proxy sets that contains the real ip-address
|
|
||||||
# Possible Values: Every Vaiation of SecureClientIpSource in the axum_client_ip package
|
|
||||||
# https://docs.rs/axum-client-ip/latest/axum_client_ip/enum.SecureClientIpSource.html
|
|
||||||
#ip_header = "RightmostXForwardedFor"
|
|
||||||
# When you don't want to use a proxy server:
|
|
||||||
ip_header = "ConnectInfo"
|
|
||||||
|
|
||||||
[dns]
|
|
||||||
# Enable the /dig enpoint
|
|
||||||
allow_forward_lookup = true
|
|
||||||
|
|
||||||
# Enable reverse lookup, make sure to configure the hidden_suffixes
|
|
||||||
# to contain your locally used domains, to prevent onformation leakage
|
|
||||||
allow_reverse_lookup = true
|
|
||||||
|
|
||||||
# Hide anything that has to do with private ip ranges
|
|
||||||
# Useful dor public services, disable if you want it
|
|
||||||
# on your internal network for some reason
|
|
||||||
#hide_private_range_ips = true
|
|
||||||
|
|
||||||
# echoip-sltecave will pretend that domains
|
|
||||||
# that end with one of these suffixes don't exist
|
|
||||||
hidden_suffixes = [".com"]
|
|
||||||
|
|
||||||
[geoip]
|
|
||||||
# Path to geoip databses
|
|
||||||
# Currently only the mmdb format is supported
|
|
||||||
# Official databases can be obtained from maxmind.com
|
|
||||||
#asn_database = "mmdb/GeoLite2-ASN.mmdb"
|
|
||||||
#location_database = "mmdb/GeoLite2-City.mmdb"
|
|
||||||
|
|
||||||
# If anyone knows a free (as in freedom) groip database
|
|
||||||
# please open an issue so I can integrate it
|
|
||||||
# https://codeberg.org/slatian/service.echoip-slatecave
|
|
||||||
|
|
||||||
[template]
|
|
||||||
# Path to the template directory, can contain glob patterns
|
|
||||||
#template_location = "templates"
|
|
@ -9,6 +9,11 @@ listen_on = "127.0.0.1:3000"
|
|||||||
# When you don't want to use a proxy server:
|
# When you don't want to use a proxy server:
|
||||||
ip_header = "ConnectInfo"
|
ip_header = "ConnectInfo"
|
||||||
|
|
||||||
|
# Allow querying of private range ips
|
||||||
|
# enable if you want to use this service
|
||||||
|
# on your internal network for some reason
|
||||||
|
allow_private_ip_lookup = true
|
||||||
|
|
||||||
[dns]
|
[dns]
|
||||||
# Enable the /dig enpoint
|
# Enable the /dig enpoint
|
||||||
allow_forward_lookup = true
|
allow_forward_lookup = true
|
||||||
@ -17,11 +22,6 @@ allow_forward_lookup = true
|
|||||||
# to contain your locally used domains, to prevent onformation leakage
|
# to contain your locally used domains, to prevent onformation leakage
|
||||||
allow_reverse_lookup = true
|
allow_reverse_lookup = true
|
||||||
|
|
||||||
# Hide anything that has to do with private ip ranges
|
|
||||||
# Useful dor public services, disable if you want it
|
|
||||||
# on your internal network for some reason
|
|
||||||
hide_private_range_ips = true
|
|
||||||
|
|
||||||
# echoip-sltecave will pretend that domains
|
# echoip-sltecave will pretend that domains
|
||||||
# that end with one of these suffixes don't exist
|
# that end with one of these suffixes don't exist
|
||||||
hidden_suffixes = [".com"]
|
hidden_suffixes = [".com"]
|
||||||
|
@ -13,13 +13,14 @@ pub struct EchoIpServiceConfig {
|
|||||||
pub struct ServerConfig {
|
pub struct ServerConfig {
|
||||||
pub listen_on: SocketAddr,
|
pub listen_on: SocketAddr,
|
||||||
pub ip_header: SecureClientIpSource,
|
pub ip_header: SecureClientIpSource,
|
||||||
|
|
||||||
|
pub allow_private_ip_lookup: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct DnsConfig {
|
pub struct DnsConfig {
|
||||||
pub allow_forward_lookup: bool,
|
pub allow_forward_lookup: bool,
|
||||||
pub allow_reverse_lookup: bool,
|
pub allow_reverse_lookup: bool,
|
||||||
pub hide_private_range_ips: bool,
|
|
||||||
pub hidden_suffixes: Vec<String>,
|
pub hidden_suffixes: Vec<String>,
|
||||||
//Future Idea: allow custom resolver
|
//Future Idea: allow custom resolver
|
||||||
}
|
}
|
||||||
@ -40,6 +41,7 @@ impl Default for ServerConfig {
|
|||||||
ServerConfig {
|
ServerConfig {
|
||||||
listen_on: "127.0.0.1:3000".parse().unwrap(),
|
listen_on: "127.0.0.1:3000".parse().unwrap(),
|
||||||
ip_header: SecureClientIpSource::RightmostXForwardedFor,
|
ip_header: SecureClientIpSource::RightmostXForwardedFor,
|
||||||
|
allow_private_ip_lookup: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,7 +51,6 @@ impl Default for DnsConfig {
|
|||||||
DnsConfig {
|
DnsConfig {
|
||||||
allow_forward_lookup: true,
|
allow_forward_lookup: true,
|
||||||
allow_reverse_lookup: false,
|
allow_reverse_lookup: false,
|
||||||
hide_private_range_ips: true,
|
|
||||||
hidden_suffixes: Vec::new(),
|
hidden_suffixes: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
112
src/ipinfo.rs
Normal file
112
src/ipinfo.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* The code in this file should provide a simple way to categorize
|
||||||
|
* IP-Address ranges (based on the rust tandard library) and return the
|
||||||
|
* result in a template ready format that can be used for custom messages
|
||||||
|
* depending on the type of IP-Address.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, PartialEq)]
|
||||||
|
#[serde(rename_all="lowercase")]
|
||||||
|
pub enum AddressCast {
|
||||||
|
Unspecified,
|
||||||
|
#[default]
|
||||||
|
Unicast,
|
||||||
|
Multicast,
|
||||||
|
Broadcast,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, PartialEq)]
|
||||||
|
#[serde(rename_all="lowercase")]
|
||||||
|
pub enum AddressScope {
|
||||||
|
Global,
|
||||||
|
Private,
|
||||||
|
Shared,
|
||||||
|
LinkLocal,
|
||||||
|
Loopback,
|
||||||
|
Reserved,
|
||||||
|
Documentation,
|
||||||
|
#[default]
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
|
pub struct AddressInfo {
|
||||||
|
pub is_v6_address: bool,
|
||||||
|
pub cast: AddressCast,
|
||||||
|
pub scope: AddressScope,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddressInfo {
|
||||||
|
pub fn new(address: &IpAddr) -> Self {
|
||||||
|
let mut is_v6_address = false;
|
||||||
|
let mut address_cast = AddressCast::Unicast;
|
||||||
|
let mut address_scope = AddressScope::Unknown;
|
||||||
|
match address {
|
||||||
|
IpAddr::V4(addr) => {
|
||||||
|
let naddr : u32 = (*addr).into();
|
||||||
|
let shared_net : u32 = Ipv4Addr::new(100, 64, 0, 0).into();
|
||||||
|
let v4_10_mask : u32 = 0xffc00000;
|
||||||
|
if addr.is_documentation() {
|
||||||
|
address_scope = AddressScope::Documentation;
|
||||||
|
//test if this is a shared address
|
||||||
|
} else if naddr & v4_10_mask == shared_net {
|
||||||
|
address_scope = AddressScope::Shared;
|
||||||
|
} else if addr.is_link_local() {
|
||||||
|
address_scope = AddressScope::LinkLocal;
|
||||||
|
} else if addr.is_private() {
|
||||||
|
address_scope = AddressScope::Private;
|
||||||
|
} else if addr.is_broadcast() {
|
||||||
|
address_cast = AddressCast::Broadcast;
|
||||||
|
address_scope = AddressScope::LinkLocal;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IpAddr::V6(addr) => {
|
||||||
|
is_v6_address = true;
|
||||||
|
let segments = addr.segments();
|
||||||
|
// for std::net these are still nightly only api … 😕
|
||||||
|
// Test for unique local addresses fc00::/7
|
||||||
|
if segments[0] & 0xfe00 == 0xfc00 {
|
||||||
|
address_scope = AddressScope::Private;
|
||||||
|
// Test for link local addresses fe80::/10
|
||||||
|
} else if segments[0] & 0xffc0 == 0xfe80 {
|
||||||
|
address_scope = AddressScope::LinkLocal;
|
||||||
|
// Test for the documentation address 2001:db8::/32
|
||||||
|
} else if segments[0]==0x2001 && segments[1]==0x0db8 && segments[2]==0 && segments[3]==0 {
|
||||||
|
address_scope = AddressScope::Documentation;
|
||||||
|
// Test for multicase scope
|
||||||
|
} else if addr.is_multicast() {
|
||||||
|
address_cast = AddressCast::Multicast;
|
||||||
|
let cast_type = segments[1] & 0x0f;
|
||||||
|
match cast_type {
|
||||||
|
1 => address_scope = AddressScope::Loopback,
|
||||||
|
2 => address_scope = AddressScope::LinkLocal,
|
||||||
|
4 | 5 | 8 => address_scope = AddressScope::Private,
|
||||||
|
0xe => address_scope = AddressScope::Global,
|
||||||
|
0 | 3 | 0xf => address_scope = AddressScope::Reserved,
|
||||||
|
_ => address_scope = AddressScope::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if address.is_loopback() {
|
||||||
|
address_scope = AddressScope::Loopback;
|
||||||
|
address_cast = AddressCast::Unicast;
|
||||||
|
} else if address.is_multicast() {
|
||||||
|
address_cast = AddressCast::Multicast;
|
||||||
|
} else if address.is_unspecified() {
|
||||||
|
address_scope = AddressScope::Unknown;
|
||||||
|
address_cast = AddressCast::Unspecified;
|
||||||
|
}
|
||||||
|
AddressInfo {
|
||||||
|
is_v6_address: is_v6_address,
|
||||||
|
cast: address_cast,
|
||||||
|
scope: address_scope
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
49
src/main.rs
49
src/main.rs
@ -6,13 +6,13 @@ use axum::{
|
|||||||
Router,
|
Router,
|
||||||
routing::get,
|
routing::get,
|
||||||
};
|
};
|
||||||
use axum_client_ip::{SecureClientIp, SecureClientIpSource};
|
use axum_client_ip::SecureClientIp;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
use trust_dns_resolver::{
|
use trust_dns_resolver::{
|
||||||
TokioAsyncResolver,
|
TokioAsyncResolver,
|
||||||
config::ResolverOpts,
|
// config::ResolverOpts,
|
||||||
config::ResolverConfig,
|
// config::ResolverConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -20,10 +20,11 @@ use std::net::IpAddr;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
mod geoip;
|
||||||
|
mod ipinfo;
|
||||||
mod simple_dns;
|
mod simple_dns;
|
||||||
mod templating_engine;
|
mod templating_engine;
|
||||||
mod geoip;
|
|
||||||
mod config;
|
|
||||||
|
|
||||||
use crate::geoip::QueryAsn;
|
use crate::geoip::QueryAsn;
|
||||||
use crate::geoip::QueryLocation;
|
use crate::geoip::QueryLocation;
|
||||||
@ -33,6 +34,8 @@ use geoip::LocationResult;
|
|||||||
use crate::templating_engine::View;
|
use crate::templating_engine::View;
|
||||||
use crate::templating_engine::ResponseFormat;
|
use crate::templating_engine::ResponseFormat;
|
||||||
|
|
||||||
|
use crate::ipinfo::{AddressCast,AddressInfo,AddressScope};
|
||||||
|
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
pub struct BaseQuery {
|
pub struct BaseQuery {
|
||||||
format: Option<ResponseFormat>,
|
format: Option<ResponseFormat>,
|
||||||
@ -57,6 +60,7 @@ pub struct IpResult {
|
|||||||
hostname: Option<String>,
|
hostname: Option<String>,
|
||||||
asn: Option<AsnResult>,
|
asn: Option<AsnResult>,
|
||||||
location: Option<LocationResult>,
|
location: Option<LocationResult>,
|
||||||
|
ip_info: AddressInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ServiceSharedState {
|
struct ServiceSharedState {
|
||||||
@ -163,6 +167,7 @@ async fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let listen_on = config.server.listen_on;
|
let listen_on = config.server.listen_on;
|
||||||
|
let ip_header = config.server.ip_header.clone();
|
||||||
|
|
||||||
// Initialize shared state
|
// Initialize shared state
|
||||||
let shared_state = Arc::new(
|
let shared_state = Arc::new(
|
||||||
@ -185,7 +190,7 @@ async fn main() {
|
|||||||
.route("/ip/:address", get(handle_ip_route_with_path))
|
.route("/ip/:address", get(handle_ip_route_with_path))
|
||||||
.route("/hi", get(hello_world_handler))
|
.route("/hi", get(hello_world_handler))
|
||||||
.with_state(shared_state)
|
.with_state(shared_state)
|
||||||
.layer(SecureClientIpSource::RightmostXForwardedFor.into_extension())
|
.layer(ip_header.into_extension())
|
||||||
;
|
;
|
||||||
|
|
||||||
println!("Starting Server ...");
|
println!("Starting Server ...");
|
||||||
@ -223,23 +228,7 @@ async fn handle_default_route(
|
|||||||
|
|
||||||
let state = Arc::clone(&arc_state);
|
let state = Arc::clone(&arc_state);
|
||||||
|
|
||||||
// do reverse lookup
|
let result = get_ip_result(&ip_query, &state).await;
|
||||||
let hostname = simple_dns::reverse_lookup(&state.dns_resolver, &address);
|
|
||||||
|
|
||||||
// asn lookup
|
|
||||||
let asn_result = state.asn_db.query_asn_for_ip(address);
|
|
||||||
|
|
||||||
// location lookup
|
|
||||||
let location_result = state.location_db.query_location_for_ip(
|
|
||||||
address,
|
|
||||||
&vec![&ip_query.lang.as_ref().unwrap_or(&"en".to_string()), &"en".to_string()]
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = IpResult{
|
|
||||||
hostname: hostname.await,
|
|
||||||
asn: asn_result,
|
|
||||||
location: location_result,
|
|
||||||
};
|
|
||||||
|
|
||||||
state.templating_engine.render_view(
|
state.templating_engine.render_view(
|
||||||
format,
|
format,
|
||||||
@ -287,6 +276,19 @@ async fn get_ip_result(
|
|||||||
) -> IpResult {
|
) -> IpResult {
|
||||||
let address = ip_query.ip;
|
let address = ip_query.ip;
|
||||||
|
|
||||||
|
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::Private || ip_info.scope == AddressScope::LinkLocal) && state.config.server.allow_private_ip_lookup) {
|
||||||
|
return IpResult {
|
||||||
|
hostname: None,
|
||||||
|
asn: None,
|
||||||
|
location: None,
|
||||||
|
ip_info: ip_info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// do reverse lookup
|
// do reverse lookup
|
||||||
let hostname = if state.config.dns.allow_reverse_lookup {
|
let hostname = if state.config.dns.allow_reverse_lookup {
|
||||||
simple_dns::reverse_lookup(&state.dns_resolver, &address).await
|
simple_dns::reverse_lookup(&state.dns_resolver, &address).await
|
||||||
@ -319,6 +321,7 @@ async fn get_ip_result(
|
|||||||
hostname: final_hostname,
|
hostname: final_hostname,
|
||||||
asn: asn_result,
|
asn: asn_result,
|
||||||
location: location_result,
|
location: location_result,
|
||||||
|
ip_info: ip_info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user