feat: custom hostname

This commit is contained in:
m1m1sha
2024-05-08 14:47:22 +08:00
parent c3df9ea7fa
commit 0498b55d39
10 changed files with 91 additions and 8 deletions

3
Cargo.lock generated
View File

@@ -387,7 +387,7 @@ dependencies = [
[[package]] [[package]]
name = "boringtun" name = "boringtun"
version = "0.6.0" version = "0.6.0"
source = "git+https://github.com/KKRainbow/boringtun.git#449204c3eca736dc23b075d81426527a357e2f2a" source = "git+https://github.com/EasyTier/boringtun.git#449204c3eca736dc23b075d81426527a357e2f2a"
dependencies = [ dependencies = [
"aead", "aead",
"atomic-shim", "atomic-shim",
@@ -1309,6 +1309,7 @@ dependencies = [
"quinn", "quinn",
"rand 0.8.5", "rand 0.8.5",
"rcgen", "rcgen",
"regex",
"reqwest", "reqwest",
"ring 0.17.8", "ring 0.17.8",
"rstest", "rstest",

View File

@@ -32,6 +32,7 @@ settings: 设置
exchange_language: Switch to English exchange_language: Switch to English
exit: 退出 exit: 退出
chips_placeholder: 例如: {0}, 按回车添加 chips_placeholder: 例如: {0}, 按回车添加
hostname_placeholder: 留空默认为设备名称
off_text: 点击关闭 off_text: 点击关闭
on_text: 点击开启 on_text: 点击开启
show_config: 显示配置 show_config: 显示配置

View File

@@ -33,6 +33,7 @@ exchange_language: 切换中文
exit: Exit exit: Exit
chips_placeholder: 'e.g: {0}, press Enter to add' chips_placeholder: 'e.g: {0}, press Enter to add'
hostname_placeholder: Leave blank and default to device name
off_text: Press to disable off_text: Press to disable
on_text: Press to enable on_text: Press to enable
show_config: Show Config show_config: Show Config

View File

@@ -42,6 +42,7 @@ struct NetworkConfig {
instance_id: String, instance_id: String,
virtual_ipv4: String, virtual_ipv4: String,
hostname: Option<String>,
network_name: String, network_name: String,
network_secret: String, network_secret: String,
networking_method: NetworkingMethod, networking_method: NetworkingMethod,
@@ -70,6 +71,7 @@ impl NetworkConfig {
.parse() .parse()
.with_context(|| format!("failed to parse instance id: {}", self.instance_id))?, .with_context(|| format!("failed to parse instance id: {}", self.instance_id))?,
); );
cfg.set_hostname(self.hostname.clone());
cfg.set_inst_name(self.network_name.clone()); cfg.set_inst_name(self.network_name.clone());
cfg.set_network_identity(NetworkIdentity::new( cfg.set_network_identity(NetworkIdentity::new(
self.network_name.clone(), self.network_name.clone(),

View File

@@ -32,6 +32,18 @@ const curNetwork = computed(() => {
const presetPublicServers = [ const presetPublicServers = [
'tcp://easytier.public.kkrainbow.top:11010', 'tcp://easytier.public.kkrainbow.top:11010',
] ]
function validateHostname() {
if (curNetwork.value.hostname) {
// eslint no-useless-escape
let name = curNetwork.value.hostname!.replaceAll(/[^\u4E00-\u9FA5a-zA-Z0-9\-]*/g, '')
if (name.length > 32)
name = name.substring(0, 32)
if (curNetwork.value.hostname !== name)
curNetwork.value.hostname = name
}
}
</script> </script>
<template> <template>
@@ -151,6 +163,14 @@ const presetPublicServers = [
/> />
</div> </div>
</div> </div>
<div class="flex flex-row gap-x-9 flex-wrap">
<div class="flex flex-column gap-2 basis-5/12 grow">
<label for="hostname">{{ $t('hostname') }}</label>
<InputText
id="hostname" v-model="curNetwork.hostname" aria-describedby="hostname-help" :format="true" @blur="validateHostname"
/>
</div>
</div>
</div> </div>
</Panel> </Panel>

View File

@@ -10,6 +10,7 @@ export interface NetworkConfig {
instance_id: string instance_id: string
virtual_ipv4: string virtual_ipv4: string
hostname?: string
network_name: string network_name: string
network_secret: string network_secret: string

View File

@@ -58,6 +58,8 @@ async-trait = "0.1.74"
dashmap = "5.5.3" dashmap = "5.5.3"
timedmap = "=1.0.1" timedmap = "=1.0.1"
regex = "1"
# for full-path zero-copy # for full-path zero-copy
zerocopy = { version = "0.7.32", features = ["derive", "simd"] } zerocopy = { version = "0.7.32", features = ["derive", "simd"] }
bytes = "1.5.0" bytes = "1.5.0"

View File

@@ -14,6 +14,9 @@ pub trait ConfigLoader: Send + Sync {
fn get_id(&self) -> uuid::Uuid; fn get_id(&self) -> uuid::Uuid;
fn set_id(&self, id: uuid::Uuid); fn set_id(&self, id: uuid::Uuid);
fn get_hostname(&self) -> String;
fn set_hostname(&self, name: Option<String>);
fn get_inst_name(&self) -> String; fn get_inst_name(&self) -> String;
fn set_inst_name(&self, name: String); fn set_inst_name(&self, name: String);
@@ -152,6 +155,7 @@ pub struct Flags {
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
struct Config { struct Config {
netns: Option<String>, netns: Option<String>,
hostname: Option<String>,
instance_name: Option<String>, instance_name: Option<String>,
instance_id: Option<uuid::Uuid>, instance_id: Option<uuid::Uuid>,
ipv4: Option<String>, ipv4: Option<String>,
@@ -216,6 +220,19 @@ impl ConfigLoader for TomlConfigLoader {
self.config.lock().unwrap().instance_name = Some(name); self.config.lock().unwrap().instance_name = Some(name);
} }
fn get_hostname(&self) -> String {
self.config
.lock()
.unwrap()
.hostname
.clone()
.unwrap_or(gethostname::gethostname().to_string_lossy().to_string())
}
fn set_hostname(&self, name: Option<String>) {
self.config.lock().unwrap().hostname = name;
}
fn get_netns(&self) -> Option<String> { fn get_netns(&self) -> Option<String> {
self.config.lock().unwrap().netns.clone() self.config.lock().unwrap().netns.clone()
} }

View File

@@ -54,7 +54,7 @@ pub struct GlobalCtx {
ip_collector: Arc<IPCollector>, ip_collector: Arc<IPCollector>,
hotname: AtomicCell<Option<String>>, hostname: AtomicCell<Option<String>>,
stun_info_collection: Box<dyn StunInfoCollectorTrait>, stun_info_collection: Box<dyn StunInfoCollectorTrait>,
@@ -80,6 +80,7 @@ impl GlobalCtx {
let id = config_fs.get_id(); let id = config_fs.get_id();
let network = config_fs.get_network_identity(); let network = config_fs.get_network_identity();
let net_ns = NetNS::new(config_fs.get_netns()); let net_ns = NetNS::new(config_fs.get_netns());
let hostname = config_fs.get_hostname();
let (event_bus, _) = tokio::sync::broadcast::channel(100); let (event_bus, _) = tokio::sync::broadcast::channel(100);
@@ -96,7 +97,7 @@ impl GlobalCtx {
ip_collector: Arc::new(IPCollector::new(net_ns)), ip_collector: Arc::new(IPCollector::new(net_ns)),
hotname: AtomicCell::new(None), hostname: AtomicCell::new(Some(hostname)),
stun_info_collection: Box::new(StunInfoCollector::new_with_default_servers()), stun_info_collection: Box::new(StunInfoCollector::new_with_default_servers()),
@@ -166,13 +167,27 @@ impl GlobalCtx {
} }
pub fn get_hostname(&self) -> Option<String> { pub fn get_hostname(&self) -> Option<String> {
if let Some(hostname) = self.hotname.take() { let hostname = gethostname::gethostname().to_string_lossy().to_string();
self.hotname.store(Some(hostname.clone()));
return Some(hostname); let hostname = match self.hostname.take() {
Some(name) => {
// when allowing custom hostname, there may be empty
if name.is_empty() {
hostname
} else {
name
}
},
None => hostname,
};
let re = regex::Regex::new(r"[^\u4E00-\u9FA5a-zA-Z0-9\-]*").unwrap();
let mut hostname = re.replace_all(&hostname, "").to_string();
if hostname.len() > 32 {
hostname = hostname.chars().take(32).collect::<String>();
} }
let hostname = gethostname::gethostname().to_string_lossy().to_string(); self.hostname.store(Some(hostname.clone()));
self.hotname.store(Some(hostname.clone()));
return Some(hostname); return Some(hostname);
} }

View File

@@ -111,6 +111,9 @@ struct Cli {
#[arg(long, help = "directory to store log files")] #[arg(long, help = "directory to store log files")]
file_log_dir: Option<String>, file_log_dir: Option<String>,
#[arg(long, help = "host name to identify this device")]
hostname: Option<String>,
#[arg( #[arg(
short = 'm', short = 'm',
long, long,
@@ -177,6 +180,26 @@ impl From<Cli> for TomlConfigLoader {
let cfg = TomlConfigLoader::default(); let cfg = TomlConfigLoader::default();
cfg.set_inst_name(cli.instance_name.clone()); cfg.set_inst_name(cli.instance_name.clone());
let hostname = gethostname::gethostname().to_string_lossy().to_string();
let hostname = match cli.hostname {
Some(name) => {
// when allowing custom hostname, there may be empty
if name.is_empty() {
hostname
} else {
name
}
}
None => hostname,
};
let re = regex::Regex::new(r"[^\u4E00-\u9FA5a-zA-Z0-9\-]*").unwrap();
let mut hostname = re.replace_all(&hostname, "").to_string();
if hostname.len() > 32 {
hostname = hostname.chars().take(32).collect::<String>();
}
cfg.set_hostname(Some(hostname));
cfg.set_network_identity(NetworkIdentity::new( cfg.set_network_identity(NetworkIdentity::new(
cli.network_name.clone(), cli.network_name.clone(),
cli.network_secret.clone(), cli.network_secret.clone(),