🏡 index : ~doyle/titanirc.git

author Jordan Doyle <jordan@doyle.la> 2024-01-31 2:25:20.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2024-01-31 2:25:20.0 +00:00:00
commit
0f4c2633739a7a5911b75539742de3cac3f454ea [patch]
tree
cb1d337e19cb60e18fd66f3968f14fbdc4842a88
parent
21ea94dd3e13c65736693e385a20b764579b86af
download
0f4c2633739a7a5911b75539742de3cac3f454ea.tar.gz

Implement hostname resolution



Diff

 Cargo.lock             | 163 +++++++++++++++++++++++++++++++++++++++++++++++++-
 Cargo.toml             |   1 +-
 src/connection.rs      |  21 +++++-
 src/main.rs            |   5 +-
 src/server/response.rs |   5 +-
 5 files changed, 191 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index b2e91c4..6ce7754 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -184,6 +184,17 @@ dependencies = [
]

[[package]]
name = "async-trait"
version = "0.1.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.48",
]

[[package]]
name = "atoi"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -452,6 +463,12 @@ dependencies = [
]

[[package]]
name = "data-encoding"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"

[[package]]
name = "der"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -554,6 +571,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"

[[package]]
name = "enum-as-inner"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a"
dependencies = [
 "heck",
 "proc-macro2",
 "quote",
 "syn 2.0.48",
]

[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -786,6 +815,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"

[[package]]
name = "hickory-proto"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "091a6fbccf4860009355e3efc52ff4acf37a63489aad7435372d44ceeb6fbbcf"
dependencies = [
 "async-trait",
 "cfg-if",
 "data-encoding",
 "enum-as-inner",
 "futures-channel",
 "futures-io",
 "futures-util",
 "idna 0.4.0",
 "ipnet",
 "once_cell",
 "rand",
 "thiserror",
 "tinyvec",
 "tokio",
 "tracing",
 "url",
]

[[package]]
name = "hickory-resolver"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35b8f021164e6a984c9030023544c57789c51760065cd510572fedcfb04164e8"
dependencies = [
 "cfg-if",
 "futures-util",
 "hickory-proto",
 "ipconfig",
 "lru-cache",
 "once_cell",
 "parking_lot",
 "rand",
 "resolv-conf",
 "smallvec",
 "thiserror",
 "tokio",
 "tracing",
]

[[package]]
name = "hkdf"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -813,6 +887,17 @@ dependencies = [
]

[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
 "libc",
 "match_cfg",
 "winapi",
]

[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -846,6 +931,16 @@ dependencies = [

[[package]]
name = "idna"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
dependencies = [
 "unicode-bidi",
 "unicode-normalization",
]

[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
@@ -865,6 +960,24 @@ dependencies = [
]

[[package]]
name = "ipconfig"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
dependencies = [
 "socket2",
 "widestring",
 "windows-sys 0.48.0",
 "winreg",
]

[[package]]
name = "ipnet"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"

[[package]]
name = "irc-proto"
version = "0.15.0"
source = "git+https://github.com/JordanForks/irc#923e080f2408ae301135e82549cff80e92aaa844"
@@ -933,6 +1046,12 @@ dependencies = [
]

[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"

[[package]]
name = "linux-raw-sys"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -955,6 +1074,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"

[[package]]
name = "lru-cache"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
dependencies = [
 "linked-hash-map",
]

[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"

[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1323,6 +1457,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"

[[package]]
name = "resolv-conf"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
dependencies = [
 "hostname",
 "quick-error",
]

[[package]]
name = "ring"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1905,6 +2049,7 @@ dependencies = [
 "clap",
 "const_format",
 "futures",
 "hickory-resolver",
 "irc-proto",
 "itertools",
 "rand",
@@ -2141,7 +2286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
dependencies = [
 "form_urlencoded",
 "idna",
 "idna 0.5.0",
 "percent-encoding",
]

@@ -2248,6 +2393,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50"

[[package]]
name = "widestring"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"

[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2420,6 +2571,16 @@ dependencies = [
]

[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
 "cfg-if",
 "windows-sys 0.48.0",
]

[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 8ea572b..0bbe178 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,6 +17,7 @@ const_format = "0.2"
chrono = "0.4"
clap = { version = "4.1", features = ["cargo", "derive", "std", "suggestions", "color"] }
futures = "0.3"
hickory-resolver = { version = "0.24", features = ["tokio-runtime", "system-config"] }
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
serde-humantime = "0.1"
diff --git a/src/connection.rs b/src/connection.rs
index c8cf981..1f59ecd 100644
--- a/src/connection.rs
+++ b/src/connection.rs
@@ -8,6 +8,7 @@ use std::{
    io::{Error, ErrorKind},
    net::SocketAddr,
    str::FromStr,
    time::Duration,
};

use actix::{io::FramedWrite, Actor, Addr};
@@ -15,6 +16,7 @@ use bitflags::bitflags;
use chrono::Utc;
use const_format::concatcp;
use futures::{SinkExt, TryStreamExt};
use hickory_resolver::TokioAsyncResolver;
use irc_proto::{
    error::ProtocolError, CapSubCommand, Command, IrcCodec, Message, Prefix, Response,
};
@@ -44,6 +46,7 @@ pub struct UserId(pub i64);
#[derive(Default)]
pub struct ConnectionRequest {
    host: Option<SocketAddr>,
    resolved_host: Option<String>,
    nick: Option<String>,
    user: Option<String>,
    real_name: Option<String>,
@@ -54,6 +57,7 @@ pub struct ConnectionRequest {
#[derive(Clone, Debug)]
pub struct InitiatedConnection {
    pub host: SocketAddr,
    pub resolved_host: Option<String>,
    pub cloak: String,
    pub nick: String,
    pub user: String,
@@ -87,6 +91,7 @@ impl TryFrom<ConnectionRequest> for InitiatedConnection {
    fn try_from(value: ConnectionRequest) -> Result<Self, Self::Error> {
        let ConnectionRequest {
            host: Some(host),
            resolved_host,
            nick: Some(nick),
            user: Some(user),
            real_name: Some(real_name),
@@ -99,7 +104,8 @@ impl TryFrom<ConnectionRequest> for InitiatedConnection {

        Ok(Self {
            host,
            cloak: format!("0{}", host.ip()),
            resolved_host: resolved_host.clone(),
            cloak: resolved_host.unwrap_or_else(|| "xxx".to_string()),
            nick,
            user,
            mode: UserMode::empty(),
@@ -121,6 +127,7 @@ pub async fn negotiate_client_connection(
    host: SocketAddr,
    persistence: &Addr<Persistence>,
    database: sqlx::Pool<sqlx::Any>,
    resolver: &TokioAsyncResolver,
) -> Result<Option<InitiatedConnection>, ProtocolError> {
    let mut request = ConnectionRequest {
        host: Some(host),
@@ -203,6 +210,18 @@ pub async fn negotiate_client_connection(
            }
        };

        if let Ok(Ok(v)) = tokio::time::timeout(
            Duration::from_millis(250),
            resolver.reverse_lookup(host.ip()),
        )
        .await
        {
            request.resolved_host = v
                .iter()
                .next()
                .map(|v| v.to_utf8().trim_end_matches('.').to_string());
        }

        match InitiatedConnection::try_from(std::mem::take(&mut request)) {
            Ok(v) => break Some(v),
            Err(v) => {
diff --git a/src/main.rs b/src/main.rs
index da80296..fc9ef05 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,6 +12,7 @@ use actix_rt::{Arbiter, System};
use bytes::BytesMut;
use clap::Parser;
use futures::SinkExt;
use hickory_resolver::AsyncResolver;
use irc_proto::{Command, IrcCodec, Message};
use rand::seq::SliceRandom;
use sqlx::migrate::Migrator;
@@ -113,6 +114,7 @@ async fn start_tcp_acceptor_loop(
    client_threads: usize,
) {
    let client_arbiters = Arc::new(build_arbiters(client_threads));
    let resolver = Arc::new(AsyncResolver::tokio_from_system_conf().unwrap());

    while let Ok((stream, addr)) = listener.accept().await {
        let span = info_span!("connection", %addr);
@@ -124,6 +126,7 @@ async fn start_tcp_acceptor_loop(
        let server = server.clone();
        let client_arbiters = client_arbiters.clone();
        let persistence = persistence.clone();
        let resolver = resolver.clone();

        actix_rt::spawn(async move {
            // split the stream into its read and write halves and setup codecs
@@ -133,7 +136,7 @@ async fn start_tcp_acceptor_loop(

            // ensure we have all the details required to actually connect the client to the server
            // (ie. we have a nick, user, etc)
            let connection = match connection::negotiate_client_connection(&mut read, &mut write, addr, &persistence, database).await {
            let connection = match connection::negotiate_client_connection(&mut read, &mut write, addr, &persistence, database, &resolver).await {
                Ok(Some(v)) => v,
                Ok(None) => {
                    error!("Failed to fully handshake with client, dropping connection");
diff --git a/src/server/response.rs b/src/server/response.rs
index f22bbbb..5f1e700 100644
--- a/src/server/response.rs
+++ b/src/server/response.rs
@@ -90,7 +90,10 @@ impl IntoProtocol for Whois {
                conn.nick.to_string(),
                format!(
                    "is connecting from {}@{} {}",
                    conn.user, conn.host, conn.host
                    conn.user,
                    conn.resolved_host
                        .unwrap_or_else(|| conn.host.ip().to_string()),
                    conn.host.ip()
                )
            ), // RPL_WHOISHOST
        ];