Working settings file! (partially)

This commit is contained in:
Slatian 2023-02-18 22:16:09 +01:00
parent 2394d90087
commit 645a0eed69
8 changed files with 478 additions and 39 deletions

273
Cargo.lock generated
View File

@ -70,6 +70,17 @@ dependencies = [
"tower-service",
]
[[package]]
name = "axum-client-ip"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d719fabd6813392bbc10e1fe67f2977fad52791a836e51236f7e02f2482e017"
dependencies = [
"axum",
"forwarded-header-value",
"serde",
]
[[package]]
name = "axum-core"
version = "0.3.2"
@ -170,6 +181,43 @@ dependencies = [
"phf_codegen",
]
[[package]]
name = "clap"
version = "4.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
dependencies = [
"bitflags",
"clap_derive",
"clap_lex",
"is-terminal",
"once_cell",
"strsim",
"termcolor",
]
[[package]]
name = "clap_derive"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "codespan-reporting"
version = "0.11.1"
@ -283,6 +331,27 @@ dependencies = [
"syn",
]
[[package]]
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -298,6 +367,16 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "forwarded-header-value"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9"
dependencies = [
"nonempty",
"thiserror",
]
[[package]]
name = "futures-channel"
version = "0.3.25"
@ -383,6 +462,12 @@ dependencies = [
"walkdir",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "heck"
version = "0.4.1"
@ -398,6 +483,12 @@ dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "hostname"
version = "0.3.1"
@ -540,6 +631,26 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "indexmap"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "io-lifetimes"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
dependencies = [
"libc",
"windows-sys 0.45.0",
]
[[package]]
name = "ipconfig"
version = "0.3.1"
@ -558,6 +669,18 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
[[package]]
name = "is-terminal"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef"
dependencies = [
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
"windows-sys 0.45.0",
]
[[package]]
name = "itoa"
version = "1.0.5"
@ -600,6 +723,12 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "lock_api"
version = "0.4.9"
@ -677,9 +806,24 @@ dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
name = "nom8"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
dependencies = [
"memchr",
]
[[package]]
name = "nonempty"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7"
[[package]]
name = "num-integer"
version = "0.1.45"
@ -705,7 +849,7 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
"hermit-abi",
"hermit-abi 0.2.6",
"libc",
]
@ -715,6 +859,12 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "os_str_bytes"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -735,7 +885,7 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@ -874,6 +1024,30 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.50"
@ -969,14 +1143,30 @@ name = "rust-web-thingy"
version = "0.1.0"
dependencies = [
"axum",
"axum-client-ip",
"clap",
"maxminddb",
"rand",
"serde",
"tera",
"tokio",
"toml",
"trust-dns-resolver",
]
[[package]]
name = "rustix"
version = "0.36.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys 0.45.0",
]
[[package]]
name = "rustversion"
version = "1.0.11"
@ -1050,6 +1240,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -1122,6 +1321,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.107"
@ -1231,7 +1436,7 @@ dependencies = [
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@ -1245,6 +1450,40 @@ dependencies = [
"syn",
]
[[package]]
name = "toml"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6a7712b49e1775fb9a7b998de6635b299237f48b404dde71704f2e0e7f37e5"
dependencies = [
"indexmap",
"nom8",
"serde",
"serde_spanned",
"toml_datetime",
]
[[package]]
name = "tower"
version = "0.4.13"
@ -1624,6 +1863,30 @@ dependencies = [
"windows_x86_64_msvc",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
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",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"

View File

@ -2,14 +2,17 @@
name = "rust-web-thingy"
version = "0.1.0"
edition = "2021"
authors = ["Slatian <baschdel@disroot.org>"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
axum = "0.6"
rand = "0.8"
axum-client-ip = "0.4"
clap = { version = "4", features = ["derive"] }
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
tera = "1"
toml = "0.7"
trust-dns-resolver = "0.22"
maxminddb = "0.17"

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# echoip-slatecave
## Building
Simply run `cargo build` after cloning.
NOTE: As of 2023-02-18 You need at least version 1.65 of the rust compiler. Consider using rustup.

42
echoip_config.toml Normal file
View File

@ -0,0 +1,42 @@
[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 = 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
# that end with one of these suffixes don't exist
#hidden_suffixes = [".local"]
[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"

View File

@ -1,45 +1,44 @@
use std::path::Path;
use axum_client_ip::SecureClientIpSource;
use std::net::SocketAddr;
#[derive(serde::Deserialize)]
#[derive(serde::Deserialize, Default)]
pub struct EchoIpServiceConfig {
server: ServerConfig,
dns: DnsConfig,
geoip: GeoIpConfig,
template: TemplateConfig,
pub server: ServerConfig,
pub dns: DnsConfig,
pub geoip: GeoIpConfig,
pub template: TemplateConfig,
}
#[derive(serde::Deserialize)]
pub struct ServerConfig {
listen_on: SocketAddr,
ip_header: SecureClientIpSource,
pub listen_on: SocketAddr,
pub ip_header: SecureClientIpSource,
}
#[derive(serde::Deserialize)]
pub struct DnsConfig {
allow_forward_lookup: bool,
allow_reverse_lookup: bool,
hide_private_range_ips: bool,
hidden_suffixes: Vec<String>,
pub allow_forward_lookup: bool,
pub allow_reverse_lookup: bool,
pub hide_private_range_ips: bool,
pub hidden_suffixes: Vec<String>,
//Future Idea: allow custom resolver
}
#[derive(serde::Deserialize)]
pub struct GeoIpConfig {
asn_database: Option<String>,
location_database: Option<String>,
pub asn_database: Option<String>,
pub location_database: Option<String>,
}
#[derive(serde::Deserialize)]
pub struct TemplateConfig {
template_location: String,
pub template_location: String,
}
impl Default for ServerConfig {
fn default() -> Self {
ServerConfig {
listen_on: "127.0.0.1:3000",
listen_on: "127.0.0.1:3000".parse().unwrap(),
ip_header: SecureClientIpSource::RightmostXForwardedFor,
}
}
@ -48,10 +47,27 @@ impl Default for ServerConfig {
impl Default for DnsConfig {
fn default() -> Self {
DnsConfig {
allow_forward_lookup: true;
allow_reverse_lookup: false;
hide_private_range_ips: true;
hidden_suffixes: Vec::new();
allow_forward_lookup: true,
allow_reverse_lookup: false,
hide_private_range_ips: true,
hidden_suffixes: Vec::new(),
}
}
}
impl Default for GeoIpConfig {
fn default() -> Self {
GeoIpConfig {
asn_database: Some("mmdb/GeoLite2-ASN.mmdb".to_string()),
location_database: Some("mmdb/GeoLite2-City.mmdb".to_string()),
}
}
}
impl Default for TemplateConfig {
fn default() -> Self {
TemplateConfig {
template_location: "templates/".to_string(),
}
}
}

View File

@ -7,7 +7,7 @@ use axum::{
routing::get,
};
use axum_client_ip::{SecureClientIp, SecureClientIpSource};
use clap::Parser;
use tera::Tera;
use trust_dns_resolver::{
TokioAsyncResolver,
@ -15,6 +15,7 @@ use trust_dns_resolver::{
config::ResolverConfig,
};
use std::fs;
use std::net::IpAddr;
use std::sync::Arc;
use std::path::Path;
@ -64,15 +65,50 @@ struct ServiceSharedState {
dns_resolver: TokioAsyncResolver,
asn_db: geoip::MMDBCarrier,
location_db: geoip::MMDBCarrier,
config: config::EchoIpServiceConfig,
}
#[derive(Parser)]
#[command(author, version, long_about="None")]
struct CliArgs {
#[arg(short, long)]
config: Option<String>,
#[arg(short, long)]
listen_on: Option<String>,
#[arg(short, long)]
templates: Option<String>,
}
#[tokio::main]
async fn main() {
// Parse Command line arguments
let cli_args = CliArgs::parse();
// Read configuration file
let config: config::EchoIpServiceConfig = match cli_args.config {
Some(config_path) => {
let config_text = fs::read_to_string(config_path)
.expect("Can't read configuration file!");
match toml::from_str(&config_text) {
Ok(c) => c,
Err(e) => {
panic!("Unable to parse configuration file: {e}");
}
}
},
None => Default::default(),
};
// Initalize Tera templates
// TODO: don't hardcode template directory
println!("Parsing Templates ...");
let res = Tera::new("templates/*.html");
let mut template_base_dir = (&config.template.template_location).to_owned();
if !template_base_dir.ends_with("/") {
template_base_dir = template_base_dir + "/";
}
let template_glob = template_base_dir+"*.html";
println!("Parsing Templates from '{}' ...", &template_glob);
let res = Tera::new((template_glob).as_str());
let tera = match res {
Ok(t) => t,
Err(e) => {
@ -87,13 +123,19 @@ async fn main() {
mmdb: None,
name: "GeoIP ASN Database".to_string(),
};
asn_db.load_database_from_path(Path::new("mmdb/GeoLite2-ASN.mmdb")).ok();
match &config.geoip.asn_database {
Some(path) => { asn_db.load_database_from_path(Path::new(&path)).ok(); },
None => {},
}
let mut location_db = geoip::MMDBCarrier {
mmdb: None,
name: "GeoIP Location Database".to_string(),
};
location_db.load_database_from_path(Path::new("mmdb/GeoLite2-City.mmdb")).ok();
match &config.geoip.location_database {
Some(path) => { location_db.load_database_from_path(Path::new(&path)).ok(); },
None => {},
}
// Initalize DNS resolver with os defaults
println!("Initalizing dns resolver ...");
@ -105,16 +147,19 @@ async fn main() {
::std::process::exit(1);
}
};
let listen_on = config.server.listen_on;
// Initialize shared state
let shared_state = Arc::new(
ServiceSharedState{
ServiceSharedState {
templating_engine: templating_engine::Engine{
tera: tera,
},
dns_resolver: dns_resolver,
asn_db: asn_db,
location_db: location_db,
config: config,
});
// Initalize axum server
@ -131,7 +176,7 @@ async fn main() {
println!("Starting Server ...");
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
axum::Server::bind(&listen_on)
.serve(app.into_make_service())
.await
.unwrap();

View File

@ -8,30 +8,36 @@
<body>
<h1>Lookup for: {{ q.name }}</h1>
{% if r.a %}
<p>A (IPv4) records:</p>
<p><code>A</code> (IPv4) records:</p>
<ul>
{% for address in r.a%}
<li><code>{{address}}</code></li>
<li><code><a href="/ip?ip={{address}}">{{address}}</a></code></li>
{% endfor %}
</ul>
{% else %}
<p>No <code>A</code> (IPv4) Records.</p>
{% endif %}
{% if r.aaaa %}
<p>AAAA (IPv6) records:</p>
<p><code>AAAA</code> (IPv6) records:</p>
<ul>
{% for address in r.aaaa%}
<li><code>{{address}}</code></li>
<li><code><a href="/ip?ip={{address}}">{{address}}</a></code></li>
{% endfor %}
</ul>
{% else %}
<p>No <code>AAAA</code> (IPv6) Records.</p>
{% endif %}
{% if r.mx %}
<p>MX (Mail Exchange) records:</p>
<p><code>MX</code> (Mail Exchange) records:</p>
<ul>
{% for mx in r.mx%}
<li>{{mx.preference}} <code><a href="/dig?name={{mx.exchange}}">{{mx.exchange}}</a></code></li>
{% endfor %}
</ul>
{% else %}
<p>No <code>MX</code> (Mail Exchange) records.</p>
{% endif %}
</body>

57
templates/ip.html Normal file
View File

@ -0,0 +1,57 @@
{% import "helpers.html" as helper %}
<!DOCTYPE html>
<html>
<head>
<title>{{ data.query.ip }}</title>
</head>
<body>
{% set r = data.result %}
<h1>About IP-Address: {{ data.query.ip }}</h1>
<section>
<h2>Network Information</h2>
<dl>
{% if r.hostname %}
<dh>Hostname</dh>
<dd><a href="/dig?name={{r.hostname}}">{{r.hostname}}</a></dd>
{% endif %}
{% if r.asn %}
<dh><abbr="Autonomous System Number">ASN</abbr></dh>
<dd>AS{{r.asn.asn}}</dd>
<dh>AS Name</dh>
<dd>{{ r.asn.name }}</dd>
</dl>
{% endif %}
</section>
{% if r.location %}
<section>
<h2>Geolocation</h2>
<dl>
{{ helper::place_dl(place=r.location.continent, label="Continent") }}
{{ helper::place_dl(place=r.location.country, label="Country") }}
{{ helper::place_dl(place=r.location.registered_country, label="Registred in") }}
{{ helper::place_dl(place=r.location.represented_country, label="Represents") }}
{% if r.location.subdivisions %}
{% for sd in r.location.subdivisions %}
{{ helper::place_dl(place=sd, label="Subdivision", iso_code_prefix=r.location.country.iso_code|default(value="")) }}
{% endfor %}
{% endif %}
{{ helper::place_dl(place=r.location.city, label="City") }}
{% if r.location.postal_code %}
<dh>Postal Code</dh>
<dd>{{r.location.postal_code}}</dd>
{% endif %}
{% if r.location.time_zone %}
<dh>Timezone</dh>
<dd>{{r.location.time_zone}}</dd>
{% endif %}
</dl>
<!--We have to put that there to comply with maxminds licensing-->
<p><small>
The GeopIP and ASN information is provided by the GeoLite2 database created by
<a target="_blank" href="https://www.maxmind.com">MaxMind</a>.
</small></p>
</section>
{% endif %}
</body>
</html>