mirror of
https://github.com/EasyTier/EasyTier.git
synced 2024-11-16 11:42:27 +08:00
parent
bad6a5946a
commit
0ead308392
|
@ -4,6 +4,7 @@ public_server: 公共服务器
|
||||||
manual: 手动
|
manual: 手动
|
||||||
standalone: 独立
|
standalone: 独立
|
||||||
virtual_ipv4: 虚拟IPv4地址
|
virtual_ipv4: 虚拟IPv4地址
|
||||||
|
virtual_ipv4_dhcp: DHCP
|
||||||
network_name: 网络名称
|
network_name: 网络名称
|
||||||
network_secret: 网络密码
|
network_secret: 网络密码
|
||||||
public_server_url: 公共服务器地址
|
public_server_url: 公共服务器地址
|
||||||
|
@ -59,3 +60,4 @@ run_network: 运行网络
|
||||||
stop_network: 停止网络
|
stop_network: 停止网络
|
||||||
network_running: 运行中
|
network_running: 运行中
|
||||||
network_stopped: 已停止
|
network_stopped: 已停止
|
||||||
|
dhcp_experimental_warning: 实验性警告!使用DHCP时如果组网环境中发生IP冲突,将自动更改IP。
|
||||||
|
|
|
@ -4,6 +4,7 @@ public_server: Public Server
|
||||||
manual: Manual
|
manual: Manual
|
||||||
standalone: Standalone
|
standalone: Standalone
|
||||||
virtual_ipv4: Virtual IPv4
|
virtual_ipv4: Virtual IPv4
|
||||||
|
virtual_ipv4_dhcp: DHCP
|
||||||
network_name: Network Name
|
network_name: Network Name
|
||||||
network_secret: Network Secret
|
network_secret: Network Secret
|
||||||
public_server_url: Public Server URL
|
public_server_url: Public Server URL
|
||||||
|
@ -59,3 +60,4 @@ run_network: Run Network
|
||||||
stop_network: Stop Network
|
stop_network: Stop Network
|
||||||
network_running: running
|
network_running: running
|
||||||
network_stopped: stopped
|
network_stopped: stopped
|
||||||
|
dhcp_experimental_warning: Experimental warning! if there is an IP conflict in the network when using DHCP, the IP will be automatically changed.
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl Default for NetworkingMethod {
|
||||||
struct NetworkConfig {
|
struct NetworkConfig {
|
||||||
instance_id: String,
|
instance_id: String,
|
||||||
|
|
||||||
|
dhcp: bool,
|
||||||
virtual_ipv4: String,
|
virtual_ipv4: String,
|
||||||
hostname: Option<String>,
|
hostname: Option<String>,
|
||||||
network_name: String,
|
network_name: String,
|
||||||
|
@ -53,7 +54,7 @@ struct NetworkConfig {
|
||||||
proxy_cidrs: Vec<String>,
|
proxy_cidrs: Vec<String>,
|
||||||
|
|
||||||
enable_vpn_portal: bool,
|
enable_vpn_portal: bool,
|
||||||
vpn_portal_listne_port: i32,
|
vpn_portal_listen_port: i32,
|
||||||
vpn_portal_client_network_addr: String,
|
vpn_portal_client_network_addr: String,
|
||||||
vpn_portal_client_network_len: i32,
|
vpn_portal_client_network_len: i32,
|
||||||
|
|
||||||
|
@ -72,18 +73,19 @@ impl NetworkConfig {
|
||||||
.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_hostname(self.hostname.clone());
|
||||||
|
cfg.set_dhcp(self.dhcp);
|
||||||
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(),
|
||||||
self.network_secret.clone(),
|
self.network_secret.clone(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if !self.dhcp {
|
||||||
if self.virtual_ipv4.len() > 0 {
|
if self.virtual_ipv4.len() > 0 {
|
||||||
cfg.set_ipv4(
|
cfg.set_ipv4(Some(self.virtual_ipv4.parse().with_context(|| {
|
||||||
self.virtual_ipv4.parse().with_context(|| {
|
|
||||||
format!("failed to parse ipv4 address: {}", self.virtual_ipv4)
|
format!("failed to parse ipv4 address: {}", self.virtual_ipv4)
|
||||||
})?,
|
})?))
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.networking_method {
|
match self.networking_method {
|
||||||
|
@ -150,12 +152,12 @@ impl NetworkConfig {
|
||||||
client_cidr: cidr
|
client_cidr: cidr
|
||||||
.parse()
|
.parse()
|
||||||
.with_context(|| format!("failed to parse vpn portal client cidr: {}", cidr))?,
|
.with_context(|| format!("failed to parse vpn portal client cidr: {}", cidr))?,
|
||||||
wireguard_listen: format!("0.0.0.0:{}", self.vpn_portal_listne_port)
|
wireguard_listen: format!("0.0.0.0:{}", self.vpn_portal_listen_port)
|
||||||
.parse()
|
.parse()
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"failed to parse vpn portal wireguard listen port. {}",
|
"failed to parse vpn portal wireguard listen port. {}",
|
||||||
self.vpn_portal_listne_port
|
self.vpn_portal_listen_port
|
||||||
)
|
)
|
||||||
})?,
|
})?,
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import InputGroup from 'primevue/inputgroup'
|
import InputGroup from 'primevue/inputgroup'
|
||||||
import InputGroupAddon from 'primevue/inputgroupaddon'
|
import InputGroupAddon from 'primevue/inputgroupaddon'
|
||||||
import { getOsHostname } from '~/composables/network'
|
import { getOsHostname } from '~/composables/network'
|
||||||
import { i18n } from '~/modules/i18n'
|
|
||||||
import { NetworkingMethod } from '~/types/network'
|
import { NetworkingMethod } from '~/types/network'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -12,10 +11,12 @@ const props = defineProps<{
|
||||||
|
|
||||||
defineEmits(['runNetwork'])
|
defineEmits(['runNetwork'])
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const networking_methods = ref([
|
const networking_methods = ref([
|
||||||
{ value: NetworkingMethod.PublicServer, label: i18n.global.t('public_server') },
|
{ value: NetworkingMethod.PublicServer, label: t('public_server') },
|
||||||
{ value: NetworkingMethod.Manual, label: i18n.global.t('manual') },
|
{ value: NetworkingMethod.Manual, label: t('manual') },
|
||||||
{ value: NetworkingMethod.Standalone, label: i18n.global.t('standalone') },
|
{ value: NetworkingMethod.Standalone, label: t('standalone') },
|
||||||
])
|
])
|
||||||
|
|
||||||
const networkStore = useNetworkStore()
|
const networkStore = useNetworkStore()
|
||||||
|
@ -56,14 +57,29 @@ onMounted(async () => {
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-column h-full">
|
<div class="flex flex-column h-full">
|
||||||
<div class="flex flex-column">
|
<div class="flex flex-column">
|
||||||
|
<div class="w-7/12 self-center ">
|
||||||
|
<Message severity="warn">
|
||||||
|
{{ $t('dhcp_experimental_warning') }}
|
||||||
|
</Message>
|
||||||
|
</div>
|
||||||
<div class="w-7/12 self-center ">
|
<div class="w-7/12 self-center ">
|
||||||
<Panel :header="$t('basic_settings')">
|
<Panel :header="$t('basic_settings')">
|
||||||
<div class="flex flex-column gap-y-2">
|
<div class="flex flex-column gap-y-2">
|
||||||
<div class="flex flex-row gap-x-9 flex-wrap">
|
<div class="flex flex-row gap-x-9 flex-wrap">
|
||||||
<div class="flex flex-column gap-2 basis-5/12 grow">
|
<div class="flex flex-column gap-2 basis-5/12 grow">
|
||||||
<label for="virtual_ip">{{ $t('virtual_ipv4') }}</label>
|
<div class="flex align-items-center" for="virtual_ip">
|
||||||
|
<label class="mr-2"> {{ $t('virtual_ipv4') }} </label>
|
||||||
|
<Checkbox v-model="curNetwork.dhcp" input-id="virtual_ip_auto" :binary="true" />
|
||||||
|
|
||||||
|
<label for="virtual_ip_auto" class="ml-2">
|
||||||
|
{{ t('virtual_ipv4_dhcp') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<InputText id="virtual_ip" v-model="curNetwork.virtual_ipv4" aria-describedby="virtual_ipv4-help" />
|
<InputText
|
||||||
|
id="virtual_ip" v-model="curNetwork.virtual_ipv4" :disabled="curNetwork.dhcp"
|
||||||
|
aria-describedby="virtual_ipv4-help"
|
||||||
|
/>
|
||||||
<InputGroupAddon>
|
<InputGroupAddon>
|
||||||
<span>/24</span>
|
<span>/24</span>
|
||||||
</InputGroupAddon>
|
</InputGroupAddon>
|
||||||
|
@ -112,7 +128,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Panel :header="$t('advanced_settings')" toggleable>
|
<Panel :header="$t('advanced_settings')" toggleable collapsed>
|
||||||
<div class="flex flex-column gap-y-2">
|
<div class="flex flex-column gap-y-2">
|
||||||
<div class="flex flex-row gap-x-9 flex-wrap">
|
<div class="flex flex-row gap-x-9 flex-wrap">
|
||||||
<div class="flex flex-column gap-2 basis-5/12 grow">
|
<div class="flex flex-column gap-2 basis-5/12 grow">
|
||||||
|
@ -154,7 +170,7 @@ onMounted(async () => {
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</div>
|
</div>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-if="curNetwork.enable_vpn_portal" v-model="curNetwork.vpn_portal_listne_port"
|
v-if="curNetwork.enable_vpn_portal" v-model="curNetwork.vpn_portal_listen_port"
|
||||||
:placeholder="$t('vpn_portal_listen_port')" class="" :format="false" :min="0" :max="65535"
|
:placeholder="$t('vpn_portal_listen_port')" class="" :format="false" :min="0" :max="65535"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,7 +24,7 @@ const curNetworkInst = computed(() => {
|
||||||
|
|
||||||
const peerRouteInfos = computed(() => {
|
const peerRouteInfos = computed(() => {
|
||||||
if (curNetworkInst.value)
|
if (curNetworkInst.value)
|
||||||
return curNetworkInst.value.detail.peer_route_pairs
|
return curNetworkInst.value.detail?.peer_route_pairs || []
|
||||||
|
|
||||||
return []
|
return []
|
||||||
})
|
})
|
||||||
|
@ -116,6 +116,13 @@ const myNodeInfoChips = computed(() => {
|
||||||
if (!my_node_info)
|
if (!my_node_info)
|
||||||
return chips
|
return chips
|
||||||
|
|
||||||
|
// virtual ipv4
|
||||||
|
|
||||||
|
chips.push({
|
||||||
|
label: `Virtual IPv4: ${my_node_info.virtual_ipv4}`,
|
||||||
|
icon: '',
|
||||||
|
} as Chip)
|
||||||
|
|
||||||
// local ipv4s
|
// local ipv4s
|
||||||
const local_ipv4s = my_node_info.ips?.interface_ipv4s
|
const local_ipv4s = my_node_info.ips?.interface_ipv4s
|
||||||
for (const [idx, ip] of local_ipv4s?.entries()) {
|
for (const [idx, ip] of local_ipv4s?.entries()) {
|
||||||
|
@ -290,7 +297,8 @@ function showEventLogs() {
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card v-if="!curNetworkInst?.error_msg">
|
<template v-else>
|
||||||
|
<Card>
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ $t('my_node_info') }}
|
{{ $t('my_node_info') }}
|
||||||
</template>
|
</template>
|
||||||
|
@ -351,7 +359,7 @@ function showEventLogs() {
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Card v-if="!curNetworkInst?.error_msg">
|
<Card>
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ $t('peer_info') }}
|
{{ $t('peer_info') }}
|
||||||
</template>
|
</template>
|
||||||
|
@ -367,5 +375,6 @@ function showEventLogs() {
|
||||||
</DataTable>
|
</DataTable>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -52,7 +52,6 @@ enum Severity {
|
||||||
|
|
||||||
const messageBarSeverity = ref(Severity.None)
|
const messageBarSeverity = ref(Severity.None)
|
||||||
const messageBarContent = ref('')
|
const messageBarContent = ref('')
|
||||||
|
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
const networkStore = useNetworkStore()
|
const networkStore = useNetworkStore()
|
||||||
|
@ -108,12 +107,8 @@ onMounted(() => {
|
||||||
})
|
})
|
||||||
onUnmounted(() => clearInterval(intervalId))
|
onUnmounted(() => clearInterval(intervalId))
|
||||||
|
|
||||||
const curNetworkHasInstance = computed(() => {
|
|
||||||
return networkStore.networkInstanceIds.includes(networkStore.curNetworkId)
|
|
||||||
})
|
|
||||||
|
|
||||||
const activeStep = computed(() => {
|
const activeStep = computed(() => {
|
||||||
return curNetworkHasInstance.value ? 1 : 0
|
return networkStore.networkInstanceIds.includes(networkStore.curNetworkId) ? 1 : 0
|
||||||
})
|
})
|
||||||
|
|
||||||
const setting_menu = ref()
|
const setting_menu = ref()
|
||||||
|
@ -190,8 +185,12 @@ function isRunning(id: string) {
|
||||||
<div class="flex items-start content-center">
|
<div class="flex items-start content-center">
|
||||||
<div class="mr-3">
|
<div class="mr-3">
|
||||||
<span>{{ slotProps.value.network_name }}</span>
|
<span>{{ slotProps.value.network_name }}</span>
|
||||||
<span v-if="isRunning(slotProps.value.instance_id)" class="ml-3">
|
<span
|
||||||
{{ slotProps.value.virtual_ipv4 }}
|
v-if="isRunning(slotProps.value.instance_id) && networkStore.instances[slotProps.value.instance_id].detail && (networkStore.instances[slotProps.value.instance_id].detail?.my_node_info.virtual_ipv4 !== '')"
|
||||||
|
class="ml-3"
|
||||||
|
>
|
||||||
|
{{ networkStore.instances[slotProps.value.instance_id].detail
|
||||||
|
? networkStore.instances[slotProps.value.instance_id].detail?.my_node_info.virtual_ipv4 : '' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Tag
|
<Tag
|
||||||
|
|
|
@ -56,7 +56,7 @@ export const useNetworkStore = defineStore('networkStore', {
|
||||||
instance_id: instanceId,
|
instance_id: instanceId,
|
||||||
running: false,
|
running: false,
|
||||||
error_msg: '',
|
error_msg: '',
|
||||||
detail: {} as NetworkInstanceRunningInfo,
|
detail: undefined,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -31,3 +31,18 @@
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #0000005d;
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ export enum NetworkingMethod {
|
||||||
export interface NetworkConfig {
|
export interface NetworkConfig {
|
||||||
instance_id: string
|
instance_id: string
|
||||||
|
|
||||||
|
dhcp: boolean
|
||||||
virtual_ipv4: string
|
virtual_ipv4: string
|
||||||
hostname?: string
|
hostname?: string
|
||||||
network_name: string
|
network_name: string
|
||||||
|
@ -17,18 +18,18 @@ export interface NetworkConfig {
|
||||||
networking_method: NetworkingMethod
|
networking_method: NetworkingMethod
|
||||||
|
|
||||||
public_server_url: string
|
public_server_url: string
|
||||||
peer_urls: Array<string>
|
peer_urls: string[]
|
||||||
|
|
||||||
proxy_cidrs: Array<string>
|
proxy_cidrs: string[]
|
||||||
|
|
||||||
enable_vpn_portal: boolean
|
enable_vpn_portal: boolean
|
||||||
vpn_portal_listne_port: number
|
vpn_portal_listen_port: number
|
||||||
vpn_portal_client_network_addr: string
|
vpn_portal_client_network_addr: string
|
||||||
vpn_portal_client_network_len: number
|
vpn_portal_client_network_len: number
|
||||||
|
|
||||||
advanced_settings: boolean
|
advanced_settings: boolean
|
||||||
|
|
||||||
listener_urls: Array<string>
|
listener_urls: string[]
|
||||||
rpc_port: number
|
rpc_port: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +37,9 @@ export function DEFAULT_NETWORK_CONFIG(): NetworkConfig {
|
||||||
return {
|
return {
|
||||||
instance_id: uuidv4(),
|
instance_id: uuidv4(),
|
||||||
|
|
||||||
|
dhcp: false,
|
||||||
virtual_ipv4: '',
|
virtual_ipv4: '',
|
||||||
network_name: 'default',
|
network_name: 'easytier',
|
||||||
network_secret: '',
|
network_secret: '',
|
||||||
|
|
||||||
networking_method: NetworkingMethod.PublicServer,
|
networking_method: NetworkingMethod.PublicServer,
|
||||||
|
@ -48,7 +50,7 @@ export function DEFAULT_NETWORK_CONFIG(): NetworkConfig {
|
||||||
proxy_cidrs: [],
|
proxy_cidrs: [],
|
||||||
|
|
||||||
enable_vpn_portal: false,
|
enable_vpn_portal: false,
|
||||||
vpn_portal_listne_port: 22022,
|
vpn_portal_listen_port: 22022,
|
||||||
vpn_portal_client_network_addr: '',
|
vpn_portal_client_network_addr: '',
|
||||||
vpn_portal_client_network_len: 24,
|
vpn_portal_client_network_len: 24,
|
||||||
|
|
||||||
|
@ -59,7 +61,7 @@ export function DEFAULT_NETWORK_CONFIG(): NetworkConfig {
|
||||||
'udp://0.0.0.0:11010',
|
'udp://0.0.0.0:11010',
|
||||||
'wg://0.0.0.0:11011',
|
'wg://0.0.0.0:11011',
|
||||||
],
|
],
|
||||||
rpc_port: 15888,
|
rpc_port: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +71,7 @@ export interface NetworkInstance {
|
||||||
running: boolean
|
running: boolean
|
||||||
error_msg: string
|
error_msg: string
|
||||||
|
|
||||||
detail: NetworkInstanceRunningInfo
|
detail?: NetworkInstanceRunningInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NetworkInstanceRunningInfo {
|
export interface NetworkInstanceRunningInfo {
|
||||||
|
|
|
@ -24,7 +24,10 @@ pub trait ConfigLoader: Send + Sync {
|
||||||
fn set_netns(&self, ns: Option<String>);
|
fn set_netns(&self, ns: Option<String>);
|
||||||
|
|
||||||
fn get_ipv4(&self) -> Option<std::net::Ipv4Addr>;
|
fn get_ipv4(&self) -> Option<std::net::Ipv4Addr>;
|
||||||
fn set_ipv4(&self, addr: std::net::Ipv4Addr);
|
fn set_ipv4(&self, addr: Option<std::net::Ipv4Addr>);
|
||||||
|
|
||||||
|
fn get_dhcp(&self) -> bool;
|
||||||
|
fn set_dhcp(&self, dhcp: bool);
|
||||||
|
|
||||||
fn add_proxy_cidr(&self, cidr: cidr::IpCidr);
|
fn add_proxy_cidr(&self, cidr: cidr::IpCidr);
|
||||||
fn remove_proxy_cidr(&self, cidr: cidr::IpCidr);
|
fn remove_proxy_cidr(&self, cidr: cidr::IpCidr);
|
||||||
|
@ -161,6 +164,7 @@ struct Config {
|
||||||
instance_name: Option<String>,
|
instance_name: Option<String>,
|
||||||
instance_id: Option<uuid::Uuid>,
|
instance_id: Option<uuid::Uuid>,
|
||||||
ipv4: Option<String>,
|
ipv4: Option<String>,
|
||||||
|
dhcp: Option<bool>,
|
||||||
network_identity: Option<NetworkIdentity>,
|
network_identity: Option<NetworkIdentity>,
|
||||||
listeners: Option<Vec<url::Url>>,
|
listeners: Option<Vec<url::Url>>,
|
||||||
|
|
||||||
|
@ -280,8 +284,20 @@ impl ConfigLoader for TomlConfigLoader {
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_ipv4(&self, addr: std::net::Ipv4Addr) {
|
fn set_ipv4(&self, addr: Option<std::net::Ipv4Addr>) {
|
||||||
self.config.lock().unwrap().ipv4 = Some(addr.to_string());
|
self.config.lock().unwrap().ipv4 = if let Some(addr) = addr {
|
||||||
|
Some(addr.to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_dhcp(&self) -> bool {
|
||||||
|
self.config.lock().unwrap().dhcp.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_dhcp(&self, dhcp: bool) {
|
||||||
|
self.config.lock().unwrap().dhcp = Some(dhcp);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_proxy_cidr(&self, cidr: cidr::IpCidr) {
|
fn add_proxy_cidr(&self, cidr: cidr::IpCidr) {
|
||||||
|
|
|
@ -36,6 +36,9 @@ pub enum GlobalCtxEvent {
|
||||||
|
|
||||||
VpnPortalClientConnected(String, String), // (portal, client ip)
|
VpnPortalClientConnected(String, String), // (portal, client ip)
|
||||||
VpnPortalClientDisconnected(String, String), // (portal, client ip)
|
VpnPortalClientDisconnected(String, String), // (portal, client ip)
|
||||||
|
|
||||||
|
DhcpIpv4Changed(Option<std::net::Ipv4Addr>, Option<std::net::Ipv4Addr>), // (old, new)
|
||||||
|
DhcpIpv4Conflicted(Option<std::net::Ipv4Addr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventBus = tokio::sync::broadcast::Sender<GlobalCtxEvent>;
|
type EventBus = tokio::sync::broadcast::Sender<GlobalCtxEvent>;
|
||||||
|
@ -127,7 +130,7 @@ impl GlobalCtx {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_ipv4(&mut self, addr: std::net::Ipv4Addr) {
|
pub fn set_ipv4(&self, addr: Option<std::net::Ipv4Addr>) {
|
||||||
self.config.set_ipv4(addr);
|
self.config.set_ipv4(addr);
|
||||||
self.cached_ipv4.store(None);
|
self.cached_ipv4.store(None);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,13 @@ struct Cli {
|
||||||
)]
|
)]
|
||||||
ipv4: Option<String>,
|
ipv4: Option<String>,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "automatically determine and set IP address by Easytier, and the IP address starts from 10.0.0.1 by default. Warning, if there is an IP conflict in the network when using DHCP, the IP will be automatically changed."
|
||||||
|
)]
|
||||||
|
dhcp: bool,
|
||||||
|
|
||||||
#[arg(short, long, help = "peers to connect initially", num_args = 0..)]
|
#[arg(short, long, help = "peers to connect initially", num_args = 0..)]
|
||||||
peers: Vec<String>,
|
peers: Vec<String>,
|
||||||
|
|
||||||
|
@ -271,12 +278,16 @@ impl From<Cli> for TomlConfigLoader {
|
||||||
cli.network_secret.clone(),
|
cli.network_secret.clone(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
cfg.set_dhcp(cli.dhcp);
|
||||||
|
|
||||||
|
if !cli.dhcp {
|
||||||
if let Some(ipv4) = &cli.ipv4 {
|
if let Some(ipv4) = &cli.ipv4 {
|
||||||
cfg.set_ipv4(
|
cfg.set_ipv4(Some(
|
||||||
ipv4.parse()
|
ipv4.parse()
|
||||||
.with_context(|| format!("failed to parse ipv4 address: {}", ipv4))
|
.with_context(|| format!("failed to parse ipv4 address: {}", ipv4))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.set_peers(
|
cfg.set_peers(
|
||||||
|
@ -503,6 +514,14 @@ pub async fn async_main(cli: Cli) {
|
||||||
portal, client_addr
|
portal, client_addr
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GlobalCtxEvent::DhcpIpv4Changed(old, new) => {
|
||||||
|
print_event(format!("dhcp ip changed. old: {:?}, new: {:?}", old, new));
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalCtxEvent::DhcpIpv4Conflicted(ip) => {
|
||||||
|
print_event(format!("dhcp ip conflict. ip: {:?}", ip));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use std::borrow::BorrowMut;
|
use std::borrow::BorrowMut;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use cidr::Ipv4Inet;
|
||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
|
|
||||||
use pnet::packet::ipv4::Ipv4Packet;
|
use pnet::packet::ipv4::Ipv4Packet;
|
||||||
|
@ -285,6 +287,116 @@ impl Instance {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warning, if there is an IP conflict in the network when using DHCP, the IP will be automatically changed.
|
||||||
|
fn check_dhcp_ip_conflict(&self) {
|
||||||
|
use rand::Rng;
|
||||||
|
let peer_manager_c = self.peer_manager.clone();
|
||||||
|
let global_ctx_c = self.get_global_ctx();
|
||||||
|
let nic_c = self.virtual_nic.as_ref().unwrap().clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let default_ipv4_addr = Ipv4Addr::new(10, 0, 0, 0);
|
||||||
|
let mut dhcp_ip: Option<Ipv4Inet> = None;
|
||||||
|
let mut tries = 6;
|
||||||
|
loop {
|
||||||
|
let mut ipv4_addr: Option<Ipv4Inet> = None;
|
||||||
|
let mut unique_ipv4 = HashSet::new();
|
||||||
|
|
||||||
|
for i in 0..tries {
|
||||||
|
if dhcp_ip.is_none() {
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
for route in peer_manager_c.list_routes().await {
|
||||||
|
if !route.ipv4_addr.is_empty() {
|
||||||
|
if let Ok(ip) = Ipv4Inet::new(
|
||||||
|
if let Ok(ipv4) = route.ipv4_addr.parse::<Ipv4Addr>() {
|
||||||
|
ipv4
|
||||||
|
} else {
|
||||||
|
default_ipv4_addr
|
||||||
|
},
|
||||||
|
24,
|
||||||
|
) {
|
||||||
|
unique_ipv4.insert(ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == tries - 1 && unique_ipv4.is_empty() {
|
||||||
|
unique_ipv4.insert(Ipv4Inet::new(default_ipv4_addr, 24).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ip) = dhcp_ip {
|
||||||
|
if !unique_ipv4.contains(&ip) {
|
||||||
|
ipv4_addr = dhcp_ip;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for net in unique_ipv4.iter().map(|inet| inet.network()).take(1) {
|
||||||
|
if let Some(ip) = net.iter().find(|ip| {
|
||||||
|
ip.address() != net.first_address()
|
||||||
|
&& ip.address() != net.last_address()
|
||||||
|
&& !unique_ipv4.contains(ip)
|
||||||
|
}) {
|
||||||
|
ipv4_addr = Some(ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if dhcp_ip != ipv4_addr {
|
||||||
|
let last_ip = dhcp_ip.map(|p| p.address());
|
||||||
|
tracing::debug!("last_ip: {:?}", last_ip);
|
||||||
|
let _ = nic_c.remove_ip(last_ip).await;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
if last_ip.is_some() {
|
||||||
|
let _g = global_ctx_c.net_ns.guard();
|
||||||
|
let ret = nic_c
|
||||||
|
.get_ifcfg()
|
||||||
|
.remove_ipv4_route(nic_c.ifname(), last_ip.unwrap(), 24)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if ret.is_err() {
|
||||||
|
tracing::trace!(
|
||||||
|
cidr = 24,
|
||||||
|
err = ?ret,
|
||||||
|
"remove route failed.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ip) = ipv4_addr {
|
||||||
|
let _ = nic_c.link_up().await;
|
||||||
|
dhcp_ip = Some(ip);
|
||||||
|
tries = 1;
|
||||||
|
if let Err(e) = nic_c.add_ip(ip.address(), 24).await {
|
||||||
|
tracing::error!("add ip failed: {:?}", e);
|
||||||
|
global_ctx_c.set_ipv4(None);
|
||||||
|
let sleep: u64 = rand::thread_rng().gen_range(200..500);
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(sleep)).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let _ = nic_c.add_route(ip.address(), 24).await;
|
||||||
|
global_ctx_c.set_ipv4(Some(ip.address()));
|
||||||
|
global_ctx_c.issue_event(GlobalCtxEvent::DhcpIpv4Changed(
|
||||||
|
last_ip,
|
||||||
|
Some(ip.address()),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
global_ctx_c.set_ipv4(None);
|
||||||
|
global_ctx_c.issue_event(GlobalCtxEvent::DhcpIpv4Conflicted(last_ip));
|
||||||
|
dhcp_ip = None;
|
||||||
|
tries = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let sleep: u64 = rand::thread_rng().gen_range(5..10);
|
||||||
|
|
||||||
|
tokio::time::sleep(std::time::Duration::from_secs(sleep)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn run(&mut self) -> Result<(), Error> {
|
pub async fn run(&mut self) -> Result<(), Error> {
|
||||||
self.listener_manager
|
self.listener_manager
|
||||||
.lock()
|
.lock()
|
||||||
|
@ -294,7 +406,11 @@ impl Instance {
|
||||||
self.listener_manager.lock().await.run().await?;
|
self.listener_manager.lock().await.run().await?;
|
||||||
self.peer_manager.run().await?;
|
self.peer_manager.run().await?;
|
||||||
|
|
||||||
if let Some(ipv4_addr) = self.global_ctx.get_ipv4() {
|
if self.global_ctx.config.get_dhcp() {
|
||||||
|
self.prepare_tun_device().await?;
|
||||||
|
self.run_proxy_cidrs_route_updater();
|
||||||
|
self.check_dhcp_ip_conflict();
|
||||||
|
} else if let Some(ipv4_addr) = self.global_ctx.get_ipv4() {
|
||||||
self.prepare_tun_device().await?;
|
self.prepare_tun_device().await?;
|
||||||
self.assign_ipv4_to_tun_device(ipv4_addr).await?;
|
self.assign_ipv4_to_tun_device(ipv4_addr).await?;
|
||||||
self.run_proxy_cidrs_route_updater();
|
self.run_proxy_cidrs_route_updater();
|
||||||
|
|
|
@ -48,7 +48,7 @@ pub fn get_inst_config(inst_name: &str, ns: Option<&str>, ipv4: &str) -> TomlCon
|
||||||
let config = TomlConfigLoader::default();
|
let config = TomlConfigLoader::default();
|
||||||
config.set_inst_name(inst_name.to_owned());
|
config.set_inst_name(inst_name.to_owned());
|
||||||
config.set_netns(ns.map(|s| s.to_owned()));
|
config.set_netns(ns.map(|s| s.to_owned()));
|
||||||
config.set_ipv4(ipv4.parse().unwrap());
|
config.set_ipv4(Some(ipv4.parse().unwrap()));
|
||||||
config.set_listeners(vec![
|
config.set_listeners(vec![
|
||||||
"tcp://0.0.0.0:11010".parse().unwrap(),
|
"tcp://0.0.0.0:11010".parse().unwrap(),
|
||||||
"udp://0.0.0.0:11010".parse().unwrap(),
|
"udp://0.0.0.0:11010".parse().unwrap(),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user