mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 18:24:36 +00:00
refactor(rpc): Centralize RPC service and unify API (#1427)
This change introduces a major refactoring of the RPC service layer to improve modularity, unify the API, and simplify the overall architecture. Key changes: - Replaced per-network-instance RPC services with a single global RPC server, reducing resource usage and simplifying management. - All clients (CLI, Web UI, etc.) now interact with EasyTier core through a unified RPC entrypoint, enabling consistent authentication and control. - RPC implementation logic has been moved to `easytier/src/rpc_service/` and organized by functionality (e.g., `instance_manage.rs`, `peer_manage.rs`, `config.rs`) for better maintainability. - Standardized Protobuf API definitions under `easytier/src/proto/` with an `api_` prefix (e.g., `cli.proto` → `api_instance.proto`) to provide a consistent interface. - CLI commands now require explicit `--instance-id` or `--instance-name` when multiple network instances are running; the parameter is optional when only one instance exists. BREAKING CHANGE: RPC portal configuration (`rpc_portal` and `rpc_portal_whitelist`) has been removed from per-instance configs and the Web UI. The RPC listen address must now be specified globally via the `--rpc-portal` command-line flag or the `ET_RPC_PORTAL` environment variable, as there is only one RPC service for the entire application.
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
pub mod config {
|
||||
include!(concat!(env!("OUT_DIR"), "/api.config.rs"));
|
||||
pub struct Patchable<T> {
|
||||
pub action: Option<ConfigPatchAction>,
|
||||
pub value: Option<T>,
|
||||
}
|
||||
|
||||
impl From<PortForwardPatch> for Patchable<crate::common::config::PortForwardConfig> {
|
||||
fn from(patch: PortForwardPatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(patch.action).ok(),
|
||||
value: patch.cfg.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RoutePatch> for Patchable<cidr::Ipv4Cidr> {
|
||||
fn from(value: RoutePatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(value.action).ok(),
|
||||
value: value.cidr.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExitNodePatch> for Patchable<std::net::IpAddr> {
|
||||
fn from(value: ExitNodePatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(value.action).ok(),
|
||||
value: value.node.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StringPatch> for Patchable<String> {
|
||||
fn from(value: StringPatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(value.action).ok(),
|
||||
value: Some(value.value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UrlPatch> for Patchable<url::Url> {
|
||||
fn from(value: UrlPatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(value.action).ok(),
|
||||
value: value.url.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn patch_vec<T>(v: &mut Vec<T>, patches: Vec<Patchable<T>>)
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
for patch in patches {
|
||||
match patch.action {
|
||||
Some(ConfigPatchAction::Add) => {
|
||||
if let Some(value) = patch.value {
|
||||
v.push(value);
|
||||
}
|
||||
}
|
||||
Some(ConfigPatchAction::Remove) => {
|
||||
if let Some(value) = patch.value {
|
||||
v.retain(|x| x != &value);
|
||||
}
|
||||
}
|
||||
Some(ConfigPatchAction::Clear) => {
|
||||
v.clear();
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod instance {
|
||||
include!(concat!(env!("OUT_DIR"), "/api.instance.rs"));
|
||||
|
||||
impl PeerRoutePair {
|
||||
pub fn get_latency_ms(&self) -> Option<f64> {
|
||||
let mut ret = u64::MAX;
|
||||
let p = self.peer.as_ref()?;
|
||||
let default_conn_id = p.default_conn_id.map(|id| id.to_string());
|
||||
for conn in p.conns.iter() {
|
||||
let Some(stats) = &conn.stats else {
|
||||
continue;
|
||||
};
|
||||
if default_conn_id == Some(conn.conn_id.to_string()) {
|
||||
return Some(f64::from(stats.latency_us as u32) / 1000.0);
|
||||
}
|
||||
ret = ret.min(stats.latency_us);
|
||||
}
|
||||
|
||||
if ret == u64::MAX {
|
||||
None
|
||||
} else {
|
||||
Some(f64::from(ret as u32) / 1000.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rx_bytes(&self) -> Option<u64> {
|
||||
let mut ret = 0;
|
||||
let p = self.peer.as_ref()?;
|
||||
for conn in p.conns.iter() {
|
||||
let Some(stats) = &conn.stats else {
|
||||
continue;
|
||||
};
|
||||
ret += stats.rx_bytes;
|
||||
}
|
||||
|
||||
if ret == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_tx_bytes(&self) -> Option<u64> {
|
||||
let mut ret = 0;
|
||||
let p = self.peer.as_ref()?;
|
||||
for conn in p.conns.iter() {
|
||||
let Some(stats) = &conn.stats else {
|
||||
continue;
|
||||
};
|
||||
ret += stats.tx_bytes;
|
||||
}
|
||||
|
||||
if ret == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_loss_rate(&self) -> Option<f64> {
|
||||
let mut ret = 0.0;
|
||||
let p = self.peer.as_ref()?;
|
||||
for conn in p.conns.iter() {
|
||||
ret += conn.loss_rate;
|
||||
}
|
||||
|
||||
if ret == 0.0 {
|
||||
None
|
||||
} else {
|
||||
Some(ret as f64)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_tunnel_ipv6(tunnel_info: &super::super::common::TunnelInfo) -> bool {
|
||||
let Some(local_addr) = &tunnel_info.local_addr else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let u: url::Url = local_addr.clone().into();
|
||||
u.host()
|
||||
.map(|h| matches!(h, url::Host::Ipv6(_)))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn get_tunnel_proto_str(tunnel_info: &super::super::common::TunnelInfo) -> String {
|
||||
if Self::is_tunnel_ipv6(tunnel_info) {
|
||||
format!("{}6", tunnel_info.tunnel_type)
|
||||
} else {
|
||||
tunnel_info.tunnel_type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_conn_protos(&self) -> Option<Vec<String>> {
|
||||
let mut ret = vec![];
|
||||
let p = self.peer.as_ref()?;
|
||||
for conn in p.conns.iter() {
|
||||
let Some(tunnel_info) = &conn.tunnel else {
|
||||
continue;
|
||||
};
|
||||
// insert if not exists
|
||||
let tunnel_type = Self::get_tunnel_proto_str(tunnel_info);
|
||||
if !ret.contains(&tunnel_type) {
|
||||
ret.push(tunnel_type);
|
||||
}
|
||||
}
|
||||
|
||||
if ret.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_udp_nat_type(&self) -> String {
|
||||
use crate::proto::common::NatType;
|
||||
let mut ret = NatType::Unknown;
|
||||
if let Some(r) = &self.route.clone().unwrap_or_default().stun_info {
|
||||
ret = NatType::try_from(r.udp_nat_type).unwrap();
|
||||
}
|
||||
format!("{:?}", ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_peer_route_pair(peers: Vec<PeerInfo>, routes: Vec<Route>) -> Vec<PeerRoutePair> {
|
||||
let mut pairs: Vec<PeerRoutePair> = vec![];
|
||||
|
||||
for route in routes.iter() {
|
||||
let peer = peers.iter().find(|peer| peer.peer_id == route.peer_id);
|
||||
let pair = PeerRoutePair {
|
||||
route: Some(route.clone()),
|
||||
peer: peer.cloned(),
|
||||
};
|
||||
|
||||
pairs.push(pair);
|
||||
}
|
||||
|
||||
pairs.sort_by(|a, b| {
|
||||
let a_is_public_server = a
|
||||
.route
|
||||
.as_ref()
|
||||
.and_then(|r| r.feature_flag.as_ref())
|
||||
.is_some_and(|f| f.is_public_server);
|
||||
|
||||
let b_is_public_server = b
|
||||
.route
|
||||
.as_ref()
|
||||
.and_then(|r| r.feature_flag.as_ref())
|
||||
.is_some_and(|f| f.is_public_server);
|
||||
|
||||
if a_is_public_server != b_is_public_server {
|
||||
return if a_is_public_server {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
std::cmp::Ordering::Greater
|
||||
};
|
||||
}
|
||||
|
||||
let a_ip = a
|
||||
.route
|
||||
.as_ref()
|
||||
.and_then(|r| r.ipv4_addr.as_ref())
|
||||
.and_then(|ipv4| ipv4.address.as_ref())
|
||||
.map_or(0, |addr| addr.addr);
|
||||
|
||||
let b_ip = b
|
||||
.route
|
||||
.as_ref()
|
||||
.and_then(|r| r.ipv4_addr.as_ref())
|
||||
.and_then(|ipv4| ipv4.address.as_ref())
|
||||
.map_or(0, |addr| addr.addr);
|
||||
|
||||
a_ip.cmp(&b_ip)
|
||||
});
|
||||
|
||||
pairs
|
||||
}
|
||||
}
|
||||
|
||||
pub mod logger {
|
||||
include!(concat!(env!("OUT_DIR"), "/api.logger.rs"));
|
||||
}
|
||||
|
||||
pub mod manage {
|
||||
include!(concat!(env!("OUT_DIR"), "/api.manage.rs"));
|
||||
}
|
||||
@@ -2,8 +2,9 @@ syntax = "proto3";
|
||||
|
||||
import "common.proto";
|
||||
import "acl.proto";
|
||||
import "api_instance.proto";
|
||||
|
||||
package config;
|
||||
package api.config;
|
||||
|
||||
enum ConfigPatchAction {
|
||||
ADD = 0;
|
||||
@@ -21,6 +22,7 @@ message InstanceConfigPatch {
|
||||
repeated RoutePatch routes = 7;
|
||||
repeated ExitNodePatch exit_nodes = 8;
|
||||
repeated UrlPatch mapped_listeners = 9;
|
||||
repeated UrlPatch connectors = 10;
|
||||
}
|
||||
|
||||
message PortForwardPatch {
|
||||
@@ -60,6 +62,13 @@ message ExitNodePatch {
|
||||
common.IpAddr node = 2;
|
||||
}
|
||||
|
||||
message PatchConfigRequest { InstanceConfigPatch patch = 1; }
|
||||
message PatchConfigRequest {
|
||||
InstanceConfigPatch patch = 1;
|
||||
api.instance.InstanceIdentifier instance = 2;
|
||||
}
|
||||
|
||||
service ConfigRpc { rpc PatchConfig(PatchConfigRequest) returns (common.Void); }
|
||||
message PatchConfigResponse {}
|
||||
|
||||
service ConfigRpc {
|
||||
rpc PatchConfig(PatchConfigRequest) returns (PatchConfigResponse);
|
||||
}
|
||||
@@ -4,7 +4,16 @@ import "common.proto";
|
||||
import "peer_rpc.proto";
|
||||
import "acl.proto";
|
||||
|
||||
package cli;
|
||||
package api.instance;
|
||||
|
||||
message InstanceIdentifier {
|
||||
message InstanceSelector { optional string name = 1; }
|
||||
|
||||
oneof selector {
|
||||
common.UUID id = 1;
|
||||
InstanceSelector instance_selector = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message Status {
|
||||
int32 code = 1;
|
||||
@@ -41,7 +50,7 @@ message PeerInfo {
|
||||
repeated common.UUID directly_connected_conns = 4;
|
||||
}
|
||||
|
||||
message ListPeerRequest {}
|
||||
message ListPeerRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ListPeerResponse {
|
||||
repeated PeerInfo peer_infos = 1;
|
||||
@@ -89,19 +98,19 @@ message NodeInfo {
|
||||
peer_rpc.GetIpListResponse ip_list = 11;
|
||||
}
|
||||
|
||||
message ShowNodeInfoRequest {}
|
||||
message ShowNodeInfoRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ShowNodeInfoResponse { NodeInfo node_info = 1; }
|
||||
|
||||
message ListRouteRequest {}
|
||||
message ListRouteRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ListRouteResponse { repeated Route routes = 1; }
|
||||
|
||||
message DumpRouteRequest {}
|
||||
message DumpRouteRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message DumpRouteResponse { string result = 1; }
|
||||
|
||||
message ListForeignNetworkRequest {}
|
||||
message ListForeignNetworkRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ForeignNetworkEntryPb {
|
||||
repeated PeerInfo peers = 1;
|
||||
@@ -114,7 +123,7 @@ message ListForeignNetworkResponse {
|
||||
map<string, ForeignNetworkEntryPb> foreign_networks = 1;
|
||||
}
|
||||
|
||||
message ListGlobalForeignNetworkRequest {}
|
||||
message ListGlobalForeignNetworkRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ListGlobalForeignNetworkResponse {
|
||||
// foreign network in the entire network
|
||||
@@ -152,37 +161,25 @@ message Connector {
|
||||
ConnectorStatus status = 2;
|
||||
}
|
||||
|
||||
message ListConnectorRequest {}
|
||||
message ListConnectorRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ListConnectorResponse { repeated Connector connectors = 1; }
|
||||
|
||||
enum ConnectorManageAction {
|
||||
ADD = 0;
|
||||
REMOVE = 1;
|
||||
}
|
||||
|
||||
message ManageConnectorRequest {
|
||||
ConnectorManageAction action = 1;
|
||||
common.Url url = 2;
|
||||
}
|
||||
|
||||
message ManageConnectorResponse {}
|
||||
|
||||
service ConnectorManageRpc {
|
||||
rpc ListConnector(ListConnectorRequest) returns (ListConnectorResponse);
|
||||
rpc ManageConnector(ManageConnectorRequest) returns (ManageConnectorResponse);
|
||||
}
|
||||
|
||||
message MappedListener {
|
||||
common.Url url = 1;
|
||||
message MappedListener { common.Url url = 1; }
|
||||
|
||||
message ListMappedListenerRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ListMappedListenerResponse {
|
||||
repeated MappedListener mappedlisteners = 1;
|
||||
}
|
||||
|
||||
message ListMappedListenerRequest {}
|
||||
|
||||
message ListMappedListenerResponse { repeated MappedListener mappedlisteners = 1; }
|
||||
|
||||
service MappedListenerManageRpc {
|
||||
rpc ListMappedListener(ListMappedListenerRequest) returns (ListMappedListenerResponse);
|
||||
rpc ListMappedListener(ListMappedListenerRequest)
|
||||
returns (ListMappedListenerResponse);
|
||||
}
|
||||
|
||||
message VpnPortalInfo {
|
||||
@@ -191,7 +188,7 @@ message VpnPortalInfo {
|
||||
repeated string connected_clients = 3;
|
||||
}
|
||||
|
||||
message GetVpnPortalInfoRequest {}
|
||||
message GetVpnPortalInfoRequest { InstanceIdentifier instance = 1; }
|
||||
message GetVpnPortalInfoResponse { VpnPortalInfo vpn_portal_info = 1; }
|
||||
|
||||
service VpnPortalRpc {
|
||||
@@ -206,19 +203,19 @@ enum TcpProxyEntryTransportType {
|
||||
}
|
||||
|
||||
enum TcpProxyEntryState {
|
||||
Unknown = 0;
|
||||
// receive syn packet but not start connecting to dst
|
||||
SynReceived = 1;
|
||||
// connecting to dst
|
||||
ConnectingDst = 2;
|
||||
// connected to dst
|
||||
Connected = 3;
|
||||
// connection closed
|
||||
Closed = 4;
|
||||
// closing src
|
||||
ClosingSrc = 5;
|
||||
// closing dst
|
||||
ClosingDst = 6;
|
||||
Unknown = 0;
|
||||
// receive syn packet but not start connecting to dst
|
||||
SynReceived = 1;
|
||||
// connecting to dst
|
||||
ConnectingDst = 2;
|
||||
// connected to dst
|
||||
Connected = 3;
|
||||
// connection closed
|
||||
Closed = 4;
|
||||
// closing src
|
||||
ClosingSrc = 5;
|
||||
// closing dst
|
||||
ClosingDst = 6;
|
||||
}
|
||||
|
||||
message TcpProxyEntry {
|
||||
@@ -229,36 +226,32 @@ message TcpProxyEntry {
|
||||
TcpProxyEntryTransportType transport_type = 5;
|
||||
}
|
||||
|
||||
message ListTcpProxyEntryRequest {}
|
||||
message ListTcpProxyEntryRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ListTcpProxyEntryResponse {
|
||||
repeated TcpProxyEntry entries = 1;
|
||||
}
|
||||
message ListTcpProxyEntryResponse { repeated TcpProxyEntry entries = 1; }
|
||||
|
||||
service TcpProxyRpc {
|
||||
rpc ListTcpProxyEntry(ListTcpProxyEntryRequest)
|
||||
returns (ListTcpProxyEntryResponse);
|
||||
}
|
||||
|
||||
message GetAclStatsRequest {}
|
||||
message GetAclStatsRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message GetAclStatsResponse {
|
||||
acl.AclStats acl_stats = 1;
|
||||
}
|
||||
message GetAclStatsResponse { acl.AclStats acl_stats = 1; }
|
||||
|
||||
service AclManageRpc {
|
||||
rpc GetAclStats(GetAclStatsRequest) returns (GetAclStatsResponse);
|
||||
rpc GetWhitelist(GetWhitelistRequest) returns (GetWhitelistResponse);
|
||||
}
|
||||
|
||||
message GetWhitelistRequest {}
|
||||
message GetWhitelistRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message GetWhitelistResponse {
|
||||
repeated string tcp_ports = 1;
|
||||
repeated string udp_ports = 2;
|
||||
}
|
||||
|
||||
message ListPortForwardRequest {}
|
||||
message ListPortForwardRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ListPortForwardResponse {
|
||||
repeated common.PortForwardConfigPb cfgs = 1;
|
||||
@@ -274,47 +267,16 @@ message MetricSnapshot {
|
||||
map<string, string> labels = 3;
|
||||
}
|
||||
|
||||
message GetStatsRequest {}
|
||||
message GetStatsRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message GetStatsResponse {
|
||||
repeated MetricSnapshot metrics = 1;
|
||||
}
|
||||
message GetStatsResponse { repeated MetricSnapshot metrics = 1; }
|
||||
|
||||
message GetPrometheusStatsRequest {}
|
||||
message GetPrometheusStatsRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message GetPrometheusStatsResponse {
|
||||
string prometheus_text = 1;
|
||||
}
|
||||
message GetPrometheusStatsResponse { string prometheus_text = 1; }
|
||||
|
||||
service StatsRpc {
|
||||
rpc GetStats(GetStatsRequest) returns (GetStatsResponse);
|
||||
rpc GetPrometheusStats(GetPrometheusStatsRequest) returns (GetPrometheusStatsResponse);
|
||||
}
|
||||
|
||||
enum LogLevel {
|
||||
DISABLED = 0;
|
||||
ERROR = 1;
|
||||
WARNING = 2;
|
||||
INFO = 3;
|
||||
DEBUG = 4;
|
||||
TRACE = 5;
|
||||
}
|
||||
|
||||
message SetLoggerConfigRequest {
|
||||
LogLevel level = 1;
|
||||
}
|
||||
|
||||
message SetLoggerConfigResponse {
|
||||
}
|
||||
|
||||
message GetLoggerConfigRequest {
|
||||
}
|
||||
|
||||
message GetLoggerConfigResponse {
|
||||
LogLevel level = 1;
|
||||
}
|
||||
|
||||
service LoggerRpc {
|
||||
rpc SetLoggerConfig(SetLoggerConfigRequest) returns (SetLoggerConfigResponse);
|
||||
rpc GetLoggerConfig(GetLoggerConfigRequest) returns (GetLoggerConfigResponse);
|
||||
rpc GetPrometheusStats(GetPrometheusStatsRequest)
|
||||
returns (GetPrometheusStatsResponse);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package api.logger;
|
||||
|
||||
enum LogLevel {
|
||||
DISABLED = 0;
|
||||
ERROR = 1;
|
||||
WARNING = 2;
|
||||
INFO = 3;
|
||||
DEBUG = 4;
|
||||
TRACE = 5;
|
||||
}
|
||||
|
||||
message SetLoggerConfigRequest { LogLevel level = 1; }
|
||||
|
||||
message SetLoggerConfigResponse {}
|
||||
|
||||
message GetLoggerConfigRequest {}
|
||||
|
||||
message GetLoggerConfigResponse { LogLevel level = 1; }
|
||||
service LoggerRpc {
|
||||
rpc SetLoggerConfig(SetLoggerConfigRequest) returns (SetLoggerConfigResponse);
|
||||
rpc GetLoggerConfig(GetLoggerConfigRequest) returns (GetLoggerConfigResponse);
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "common.proto";
|
||||
import "peer_rpc.proto";
|
||||
import "api_instance.proto";
|
||||
|
||||
package api.manage;
|
||||
|
||||
enum NetworkingMethod {
|
||||
PublicServer = 0;
|
||||
Manual = 1;
|
||||
Standalone = 2;
|
||||
}
|
||||
|
||||
message NetworkConfig {
|
||||
optional string instance_id = 1;
|
||||
|
||||
optional bool dhcp = 2;
|
||||
optional string virtual_ipv4 = 3;
|
||||
optional int32 network_length = 4;
|
||||
optional string hostname = 5;
|
||||
optional string network_name = 6;
|
||||
optional string network_secret = 7;
|
||||
optional NetworkingMethod networking_method = 8;
|
||||
|
||||
optional string public_server_url = 9;
|
||||
repeated string peer_urls = 10;
|
||||
|
||||
repeated string proxy_cidrs = 11;
|
||||
|
||||
optional bool enable_vpn_portal = 12;
|
||||
optional int32 vpn_portal_listen_port = 13;
|
||||
optional string vpn_portal_client_network_addr = 14;
|
||||
optional int32 vpn_portal_client_network_len = 15;
|
||||
|
||||
optional bool advanced_settings = 16;
|
||||
|
||||
repeated string listener_urls = 17;
|
||||
// optional int32 rpc_port = 18;
|
||||
optional bool latency_first = 19;
|
||||
|
||||
optional string dev_name = 20;
|
||||
|
||||
optional bool use_smoltcp = 21;
|
||||
optional bool disable_ipv6 = 47;
|
||||
optional bool enable_kcp_proxy = 22;
|
||||
optional bool disable_kcp_input = 23;
|
||||
optional bool disable_p2p = 24;
|
||||
optional bool bind_device = 25;
|
||||
optional bool no_tun = 26;
|
||||
|
||||
optional bool enable_exit_node = 27;
|
||||
optional bool relay_all_peer_rpc = 28;
|
||||
optional bool multi_thread = 29;
|
||||
optional bool enable_relay_network_whitelist = 30;
|
||||
repeated string relay_network_whitelist = 31;
|
||||
optional bool enable_manual_routes = 32;
|
||||
repeated string routes = 33;
|
||||
repeated string exit_nodes = 34;
|
||||
optional bool proxy_forward_by_system = 35;
|
||||
optional bool disable_encryption = 36;
|
||||
optional bool enable_socks5 = 37;
|
||||
optional int32 socks5_port = 38;
|
||||
optional bool disable_udp_hole_punching = 39;
|
||||
optional int32 mtu = 40;
|
||||
repeated string mapped_listeners = 41;
|
||||
|
||||
optional bool enable_magic_dns = 42;
|
||||
optional bool enable_private_mode = 43;
|
||||
|
||||
// repeated string rpc_portal_whitelists = 44;
|
||||
|
||||
optional bool enable_quic_proxy = 45;
|
||||
optional bool disable_quic_input = 46;
|
||||
repeated PortForwardConfig port_forwards = 48;
|
||||
|
||||
optional bool disable_sym_hole_punching = 49;
|
||||
}
|
||||
|
||||
message PortForwardConfig {
|
||||
string bind_ip = 1;
|
||||
uint32 bind_port = 2;
|
||||
string dst_ip = 3;
|
||||
uint32 dst_port = 4;
|
||||
string proto = 5;
|
||||
}
|
||||
|
||||
message MyNodeInfo {
|
||||
common.Ipv4Inet virtual_ipv4 = 1;
|
||||
string hostname = 2;
|
||||
string version = 3;
|
||||
peer_rpc.GetIpListResponse ips = 4;
|
||||
common.StunInfo stun_info = 5;
|
||||
repeated common.Url listeners = 6;
|
||||
optional string vpn_portal_cfg = 7;
|
||||
}
|
||||
|
||||
message NetworkInstanceRunningInfo {
|
||||
string dev_name = 1;
|
||||
MyNodeInfo my_node_info = 2;
|
||||
repeated string events = 3;
|
||||
repeated api.instance.Route routes = 4;
|
||||
repeated api.instance.PeerInfo peers = 5;
|
||||
repeated api.instance.PeerRoutePair peer_route_pairs = 6;
|
||||
bool running = 7;
|
||||
optional string error_msg = 8;
|
||||
peer_rpc.RouteForeignNetworkSummary foreign_network_summary = 9;
|
||||
}
|
||||
|
||||
message NetworkInstanceRunningInfoMap {
|
||||
map<string, NetworkInstanceRunningInfo> map = 1;
|
||||
}
|
||||
|
||||
message ValidateConfigRequest { NetworkConfig config = 1; }
|
||||
|
||||
message ValidateConfigResponse { string toml_config = 1; }
|
||||
|
||||
message RunNetworkInstanceRequest {
|
||||
common.UUID inst_id = 1;
|
||||
NetworkConfig config = 2;
|
||||
}
|
||||
|
||||
message RunNetworkInstanceResponse { common.UUID inst_id = 1; }
|
||||
|
||||
message RetainNetworkInstanceRequest { repeated common.UUID inst_ids = 1; }
|
||||
|
||||
message RetainNetworkInstanceResponse {
|
||||
repeated common.UUID remain_inst_ids = 1;
|
||||
}
|
||||
|
||||
message CollectNetworkInfoRequest { repeated common.UUID inst_ids = 1; }
|
||||
|
||||
message CollectNetworkInfoResponse { NetworkInstanceRunningInfoMap info = 1; }
|
||||
|
||||
message ListNetworkInstanceRequest {}
|
||||
|
||||
message ListNetworkInstanceResponse { repeated common.UUID inst_ids = 1; }
|
||||
|
||||
message DeleteNetworkInstanceRequest { repeated common.UUID inst_ids = 1; }
|
||||
|
||||
message DeleteNetworkInstanceResponse {
|
||||
repeated common.UUID remain_inst_ids = 1;
|
||||
}
|
||||
|
||||
service WebClientService {
|
||||
rpc ValidateConfig(ValidateConfigRequest) returns (ValidateConfigResponse) {}
|
||||
rpc RunNetworkInstance(RunNetworkInstanceRequest)
|
||||
returns (RunNetworkInstanceResponse) {}
|
||||
rpc RetainNetworkInstance(RetainNetworkInstanceRequest)
|
||||
returns (RetainNetworkInstanceResponse) {}
|
||||
rpc CollectNetworkInfo(CollectNetworkInfoRequest)
|
||||
returns (CollectNetworkInfoResponse) {}
|
||||
rpc ListNetworkInstance(ListNetworkInstanceRequest)
|
||||
returns (ListNetworkInstanceResponse) {}
|
||||
rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest)
|
||||
returns (DeleteNetworkInstanceResponse) {}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
use url::Host;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/cli.rs"));
|
||||
|
||||
impl PeerRoutePair {
|
||||
pub fn get_latency_ms(&self) -> Option<f64> {
|
||||
let mut ret = u64::MAX;
|
||||
let p = self.peer.as_ref()?;
|
||||
let default_conn_id = p.default_conn_id.map(|id| id.to_string());
|
||||
for conn in p.conns.iter() {
|
||||
let Some(stats) = &conn.stats else {
|
||||
continue;
|
||||
};
|
||||
if default_conn_id == Some(conn.conn_id.to_string()) {
|
||||
return Some(f64::from(stats.latency_us as u32) / 1000.0);
|
||||
}
|
||||
ret = ret.min(stats.latency_us);
|
||||
}
|
||||
|
||||
if ret == u64::MAX {
|
||||
None
|
||||
} else {
|
||||
Some(f64::from(ret as u32) / 1000.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rx_bytes(&self) -> Option<u64> {
|
||||
let mut ret = 0;
|
||||
let p = self.peer.as_ref()?;
|
||||
for conn in p.conns.iter() {
|
||||
let Some(stats) = &conn.stats else {
|
||||
continue;
|
||||
};
|
||||
ret += stats.rx_bytes;
|
||||
}
|
||||
|
||||
if ret == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_tx_bytes(&self) -> Option<u64> {
|
||||
let mut ret = 0;
|
||||
let p = self.peer.as_ref()?;
|
||||
for conn in p.conns.iter() {
|
||||
let Some(stats) = &conn.stats else {
|
||||
continue;
|
||||
};
|
||||
ret += stats.tx_bytes;
|
||||
}
|
||||
|
||||
if ret == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_loss_rate(&self) -> Option<f64> {
|
||||
let mut ret = 0.0;
|
||||
let p = self.peer.as_ref()?;
|
||||
for conn in p.conns.iter() {
|
||||
ret += conn.loss_rate;
|
||||
}
|
||||
|
||||
if ret == 0.0 {
|
||||
None
|
||||
} else {
|
||||
Some(ret as f64)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_tunnel_ipv6(tunnel_info: &super::common::TunnelInfo) -> bool {
|
||||
let Some(local_addr) = &tunnel_info.local_addr else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let u: url::Url = local_addr.clone().into();
|
||||
u.host()
|
||||
.map(|h| matches!(h, Host::Ipv6(_)))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn get_tunnel_proto_str(tunnel_info: &super::common::TunnelInfo) -> String {
|
||||
if Self::is_tunnel_ipv6(tunnel_info) {
|
||||
format!("{}6", tunnel_info.tunnel_type)
|
||||
} else {
|
||||
tunnel_info.tunnel_type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_conn_protos(&self) -> Option<Vec<String>> {
|
||||
let mut ret = vec![];
|
||||
let p = self.peer.as_ref()?;
|
||||
for conn in p.conns.iter() {
|
||||
let Some(tunnel_info) = &conn.tunnel else {
|
||||
continue;
|
||||
};
|
||||
// insert if not exists
|
||||
let tunnel_type = Self::get_tunnel_proto_str(tunnel_info);
|
||||
if !ret.contains(&tunnel_type) {
|
||||
ret.push(tunnel_type);
|
||||
}
|
||||
}
|
||||
|
||||
if ret.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_udp_nat_type(&self) -> String {
|
||||
use crate::proto::common::NatType;
|
||||
let mut ret = NatType::Unknown;
|
||||
if let Some(r) = &self.route.clone().unwrap_or_default().stun_info {
|
||||
ret = NatType::try_from(r.udp_nat_type).unwrap();
|
||||
}
|
||||
format!("{:?}", ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_peer_route_pair(peers: Vec<PeerInfo>, routes: Vec<Route>) -> Vec<PeerRoutePair> {
|
||||
let mut pairs: Vec<PeerRoutePair> = vec![];
|
||||
|
||||
for route in routes.iter() {
|
||||
let peer = peers.iter().find(|peer| peer.peer_id == route.peer_id);
|
||||
let pair = PeerRoutePair {
|
||||
route: Some(route.clone()),
|
||||
peer: peer.cloned(),
|
||||
};
|
||||
|
||||
pairs.push(pair);
|
||||
}
|
||||
|
||||
pairs.sort_by(|a, b| {
|
||||
let a_is_public_server = a
|
||||
.route
|
||||
.as_ref()
|
||||
.and_then(|r| r.feature_flag.as_ref())
|
||||
.is_some_and(|f| f.is_public_server);
|
||||
|
||||
let b_is_public_server = b
|
||||
.route
|
||||
.as_ref()
|
||||
.and_then(|r| r.feature_flag.as_ref())
|
||||
.is_some_and(|f| f.is_public_server);
|
||||
|
||||
if a_is_public_server != b_is_public_server {
|
||||
return if a_is_public_server {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
std::cmp::Ordering::Greater
|
||||
};
|
||||
}
|
||||
|
||||
let a_ip = a
|
||||
.route
|
||||
.as_ref()
|
||||
.and_then(|r| r.ipv4_addr.as_ref())
|
||||
.and_then(|ipv4| ipv4.address.as_ref())
|
||||
.map_or(0, |addr| addr.addr);
|
||||
|
||||
let b_ip = b
|
||||
.route
|
||||
.as_ref()
|
||||
.and_then(|r| r.ipv4_addr.as_ref())
|
||||
.and_then(|ipv4| ipv4.address.as_ref())
|
||||
.map_or(0, |addr| addr.addr);
|
||||
|
||||
a_ip.cmp(&b_ip)
|
||||
});
|
||||
|
||||
pairs
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
include!(concat!(env!("OUT_DIR"), "/config.rs"));
|
||||
|
||||
pub struct Patchable<T> {
|
||||
pub action: Option<ConfigPatchAction>,
|
||||
pub value: Option<T>,
|
||||
}
|
||||
|
||||
impl From<PortForwardPatch> for Patchable<crate::common::config::PortForwardConfig> {
|
||||
fn from(patch: PortForwardPatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(patch.action).ok(),
|
||||
value: patch.cfg.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RoutePatch> for Patchable<cidr::Ipv4Cidr> {
|
||||
fn from(value: RoutePatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(value.action).ok(),
|
||||
value: value.cidr.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExitNodePatch> for Patchable<std::net::IpAddr> {
|
||||
fn from(value: ExitNodePatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(value.action).ok(),
|
||||
value: value.node.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StringPatch> for Patchable<String> {
|
||||
fn from(value: StringPatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(value.action).ok(),
|
||||
value: Some(value.value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UrlPatch> for Patchable<url::Url> {
|
||||
fn from(value: UrlPatch) -> Self {
|
||||
Patchable {
|
||||
action: ConfigPatchAction::try_from(value.action).ok(),
|
||||
value: value.url.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn patch_vec<T>(v: &mut Vec<T>, patches: Vec<Patchable<T>>)
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
for patch in patches {
|
||||
match patch.action {
|
||||
Some(ConfigPatchAction::Add) => {
|
||||
if let Some(value) = patch.value {
|
||||
v.push(value);
|
||||
}
|
||||
}
|
||||
Some(ConfigPatchAction::Remove) => {
|
||||
if let Some(value) = patch.value {
|
||||
v.retain(|x| x != &value);
|
||||
}
|
||||
}
|
||||
Some(ConfigPatchAction::Clear) => {
|
||||
v.clear();
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ syntax = "proto3";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "common.proto";
|
||||
import "cli.proto";
|
||||
import "api_instance.proto";
|
||||
|
||||
package magic_dns;
|
||||
|
||||
@@ -30,7 +30,7 @@ message DnsRecordList {
|
||||
|
||||
message UpdateDnsRecordRequest {
|
||||
string zone = 1;
|
||||
repeated cli.Route routes = 2;
|
||||
repeated api.instance.Route routes = 2;
|
||||
}
|
||||
|
||||
message GetDnsRecordResponse {
|
||||
|
||||
@@ -2,9 +2,8 @@ pub mod rpc_impl;
|
||||
pub mod rpc_types;
|
||||
|
||||
pub mod acl;
|
||||
pub mod cli;
|
||||
pub mod api;
|
||||
pub mod common;
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
pub mod magic_dns;
|
||||
pub mod peer_rpc;
|
||||
|
||||
@@ -6,7 +6,7 @@ use thiserror;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("rust tun error {0}")]
|
||||
#[error("Rust error: {0}")]
|
||||
ExecutionError(#[from] anyhow::Error),
|
||||
|
||||
#[error("Decode error: {0}")]
|
||||
|
||||
+10
-175
@@ -1,188 +1,23 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "common.proto";
|
||||
import "peer_rpc.proto";
|
||||
import "cli.proto";
|
||||
|
||||
package web;
|
||||
|
||||
enum NetworkingMethod {
|
||||
PublicServer = 0;
|
||||
Manual = 1;
|
||||
Standalone = 2;
|
||||
}
|
||||
|
||||
message NetworkConfig {
|
||||
optional string instance_id = 1;
|
||||
|
||||
optional bool dhcp = 2;
|
||||
optional string virtual_ipv4 = 3;
|
||||
optional int32 network_length = 4;
|
||||
optional string hostname = 5;
|
||||
optional string network_name = 6;
|
||||
optional string network_secret = 7;
|
||||
optional NetworkingMethod networking_method = 8;
|
||||
|
||||
optional string public_server_url = 9;
|
||||
repeated string peer_urls = 10;
|
||||
|
||||
repeated string proxy_cidrs = 11;
|
||||
|
||||
optional bool enable_vpn_portal = 12;
|
||||
optional int32 vpn_portal_listen_port = 13;
|
||||
optional string vpn_portal_client_network_addr = 14;
|
||||
optional int32 vpn_portal_client_network_len = 15;
|
||||
|
||||
optional bool advanced_settings = 16;
|
||||
|
||||
repeated string listener_urls = 17;
|
||||
optional int32 rpc_port = 18;
|
||||
optional bool latency_first = 19;
|
||||
|
||||
optional string dev_name = 20;
|
||||
|
||||
optional bool use_smoltcp = 21;
|
||||
optional bool disable_ipv6 = 47;
|
||||
optional bool enable_kcp_proxy = 22;
|
||||
optional bool disable_kcp_input = 23;
|
||||
optional bool disable_p2p = 24;
|
||||
optional bool bind_device = 25;
|
||||
optional bool no_tun = 26;
|
||||
|
||||
optional bool enable_exit_node = 27;
|
||||
optional bool relay_all_peer_rpc = 28;
|
||||
optional bool multi_thread = 29;
|
||||
optional bool enable_relay_network_whitelist = 30;
|
||||
repeated string relay_network_whitelist = 31;
|
||||
optional bool enable_manual_routes = 32;
|
||||
repeated string routes = 33;
|
||||
repeated string exit_nodes = 34;
|
||||
optional bool proxy_forward_by_system = 35;
|
||||
optional bool disable_encryption = 36;
|
||||
optional bool enable_socks5 = 37;
|
||||
optional int32 socks5_port = 38;
|
||||
optional bool disable_udp_hole_punching = 39;
|
||||
optional int32 mtu = 40;
|
||||
repeated string mapped_listeners = 41;
|
||||
|
||||
optional bool enable_magic_dns = 42;
|
||||
optional bool enable_private_mode = 43;
|
||||
|
||||
repeated string rpc_portal_whitelists = 44;
|
||||
|
||||
optional bool enable_quic_proxy = 45;
|
||||
optional bool disable_quic_input = 46;
|
||||
repeated PortForwardConfig port_forwards = 48;
|
||||
|
||||
optional bool disable_sym_hole_punching = 49;
|
||||
}
|
||||
|
||||
message PortForwardConfig {
|
||||
string bind_ip = 1;
|
||||
uint32 bind_port = 2;
|
||||
string dst_ip = 3;
|
||||
uint32 dst_port = 4;
|
||||
string proto = 5;
|
||||
}
|
||||
|
||||
message MyNodeInfo {
|
||||
common.Ipv4Inet virtual_ipv4 = 1;
|
||||
string hostname = 2;
|
||||
string version = 3;
|
||||
peer_rpc.GetIpListResponse ips = 4;
|
||||
common.StunInfo stun_info = 5;
|
||||
repeated common.Url listeners = 6;
|
||||
optional string vpn_portal_cfg = 7;
|
||||
}
|
||||
|
||||
message NetworkInstanceRunningInfo {
|
||||
string dev_name = 1;
|
||||
MyNodeInfo my_node_info = 2;
|
||||
repeated string events = 3;
|
||||
repeated cli.Route routes = 4;
|
||||
repeated cli.PeerInfo peers = 5;
|
||||
repeated cli.PeerRoutePair peer_route_pairs = 6;
|
||||
bool running = 7;
|
||||
optional string error_msg = 8;
|
||||
peer_rpc.RouteForeignNetworkSummary foreign_network_summary = 9;
|
||||
}
|
||||
|
||||
message NetworkInstanceRunningInfoMap {
|
||||
map<string, NetworkInstanceRunningInfo> map = 1;
|
||||
}
|
||||
|
||||
message HeartbeatRequest {
|
||||
common.UUID machine_id = 1;
|
||||
common.UUID inst_id = 2;
|
||||
string user_token = 3;
|
||||
common.UUID machine_id = 1;
|
||||
common.UUID inst_id = 2;
|
||||
string user_token = 3;
|
||||
|
||||
string easytier_version = 4;
|
||||
string report_time = 5;
|
||||
string hostname = 6;
|
||||
string easytier_version = 4;
|
||||
string report_time = 5;
|
||||
string hostname = 6;
|
||||
|
||||
repeated common.UUID running_network_instances = 7;
|
||||
repeated common.UUID running_network_instances = 7;
|
||||
}
|
||||
|
||||
message HeartbeatResponse {
|
||||
}
|
||||
message HeartbeatResponse {}
|
||||
|
||||
service WebServerService {
|
||||
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse) {}
|
||||
}
|
||||
|
||||
message ValidateConfigRequest {
|
||||
NetworkConfig config = 1;
|
||||
}
|
||||
|
||||
message ValidateConfigResponse {
|
||||
string toml_config = 1;
|
||||
}
|
||||
|
||||
message RunNetworkInstanceRequest {
|
||||
common.UUID inst_id = 1;
|
||||
NetworkConfig config = 2;
|
||||
}
|
||||
|
||||
message RunNetworkInstanceResponse {
|
||||
common.UUID inst_id = 1;
|
||||
}
|
||||
|
||||
message RetainNetworkInstanceRequest {
|
||||
repeated common.UUID inst_ids = 1;
|
||||
}
|
||||
|
||||
message RetainNetworkInstanceResponse {
|
||||
repeated common.UUID remain_inst_ids = 1;
|
||||
}
|
||||
|
||||
message CollectNetworkInfoRequest {
|
||||
repeated common.UUID inst_ids = 1;
|
||||
}
|
||||
|
||||
message CollectNetworkInfoResponse {
|
||||
NetworkInstanceRunningInfoMap info = 1;
|
||||
}
|
||||
|
||||
message ListNetworkInstanceRequest {
|
||||
}
|
||||
|
||||
message ListNetworkInstanceResponse {
|
||||
repeated common.UUID inst_ids = 1;
|
||||
}
|
||||
|
||||
message DeleteNetworkInstanceRequest {
|
||||
repeated common.UUID inst_ids = 1;
|
||||
}
|
||||
|
||||
message DeleteNetworkInstanceResponse {
|
||||
repeated common.UUID remain_inst_ids = 1;
|
||||
}
|
||||
|
||||
service WebClientService {
|
||||
rpc ValidateConfig(ValidateConfigRequest) returns (ValidateConfigResponse) {}
|
||||
rpc RunNetworkInstance(RunNetworkInstanceRequest) returns (RunNetworkInstanceResponse) {}
|
||||
rpc RetainNetworkInstance(RetainNetworkInstanceRequest) returns (RetainNetworkInstanceResponse) {}
|
||||
rpc CollectNetworkInfo(CollectNetworkInfoRequest) returns (CollectNetworkInfoResponse) {}
|
||||
rpc ListNetworkInstance(ListNetworkInstanceRequest) returns (ListNetworkInstanceResponse) {}
|
||||
rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest) returns (DeleteNetworkInstanceResponse) {}
|
||||
}
|
||||
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
|
||||
}
|
||||
Reference in New Issue
Block a user