mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-12 12:47:25 +08:00
add portforward config to gui (#1198)
* Added port forwarding to the GUI interface * Separated port forwarding into a separate drop-down menu
This commit is contained in:
@@ -2,7 +2,13 @@
|
|||||||
import InputGroup from 'primevue/inputgroup'
|
import InputGroup from 'primevue/inputgroup'
|
||||||
import InputGroupAddon from 'primevue/inputgroupaddon'
|
import InputGroupAddon from 'primevue/inputgroupaddon'
|
||||||
import { SelectButton, Checkbox, InputText, InputNumber, AutoComplete, Panel, Divider, ToggleButton, Button, Password } from 'primevue'
|
import { SelectButton, Checkbox, InputText, InputNumber, AutoComplete, Panel, Divider, ToggleButton, Button, Password } from 'primevue'
|
||||||
import { DEFAULT_NETWORK_CONFIG, NetworkConfig, NetworkingMethod } from '../types/network'
|
import {
|
||||||
|
addRow,
|
||||||
|
DEFAULT_NETWORK_CONFIG,
|
||||||
|
NetworkConfig,
|
||||||
|
NetworkingMethod,
|
||||||
|
removeRow
|
||||||
|
} from '../types/network'
|
||||||
import { defineProps, defineEmits, ref, } from 'vue'
|
import { defineProps, defineEmits, ref, } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
@@ -163,6 +169,8 @@ const bool_flags: BoolFlag[] = [
|
|||||||
{ field: 'enable_private_mode', help: 'enable_private_mode_help' },
|
{ field: 'enable_private_mode', help: 'enable_private_mode_help' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const portForwardProtocolOptions = ref(["tcp","udp"]);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -416,6 +424,73 @@ const bool_flags: BoolFlag[] = [
|
|||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<Panel :header="t('port_forwards')" toggleable collapsed>
|
||||||
|
<div class="flex flex-col gap-y-2">
|
||||||
|
<div class="flex flex-row gap-x-9 flex-wrap w-full">
|
||||||
|
<div class="flex flex-col gap-2 grow p-fluid">
|
||||||
|
<div class="flex">
|
||||||
|
<label for="port_forwards">{{ t('port_forwards_help') }}</label>
|
||||||
|
</div>
|
||||||
|
<div v-for="(row, index) in curNetwork.port_forwards" class="form-row">
|
||||||
|
<div style="display: flex; gap: 0.5rem; align-items: flex-end;">
|
||||||
|
<SelectButton v-model="row.proto" :options="portForwardProtocolOptions" :allow-empty="false"/>
|
||||||
|
<div style="flex-grow: 4;">
|
||||||
|
<InputGroup>
|
||||||
|
<InputText
|
||||||
|
v-model="row.bind_ip"
|
||||||
|
:placeholder="t('port_forwards_bind_addr')"
|
||||||
|
/>
|
||||||
|
<InputGroupAddon>
|
||||||
|
<span style="font-weight: bold">:</span>
|
||||||
|
</InputGroupAddon>
|
||||||
|
<InputNumber v-model="row.bind_port" :format="false"
|
||||||
|
inputId="horizontal-buttons" :step="1" mode="decimal" :min="1"
|
||||||
|
:max="65535" fluid
|
||||||
|
class="max-w-20"/>
|
||||||
|
</InputGroup>
|
||||||
|
</div>
|
||||||
|
<div style="flex-grow: 4;">
|
||||||
|
<InputGroup>
|
||||||
|
<InputText
|
||||||
|
v-model="row.dst_ip"
|
||||||
|
:placeholder="t('port_forwards_dst_addr')"
|
||||||
|
/>
|
||||||
|
<InputGroupAddon>
|
||||||
|
<span style="font-weight: bold">:</span>
|
||||||
|
</InputGroupAddon>
|
||||||
|
<InputNumber v-model="row.dst_port" :format="false"
|
||||||
|
inputId="horizontal-buttons" :step="1" mode="decimal" :min="1"
|
||||||
|
:max="65535" fluid
|
||||||
|
class="max-w-20"/>
|
||||||
|
</InputGroup>
|
||||||
|
</div>
|
||||||
|
<div style="flex-grow: 1;">
|
||||||
|
<Button
|
||||||
|
v-if="curNetwork.port_forwards.length > 0"
|
||||||
|
icon="pi pi-trash"
|
||||||
|
severity="danger"
|
||||||
|
text
|
||||||
|
rounded
|
||||||
|
@click="removeRow(index,curNetwork.port_forwards)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-content-end mt-4">
|
||||||
|
<Button
|
||||||
|
icon="pi pi-plus"
|
||||||
|
:label="t('port_forwards_add_btn')"
|
||||||
|
severity="success"
|
||||||
|
@click="addRow(curNetwork.port_forwards)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
<div class="flex pt-6 justify-center">
|
<div class="flex pt-6 justify-center">
|
||||||
<Button :label="t('run_network')" icon="pi pi-arrow-right" icon-pos="right" :disabled="configInvalid"
|
<Button :label="t('run_network')" icon="pi pi-arrow-right" icon-pos="right" :disabled="configInvalid"
|
||||||
@click="$emit('runNetwork', curNetwork)" />
|
@click="$emit('runNetwork', curNetwork)" />
|
||||||
|
|||||||
@@ -150,6 +150,12 @@ socks5_help: |
|
|||||||
|
|
||||||
exit_nodes: 出口节点列表
|
exit_nodes: 出口节点列表
|
||||||
exit_nodes_help: 转发所有流量的出口节点,虚拟IPv4地址,优先级由列表顺序决定
|
exit_nodes_help: 转发所有流量的出口节点,虚拟IPv4地址,优先级由列表顺序决定
|
||||||
|
|
||||||
|
port_forwards: 端口转发
|
||||||
|
port_forwards_help: "将本地端口转发到虚拟网络中的远程端口。例如:udp://0.0.0.0:12345/10.126.126.1:23456,表示将本地UDP端口12345转发到虚拟网络中的10.126.126.1:23456。可以指定多个。"
|
||||||
|
port_forwards_bind_addr: "绑定地址,如:0.0.0.0"
|
||||||
|
port_forwards_dst_addr: "目标地址,如:10.126.126.1"
|
||||||
|
port_forwards_add_btn: "添加"
|
||||||
|
|
||||||
mtu: MTU
|
mtu: MTU
|
||||||
mtu_help: |
|
mtu_help: |
|
||||||
|
|||||||
@@ -151,6 +151,12 @@ socks5_help: |
|
|||||||
exit_nodes: Exit Nodes
|
exit_nodes: Exit Nodes
|
||||||
exit_nodes_help: Exit nodes to forward all traffic to, a virtual ipv4 address, priority is determined by the order of the list
|
exit_nodes_help: Exit nodes to forward all traffic to, a virtual ipv4 address, priority is determined by the order of the list
|
||||||
|
|
||||||
|
port_forwards: Port Forward
|
||||||
|
port_forwards_help: "forward local port to remote port in virtual network. e.g.: udp://0.0.0.0:12345/10.126.126.1:23456, means forward local udp port 12345 to 10.126.126.1:23456 in the virtual network. can specify multiple."
|
||||||
|
port_forwards_bind_addr: "Bind address, e.g.: 0.0.0.0"
|
||||||
|
port_forwards_dst_addr: "Destination address, e.g.: 10.126.126.1"
|
||||||
|
port_forwards_add_btn: "Add"
|
||||||
|
|
||||||
mtu: MTU
|
mtu: MTU
|
||||||
mtu_help: |
|
mtu_help: |
|
||||||
MTU of the TUN device, default is 1380 for non-encryption, 1360 for encryption. Range:400-1380
|
MTU of the TUN device, default is 1380 for non-encryption, 1360 for encryption. Range:400-1380
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ export interface NetworkConfig {
|
|||||||
enable_private_mode?: boolean
|
enable_private_mode?: boolean
|
||||||
|
|
||||||
rpc_portal_whitelists: string[]
|
rpc_portal_whitelists: string[]
|
||||||
|
|
||||||
|
port_forwards: PortForwardConfig[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DEFAULT_NETWORK_CONFIG(): NetworkConfig {
|
export function DEFAULT_NETWORK_CONFIG(): NetworkConfig {
|
||||||
@@ -132,6 +134,7 @@ export function DEFAULT_NETWORK_CONFIG(): NetworkConfig {
|
|||||||
enable_magic_dns: false,
|
enable_magic_dns: false,
|
||||||
enable_private_mode: false,
|
enable_private_mode: false,
|
||||||
rpc_portal_whitelists: [],
|
rpc_portal_whitelists: [],
|
||||||
|
port_forwards: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,6 +258,30 @@ export interface PeerConnStats {
|
|||||||
latency_us: number
|
latency_us: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PortForwardConfig {
|
||||||
|
bind_ip: string,
|
||||||
|
bind_port: number,
|
||||||
|
dst_ip: string,
|
||||||
|
dst_port: number,
|
||||||
|
proto: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加新行
|
||||||
|
export const addRow = (rows: PortForwardConfig[]) => {
|
||||||
|
rows.push({
|
||||||
|
proto: 'tcp',
|
||||||
|
bind_ip: '',
|
||||||
|
bind_port: 65535,
|
||||||
|
dst_ip: '',
|
||||||
|
dst_port: 65535,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除行
|
||||||
|
export const removeRow = (index: number, rows: PortForwardConfig[]) => {
|
||||||
|
rows.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
export enum EventType {
|
export enum EventType {
|
||||||
TunDeviceReady = 'TunDeviceReady', // string
|
TunDeviceReady = 'TunDeviceReady', // string
|
||||||
TunDeviceError = 'TunDeviceError', // string
|
TunDeviceError = 'TunDeviceError', // string
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::{
|
|||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
sync::{atomic::AtomicBool, Arc, RwLock},
|
sync::{atomic::AtomicBool, Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
use std::net::SocketAddr;
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{
|
common::{
|
||||||
config::{
|
config::{
|
||||||
@@ -20,6 +20,8 @@ use crate::{
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
use tokio::{sync::broadcast, task::JoinSet};
|
use tokio::{sync::broadcast, task::JoinSet};
|
||||||
|
use crate::common::config::PortForwardConfig;
|
||||||
|
use crate::proto::web;
|
||||||
|
|
||||||
pub type MyNodeInfo = crate::proto::web::MyNodeInfo;
|
pub type MyNodeInfo = crate::proto::web::MyNodeInfo;
|
||||||
|
|
||||||
@@ -588,6 +590,28 @@ impl NetworkConfig {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.port_forwards.is_empty() {
|
||||||
|
cfg.set_port_forwards(
|
||||||
|
self.port_forwards
|
||||||
|
.iter()
|
||||||
|
.filter(|pf| !pf.bind_ip.is_empty() && !pf.dst_ip.is_empty())
|
||||||
|
.filter_map(|pf| {
|
||||||
|
let bind_addr = format!("{}:{}", pf.bind_ip, pf.bind_port).parse::<SocketAddr>();
|
||||||
|
let dst_addr = format!("{}:{}", pf.dst_ip, pf.dst_port).parse::<SocketAddr>();
|
||||||
|
|
||||||
|
match (bind_addr, dst_addr) {
|
||||||
|
(Ok(bind_addr), Ok(dst_addr)) => Some(PortForwardConfig {
|
||||||
|
bind_addr,
|
||||||
|
dst_addr,
|
||||||
|
proto: pf.proto.clone(),
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if self.enable_vpn_portal.unwrap_or_default() {
|
if self.enable_vpn_portal.unwrap_or_default() {
|
||||||
let cidr = format!(
|
let cidr = format!(
|
||||||
"{}/{}",
|
"{}/{}",
|
||||||
@@ -820,6 +844,21 @@ impl NetworkConfig {
|
|||||||
result.rpc_portal_whitelists = whitelist.iter().map(|w| w.to_string()).collect();
|
result.rpc_portal_whitelists = whitelist.iter().map(|w| w.to_string()).collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let port_forwards = config.get_port_forwards();
|
||||||
|
if !port_forwards.is_empty() {
|
||||||
|
result.port_forwards = port_forwards.iter()
|
||||||
|
.map(|f| {
|
||||||
|
web::PortForwardConfig {
|
||||||
|
proto: f.proto.clone(),
|
||||||
|
bind_ip: f.bind_addr.ip().to_string(),
|
||||||
|
bind_port: f.bind_addr.port() as u32,
|
||||||
|
dst_ip: f.dst_addr.ip().to_string(),
|
||||||
|
dst_port: f.dst_addr.port() as u32,
|
||||||
|
}
|
||||||
|
}).
|
||||||
|
collect();
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(vpn_config) = config.get_vpn_portal_config() {
|
if let Some(vpn_config) = config.get_vpn_portal_config() {
|
||||||
result.enable_vpn_portal = Some(true);
|
result.enable_vpn_portal = Some(true);
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,15 @@ message NetworkConfig {
|
|||||||
|
|
||||||
optional bool enable_quic_proxy = 45;
|
optional bool enable_quic_proxy = 45;
|
||||||
optional bool disable_quic_input = 46;
|
optional bool disable_quic_input = 46;
|
||||||
|
repeated PortForwardConfig port_forwards = 48;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PortForwardConfig {
|
||||||
|
string bind_ip = 1;
|
||||||
|
uint32 bind_port = 2;
|
||||||
|
string dst_ip = 3;
|
||||||
|
uint32 dst_port = 4;
|
||||||
|
string proto = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message MyNodeInfo {
|
message MyNodeInfo {
|
||||||
|
|||||||
Reference in New Issue
Block a user