Compare commits

...

5 Commits

Author SHA1 Message Date
Jacob Kiers 5f0de72b88 Remove unused variable
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
Signed-off-by: Jacob Kiers <code@kiers.eu>
2023-08-25 22:56:46 +02:00
Jacob Kiers 40b890bc13 Add much better debug logging of address resolution
Signed-off-by: Jacob Kiers <code@kiers.eu>
2023-08-25 22:54:41 +02:00
Jacob Kiers 483c058105 Slightly better way of finding the config file
It now also looks in the current working directory.

Signed-off-by: Jacob Kiers <code@kiers.eu>
2023-08-25 22:53:46 +02:00
Jacob Kiers 6349fc6502 Prevent unnecessary clone
This also ensures that the address resolver actually keeps state.
Otherwise it was cloned before each resolution, resulting in it never
keeping the resolved addresses.

Signed-off-by: Jacob Kiers <code@kiers.eu>
2023-08-25 22:52:46 +02:00
Jacob Kiers cd35859c9b Initialize UpstreamAddress with actual address
Signed-off-by: Jacob Kiers <code@kiers.eu>
2023-08-25 22:51:25 +02:00
5 changed files with 57 additions and 18 deletions

View File

@ -173,6 +173,10 @@ fn load_config(path: &str) -> Result<ParsedConfig, ConfigError> {
name: name.to_string(),
addr: format!("{}:{}", upstream_host, upsteam_port),
protocol: upstream_url.scheme().to_string(),
addresses: Addr(Mutex::new(UpstreamAddress::new(format!(
"{}:{}",
upstream_host, upsteam_port
)))),
..Default::default()
}),
);

View File

@ -7,10 +7,10 @@ use crate::servers::Server;
use log::{debug, error};
use std::env;
use std::path::Path;
fn main() {
let config_path =
env::var("FOURTH_CONFIG").unwrap_or_else(|_| "/etc/fourth/config.yaml".to_string());
let config_path = find_config();
let config = match Config::new(&config_path) {
Ok(config) => config,
@ -27,3 +27,18 @@ fn main() {
let _ = server.run();
error!("Server ended with errors");
}
fn find_config() -> String {
let config_path =
env::var("FOURTH_CONFIG").unwrap_or_else(|_| "/etc/fourth/config.yaml".to_string());
if Path::new(&config_path).exists() {
return config_path;
}
if Path::new("config.yaml").exists() {
return String::from("config.yaml");
}
String::from("")
}

View File

@ -13,7 +13,6 @@ use protocol::tcp;
#[derive(Debug)]
pub(crate) struct Server {
pub proxies: Vec<Arc<Proxy>>,
pub config: ParsedConfig,
}
#[derive(Debug, Clone)]
@ -31,7 +30,6 @@ impl Server {
pub fn new(config: ParsedConfig) -> Self {
let mut new_server = Server {
proxies: Vec::new(),
config: config.clone(),
};
for (name, proxy) in config.servers.iter() {

View File

@ -72,21 +72,17 @@ async fn accept(inbound: TcpStream, proxy: Arc<Proxy>) -> Result<(), Box<dyn std
"No upstream named {:?} on server {:?}",
proxy.default_action, proxy.name
);
return process(
inbound,
proxy.upstream.get(&proxy.default_action).unwrap().clone(),
)
.await;
return process(inbound, proxy.upstream.get(&proxy.default_action).unwrap()).await;
// ToDo: Remove unwrap and check default option
}
};
return process(inbound, upstream.clone()).await;
return process(inbound, &upstream).await;
}
async fn process(
mut inbound: TcpStream,
upstream: Upstream,
upstream: &Upstream,
) -> Result<(), Box<dyn std::error::Error>> {
match upstream {
Upstream::Ban => {

View File

@ -19,6 +19,13 @@ impl Display for UpstreamAddress {
}
impl UpstreamAddress {
pub fn new(address: String) -> Self {
UpstreamAddress {
address,
..Default::default()
}
}
pub fn is_valid(&self) -> bool {
if let Some(resolved) = self.resolved_time {
if let Some(ttl) = self.ttl {
@ -44,20 +51,24 @@ impl UpstreamAddress {
pub async fn resolve(&mut self, mode: ResolutionMode) -> Result<Vec<SocketAddr>> {
if self.is_resolved() && self.is_valid() {
debug!(
"Already got address {:?}, still valid for {}",
"Already got address {:?}, still valid for {:.3}s",
&self.resolved_addresses,
self.time_remaining()
self.time_remaining().as_seconds_f64()
);
return Ok(self.resolved_addresses.clone());
}
debug!("Resolving addresses for {}", &self.address);
debug!(
"Resolving addresses for {} with mode {:?}",
&self.address, &mode
);
let lookup_result = tokio::net::lookup_host(&self.address).await;
let resolved_addresses = match lookup_result {
Ok(resolved_addresses) => resolved_addresses,
let resolved_addresses: Vec<SocketAddr> = match lookup_result {
Ok(resolved_addresses) => resolved_addresses.into_iter().collect(),
Err(e) => {
debug!("Failed looking up {}: {}", &self.address, &e);
// Protect against DNS flooding. Cache the result for 1 second.
self.resolved_time = Some(Instant::now());
self.ttl = Some(Duration::seconds(3));
@ -65,6 +76,8 @@ impl UpstreamAddress {
}
};
debug!("Resolved addresses: {:?}", &resolved_addresses);
let addresses: Vec<SocketAddr> = match mode {
ResolutionMode::Ipv4 => resolved_addresses
.into_iter()
@ -76,10 +89,13 @@ impl UpstreamAddress {
.filter(|a| a.is_ipv6())
.collect(),
_ => resolved_addresses.collect(),
_ => resolved_addresses,
};
debug!("Got addresses for {}: {:?}", &self.address, &addresses);
debug!(
"Got {} addresses for {}: {:?}",
&mode, &self.address, &addresses
);
debug!(
"Resolved at {}",
OffsetDateTime::now_utc()
@ -113,3 +129,13 @@ impl From<&str> for ResolutionMode {
}
}
}
impl Display for ResolutionMode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ResolutionMode::Ipv4 => write!(f, "IPv4Only"),
ResolutionMode::Ipv6 => write!(f, "IPv6Only"),
ResolutionMode::Ipv4AndIpv6 => write!(f, "IPv4 and IPv6"),
}
}
}