mirror of
https://github.com/EasyTier/EasyTier.git
synced 2025-10-18 14:50:43 +08:00
support exit node (#121)
support exit node, proxy all traffic via one of node NOTE: this patch has not implemented automatically route management.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
net::SocketAddr,
|
net::{Ipv4Addr, SocketAddr},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
@@ -58,6 +58,9 @@ pub trait ConfigLoader: Send + Sync {
|
|||||||
fn get_flags(&self) -> Flags;
|
fn get_flags(&self) -> Flags;
|
||||||
fn set_flags(&self, flags: Flags);
|
fn set_flags(&self, flags: Flags);
|
||||||
|
|
||||||
|
fn get_exit_nodes(&self) -> Vec<Ipv4Addr>;
|
||||||
|
fn set_exit_nodes(&self, nodes: Vec<Ipv4Addr>);
|
||||||
|
|
||||||
fn dump(&self) -> String;
|
fn dump(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,6 +158,8 @@ pub struct Flags {
|
|||||||
pub mtu: u16,
|
pub mtu: u16,
|
||||||
#[derivative(Default(value = "true"))]
|
#[derivative(Default(value = "true"))]
|
||||||
pub latency_first: bool,
|
pub latency_first: bool,
|
||||||
|
#[derivative(Default(value = "false"))]
|
||||||
|
pub enable_exit_node: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
||||||
@@ -167,6 +172,7 @@ struct Config {
|
|||||||
dhcp: Option<bool>,
|
dhcp: Option<bool>,
|
||||||
network_identity: Option<NetworkIdentity>,
|
network_identity: Option<NetworkIdentity>,
|
||||||
listeners: Option<Vec<url::Url>>,
|
listeners: Option<Vec<url::Url>>,
|
||||||
|
exit_nodes: Option<Vec<Ipv4Addr>>,
|
||||||
|
|
||||||
peer: Option<Vec<PeerConfig>>,
|
peer: Option<Vec<PeerConfig>>,
|
||||||
proxy_network: Option<Vec<NetworkConfig>>,
|
proxy_network: Option<Vec<NetworkConfig>>,
|
||||||
@@ -459,6 +465,19 @@ impl ConfigLoader for TomlConfigLoader {
|
|||||||
self.config.lock().unwrap().flags = Some(flags);
|
self.config.lock().unwrap().flags = Some(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_exit_nodes(&self) -> Vec<Ipv4Addr> {
|
||||||
|
self.config
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.exit_nodes
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_exit_nodes(&self, nodes: Vec<Ipv4Addr>) {
|
||||||
|
self.config.lock().unwrap().exit_nodes = Some(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
fn dump(&self) -> String {
|
fn dump(&self) -> String {
|
||||||
toml::to_string_pretty(&*self.config.lock().unwrap()).unwrap()
|
toml::to_string_pretty(&*self.config.lock().unwrap()).unwrap()
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,12 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use std::{backtrace, io::Write as _, net::SocketAddr, path::PathBuf};
|
use std::{
|
||||||
|
backtrace,
|
||||||
|
io::Write as _,
|
||||||
|
net::{Ipv4Addr, SocketAddr},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
@@ -179,6 +184,20 @@ and the vpn client is in network of 10.14.14.0/24"
|
|||||||
default_value = "false"
|
default_value = "false"
|
||||||
)]
|
)]
|
||||||
latency_first: bool,
|
latency_first: bool,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "exit nodes to forward all traffic to, a virtual ipv4 address, priority is determined by the order of the list",
|
||||||
|
num_args = 0..
|
||||||
|
)]
|
||||||
|
exit_nodes: Vec<Ipv4Addr>,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "allow this node to be an exit node, default is false",
|
||||||
|
default_value = "false"
|
||||||
|
)]
|
||||||
|
enable_exit_node: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cli {
|
impl Cli {
|
||||||
@@ -394,8 +413,11 @@ impl From<Cli> for TomlConfigLoader {
|
|||||||
if let Some(mtu) = cli.mtu {
|
if let Some(mtu) = cli.mtu {
|
||||||
f.mtu = mtu;
|
f.mtu = mtu;
|
||||||
}
|
}
|
||||||
|
f.enable_exit_node = cli.enable_exit_node;
|
||||||
cfg.set_flags(f);
|
cfg.set_flags(f);
|
||||||
|
|
||||||
|
cfg.set_exit_nodes(cli.exit_nodes.clone());
|
||||||
|
|
||||||
cfg
|
cfg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -248,6 +248,7 @@ impl IcmpProxy {
|
|||||||
async fn try_handle_peer_packet(&self, packet: &ZCPacket) -> Option<()> {
|
async fn try_handle_peer_packet(&self, packet: &ZCPacket) -> Option<()> {
|
||||||
let _ = self.global_ctx.get_ipv4()?;
|
let _ = self.global_ctx.get_ipv4()?;
|
||||||
let hdr = packet.peer_manager_header().unwrap();
|
let hdr = packet.peer_manager_header().unwrap();
|
||||||
|
let is_exit_node = hdr.is_exit_node();
|
||||||
|
|
||||||
if hdr.packet_type != PacketType::Data as u8 {
|
if hdr.packet_type != PacketType::Data as u8 {
|
||||||
return None;
|
return None;
|
||||||
@@ -260,7 +261,7 @@ impl IcmpProxy {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.cidr_set.contains_v4(ipv4.get_destination()) {
|
if !self.cidr_set.contains_v4(ipv4.get_destination()) && !is_exit_node {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -358,6 +358,7 @@ impl TcpProxy {
|
|||||||
async fn try_handle_peer_packet(&self, packet: &mut ZCPacket) -> Option<()> {
|
async fn try_handle_peer_packet(&self, packet: &mut ZCPacket) -> Option<()> {
|
||||||
let ipv4_addr = self.global_ctx.get_ipv4()?;
|
let ipv4_addr = self.global_ctx.get_ipv4()?;
|
||||||
let hdr = packet.peer_manager_header().unwrap();
|
let hdr = packet.peer_manager_header().unwrap();
|
||||||
|
let is_exit_node = hdr.is_exit_node();
|
||||||
|
|
||||||
if hdr.packet_type != PacketType::Data as u8 {
|
if hdr.packet_type != PacketType::Data as u8 {
|
||||||
return None;
|
return None;
|
||||||
@@ -370,7 +371,7 @@ impl TcpProxy {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.cidr_set.contains_v4(ipv4.get_destination()) {
|
if !self.cidr_set.contains_v4(ipv4.get_destination()) && !is_exit_node {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -233,6 +233,7 @@ impl UdpProxy {
|
|||||||
|
|
||||||
let _ = self.global_ctx.get_ipv4()?;
|
let _ = self.global_ctx.get_ipv4()?;
|
||||||
let hdr = packet.peer_manager_header().unwrap();
|
let hdr = packet.peer_manager_header().unwrap();
|
||||||
|
let is_exit_node = hdr.is_exit_node();
|
||||||
if hdr.packet_type != PacketType::Data as u8 {
|
if hdr.packet_type != PacketType::Data as u8 {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
@@ -242,7 +243,7 @@ impl UdpProxy {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.cidr_set.contains_v4(ipv4.get_destination()) {
|
if !self.cidr_set.contains_v4(ipv4.get_destination()) && !is_exit_node {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -68,7 +68,9 @@ impl IpProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn start(&self) -> Result<(), Error> {
|
async fn start(&self) -> Result<(), Error> {
|
||||||
if self.global_ctx.get_proxy_cidrs().is_empty() || self.started.load(Ordering::Relaxed) {
|
if (self.global_ctx.get_proxy_cidrs().is_empty() || self.started.load(Ordering::Relaxed))
|
||||||
|
&& !self.global_ctx.config.get_flags().enable_exit_node
|
||||||
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -155,6 +155,8 @@ pub struct PeerManager {
|
|||||||
foreign_network_client: Arc<ForeignNetworkClient>,
|
foreign_network_client: Arc<ForeignNetworkClient>,
|
||||||
|
|
||||||
encryptor: Arc<Box<dyn Encryptor>>,
|
encryptor: Arc<Box<dyn Encryptor>>,
|
||||||
|
|
||||||
|
exit_nodes: Vec<Ipv4Addr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for PeerManager {
|
impl Debug for PeerManager {
|
||||||
@@ -238,6 +240,8 @@ impl PeerManager {
|
|||||||
my_peer_id,
|
my_peer_id,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let exit_nodes = global_ctx.config.get_exit_nodes();
|
||||||
|
|
||||||
PeerManager {
|
PeerManager {
|
||||||
my_peer_id,
|
my_peer_id,
|
||||||
|
|
||||||
@@ -262,6 +266,7 @@ impl PeerManager {
|
|||||||
foreign_network_client,
|
foreign_network_client,
|
||||||
|
|
||||||
encryptor,
|
encryptor,
|
||||||
|
exit_nodes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,6 +578,7 @@ impl PeerManager {
|
|||||||
ipv4_addr
|
ipv4_addr
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut is_exit_node = false;
|
||||||
let mut dst_peers = vec![];
|
let mut dst_peers = vec![];
|
||||||
// NOTE: currently we only support ipv4 and cidr is 24
|
// NOTE: currently we only support ipv4 and cidr is 24
|
||||||
if ipv4_addr.is_broadcast() || ipv4_addr.is_multicast() || ipv4_addr.octets()[3] == 255 {
|
if ipv4_addr.is_broadcast() || ipv4_addr.is_multicast() || ipv4_addr.octets()[3] == 255 {
|
||||||
@@ -585,6 +591,14 @@ impl PeerManager {
|
|||||||
);
|
);
|
||||||
} else if let Some(peer_id) = self.peers.get_peer_id_by_ipv4(&ipv4_addr).await {
|
} else if let Some(peer_id) = self.peers.get_peer_id_by_ipv4(&ipv4_addr).await {
|
||||||
dst_peers.push(peer_id);
|
dst_peers.push(peer_id);
|
||||||
|
} else {
|
||||||
|
for exit_node in &self.exit_nodes {
|
||||||
|
if let Some(peer_id) = self.peers.get_peer_id_by_ipv4(exit_node).await {
|
||||||
|
dst_peers.push(peer_id);
|
||||||
|
is_exit_node = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dst_peers.is_empty() {
|
if dst_peers.is_empty() {
|
||||||
@@ -605,7 +619,8 @@ impl PeerManager {
|
|||||||
let is_latency_first = self.global_ctx.get_flags().latency_first;
|
let is_latency_first = self.global_ctx.get_flags().latency_first;
|
||||||
msg.mut_peer_manager_header()
|
msg.mut_peer_manager_header()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_latency_first(is_latency_first);
|
.set_latency_first(is_latency_first)
|
||||||
|
.set_exit_node(is_exit_node);
|
||||||
let next_hop_policy = Self::get_next_hop_policy(is_latency_first);
|
let next_hop_policy = Self::get_next_hop_policy(is_latency_first);
|
||||||
|
|
||||||
let mut errs: Vec<Error> = vec![];
|
let mut errs: Vec<Error> = vec![];
|
||||||
|
@@ -60,6 +60,7 @@ bitflags::bitflags! {
|
|||||||
struct PeerManagerHeaderFlags: u8 {
|
struct PeerManagerHeaderFlags: u8 {
|
||||||
const ENCRYPTED = 0b0000_0001;
|
const ENCRYPTED = 0b0000_0001;
|
||||||
const LATENCY_FIRST = 0b0000_0010;
|
const LATENCY_FIRST = 0b0000_0010;
|
||||||
|
const EXIT_NODE = 0b0000_0100;
|
||||||
|
|
||||||
const _ = !0;
|
const _ = !0;
|
||||||
}
|
}
|
||||||
@@ -101,7 +102,13 @@ impl PeerManagerHeader {
|
|||||||
.contains(PeerManagerHeaderFlags::LATENCY_FIRST)
|
.contains(PeerManagerHeaderFlags::LATENCY_FIRST)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_latency_first(&mut self, latency_first: bool) {
|
pub fn is_exit_node(&self) -> bool {
|
||||||
|
PeerManagerHeaderFlags::from_bits(self.flags)
|
||||||
|
.unwrap()
|
||||||
|
.contains(PeerManagerHeaderFlags::EXIT_NODE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_latency_first(&mut self, latency_first: bool) -> &mut Self {
|
||||||
let mut flags = PeerManagerHeaderFlags::from_bits(self.flags).unwrap();
|
let mut flags = PeerManagerHeaderFlags::from_bits(self.flags).unwrap();
|
||||||
if latency_first {
|
if latency_first {
|
||||||
flags.insert(PeerManagerHeaderFlags::LATENCY_FIRST);
|
flags.insert(PeerManagerHeaderFlags::LATENCY_FIRST);
|
||||||
@@ -109,6 +116,18 @@ impl PeerManagerHeader {
|
|||||||
flags.remove(PeerManagerHeaderFlags::LATENCY_FIRST);
|
flags.remove(PeerManagerHeaderFlags::LATENCY_FIRST);
|
||||||
}
|
}
|
||||||
self.flags = flags.bits();
|
self.flags = flags.bits();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_exit_node(&mut self, exit_node: bool) -> &mut Self {
|
||||||
|
let mut flags = PeerManagerHeaderFlags::from_bits(self.flags).unwrap();
|
||||||
|
if exit_node {
|
||||||
|
flags.insert(PeerManagerHeaderFlags::EXIT_NODE);
|
||||||
|
} else {
|
||||||
|
flags.remove(PeerManagerHeaderFlags::EXIT_NODE);
|
||||||
|
}
|
||||||
|
self.flags = flags.bits();
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user