net: allow dial randomly
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use futures::TryFutureExt;
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::SeedableRng;
|
||||
|
||||
use crate::app::SyncDnsClient;
|
||||
use crate::proxy::DialOrder;
|
||||
|
||||
pub struct Resolver {
|
||||
ips: Vec<IpAddr>,
|
||||
port: u16,
|
||||
addrs: Vec<SocketAddr>,
|
||||
}
|
||||
|
||||
impl Resolver {
|
||||
@@ -24,10 +27,17 @@ impl Resolver {
|
||||
.map_err(|e| anyhow!("lookup {} failed: {}", address, e))
|
||||
.await?
|
||||
};
|
||||
ips.reverse();
|
||||
match *crate::option::OUTBOUND_DIAL_ORDER {
|
||||
DialOrder::Ordered => ips.reverse(),
|
||||
DialOrder::Random => ips.shuffle(&mut StdRng::from_entropy()),
|
||||
DialOrder::PartialRandom => {
|
||||
let head = ips.remove(0);
|
||||
ips.shuffle(&mut StdRng::from_entropy());
|
||||
ips.push(head);
|
||||
}
|
||||
}
|
||||
Ok(Resolver {
|
||||
ips,
|
||||
port: port.to_owned(),
|
||||
addrs: ips.into_iter().map(|x| SocketAddr::new(x, *port)).collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -36,6 +46,6 @@ impl Iterator for Resolver {
|
||||
type Item = SocketAddr;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.ips.pop().map(|ip| SocketAddr::new(ip, self.port))
|
||||
self.addrs.pop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,14 @@ lazy_static! {
|
||||
get_env_var_or("OUTBOUND_DIAL_TIMEOUT", 4)
|
||||
};
|
||||
|
||||
pub static ref OUTBOUND_DIAL_ORDER: crate::proxy::DialOrder = {
|
||||
match get_env_var_or("OUTBOUND_DIAL_ORDER", "ordered".to_string()).as_str() {
|
||||
"random" => crate::proxy::DialOrder::Random,
|
||||
"partial-random" => crate::proxy::DialOrder::PartialRandom,
|
||||
_ => crate::proxy::DialOrder::Ordered,
|
||||
}
|
||||
};
|
||||
|
||||
/// Maximum outbound dial concurrency.
|
||||
pub static ref OUTBOUND_DIAL_CONCURRENCY: usize = {
|
||||
get_env_var_or("OUTBOUND_DIAL_CONCURRENCY", 1)
|
||||
|
||||
@@ -332,6 +332,19 @@ fn apply_socket_opts<S: AsRawSocket>(socket: &S) -> io::Result<()> {
|
||||
apply_socket_opts_internal(sock_ref)
|
||||
}
|
||||
|
||||
// TCP dial order.
|
||||
#[derive(PartialEq)]
|
||||
pub enum DialOrder {
|
||||
// Leave the order of IPs untouched.
|
||||
Ordered,
|
||||
// Randomize the IPs.
|
||||
Random,
|
||||
// Randomize the IPs except the first one. We have a little optimization in
|
||||
// the DNS client that moves the previously connected IP to the head, we want
|
||||
// that IP always tried first.
|
||||
PartialRandom,
|
||||
}
|
||||
|
||||
// A single TCP dial.
|
||||
async fn tcp_dial_task(dial_addr: SocketAddr) -> io::Result<(AnyStream, SocketAddr)> {
|
||||
let socket = match dial_addr {
|
||||
|
||||
Reference in New Issue
Block a user