mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 02:09:06 +00:00
add ipv6 cli
This commit is contained in:
@@ -51,13 +51,14 @@ use easytier::{
|
||||
ListCredentialsRequest, ListCredentialsResponse, ListForeignNetworkRequest,
|
||||
ListGlobalForeignNetworkRequest, ListMappedListenerRequest, ListPeerRequest,
|
||||
ListPeerResponse, ListPortForwardRequest, ListPortForwardResponse,
|
||||
ListRouteRequest, ListRouteResponse, MappedListener, MappedListenerManageRpc,
|
||||
ListPublicIpv6InfoRequest, ListPublicIpv6InfoResponse, ListRouteRequest,
|
||||
ListRouteResponse, MappedListener, MappedListenerManageRpc,
|
||||
MappedListenerManageRpcClientFactory, MetricSnapshot, NodeInfo, PeerManageRpc,
|
||||
PeerManageRpcClientFactory, PortForwardManageRpc,
|
||||
PortForwardManageRpcClientFactory, RevokeCredentialRequest, ShowNodeInfoRequest,
|
||||
StatsRpc, StatsRpcClientFactory, TcpProxyEntryState, TcpProxyEntryTransportType,
|
||||
TcpProxyRpc, TcpProxyRpcClientFactory, TrustedKeySourcePb, VpnPortalInfo,
|
||||
VpnPortalRpc, VpnPortalRpcClientFactory,
|
||||
PortForwardManageRpcClientFactory, RevokeCredentialRequest, Route as ApiRoute,
|
||||
ShowNodeInfoRequest, StatsRpc, StatsRpcClientFactory, TcpProxyEntryState,
|
||||
TcpProxyEntryTransportType, TcpProxyRpc, TcpProxyRpcClientFactory,
|
||||
TrustedKeySourcePb, VpnPortalInfo, VpnPortalRpc, VpnPortalRpcClientFactory,
|
||||
instance_identifier::{InstanceSelector, Selector},
|
||||
list_global_foreign_network_response, list_peer_route_pair,
|
||||
},
|
||||
@@ -193,6 +194,7 @@ struct PeerArgs {
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum PeerSubCommand {
|
||||
List,
|
||||
Ipv6,
|
||||
ListForeign {
|
||||
#[arg(
|
||||
long,
|
||||
@@ -536,6 +538,12 @@ struct RouteListData {
|
||||
peer_routes: Vec<PeerRoutePair>,
|
||||
}
|
||||
|
||||
struct PeerIpv6DataRaw {
|
||||
node_info: NodeInfo,
|
||||
routes: Vec<ApiRoute>,
|
||||
provider_info: ListPublicIpv6InfoResponse,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct PeerCenterRowData {
|
||||
node_id: String,
|
||||
@@ -963,6 +971,27 @@ impl<'a> CommandHandler<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
async fn fetch_local_public_ipv6_info(&self) -> Result<ListPublicIpv6InfoResponse, Error> {
|
||||
Ok(self
|
||||
.get_peer_manager_client()
|
||||
.await?
|
||||
.list_public_ipv6_info(
|
||||
BaseController::default(),
|
||||
ListPublicIpv6InfoRequest {
|
||||
instance: Some(self.instance_selector.clone()),
|
||||
},
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
async fn fetch_peer_ipv6_data(&self) -> Result<PeerIpv6DataRaw, Error> {
|
||||
Ok(PeerIpv6DataRaw {
|
||||
node_info: self.fetch_node_info().await?,
|
||||
routes: self.list_routes().await?.routes,
|
||||
provider_info: self.fetch_local_public_ipv6_info().await?,
|
||||
})
|
||||
}
|
||||
|
||||
async fn fetch_connector_list(&self) -> Result<Vec<Connector>, Error> {
|
||||
Ok(self
|
||||
.get_connector_manager_client()
|
||||
@@ -1375,6 +1404,154 @@ impl<'a> CommandHandler<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
async fn handle_peer_ipv6(&self) -> Result<(), Error> {
|
||||
#[derive(tabled::Tabled, serde::Serialize)]
|
||||
struct PeerIpv6NodeRow {
|
||||
peer_id: u32,
|
||||
hostname: String,
|
||||
inst_id: String,
|
||||
ipv4: String,
|
||||
public_ipv6_addr: String,
|
||||
provider_prefix: String,
|
||||
}
|
||||
|
||||
#[derive(tabled::Tabled, serde::Serialize)]
|
||||
struct ProviderLeaseRow {
|
||||
peer_id: u32,
|
||||
inst_id: String,
|
||||
leased_addr: String,
|
||||
valid_until: String,
|
||||
reused: bool,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct ProviderLeaseSection {
|
||||
provider_prefix: String,
|
||||
leases: Vec<ProviderLeaseRow>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct PeerIpv6View {
|
||||
nodes: Vec<PeerIpv6NodeRow>,
|
||||
local_provider: Option<ProviderLeaseSection>,
|
||||
}
|
||||
|
||||
fn fmt_ipv6_inet(value: Option<easytier::proto::common::Ipv6Inet>) -> String {
|
||||
value
|
||||
.map(|value| value.to_string())
|
||||
.unwrap_or_else(|| "-".to_string())
|
||||
}
|
||||
|
||||
fn fmt_valid_until(unix_seconds: i64) -> String {
|
||||
chrono::DateTime::<chrono::Utc>::from_timestamp(unix_seconds, 0)
|
||||
.map(|ts| {
|
||||
ts.with_timezone(&chrono::Local)
|
||||
.format("%Y-%m-%d %H:%M:%S")
|
||||
.to_string()
|
||||
})
|
||||
.unwrap_or_else(|| unix_seconds.to_string())
|
||||
}
|
||||
|
||||
let build_view = |data: &PeerIpv6DataRaw| {
|
||||
let mut nodes = Vec::with_capacity(data.routes.len() + 1);
|
||||
nodes.push(PeerIpv6NodeRow {
|
||||
peer_id: data.node_info.peer_id,
|
||||
hostname: data.node_info.hostname.clone(),
|
||||
inst_id: data.node_info.inst_id.clone(),
|
||||
ipv4: data.node_info.ipv4_addr.clone(),
|
||||
public_ipv6_addr: fmt_ipv6_inet(data.node_info.public_ipv6_addr),
|
||||
provider_prefix: fmt_ipv6_inet(data.node_info.ipv6_public_addr_prefix),
|
||||
});
|
||||
nodes.extend(data.routes.iter().map(|route| {
|
||||
PeerIpv6NodeRow {
|
||||
peer_id: route.peer_id,
|
||||
hostname: route.hostname.clone(),
|
||||
inst_id: route.inst_id.clone(),
|
||||
ipv4: route
|
||||
.ipv4_addr
|
||||
.map(|ipv4| ipv4.to_string())
|
||||
.unwrap_or_else(|| "-".to_string()),
|
||||
public_ipv6_addr: fmt_ipv6_inet(route.public_ipv6_addr),
|
||||
provider_prefix: fmt_ipv6_inet(route.ipv6_public_addr_prefix),
|
||||
}
|
||||
}));
|
||||
nodes.sort_by_key(|row| {
|
||||
(
|
||||
row.peer_id != data.node_info.peer_id,
|
||||
row.peer_id,
|
||||
row.inst_id.clone(),
|
||||
)
|
||||
});
|
||||
|
||||
let local_provider = data.provider_info.provider_prefix.map(|provider_prefix| {
|
||||
let mut leases = data
|
||||
.provider_info
|
||||
.provider_leases
|
||||
.iter()
|
||||
.map(|lease| ProviderLeaseRow {
|
||||
peer_id: lease.peer_id,
|
||||
inst_id: lease.inst_id.clone(),
|
||||
leased_addr: fmt_ipv6_inet(lease.leased_addr),
|
||||
valid_until: fmt_valid_until(lease.valid_until_unix_seconds),
|
||||
reused: lease.reused,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
leases.sort_by_key(|lease| {
|
||||
(
|
||||
lease.peer_id,
|
||||
lease.inst_id.clone(),
|
||||
lease.leased_addr.clone(),
|
||||
)
|
||||
});
|
||||
ProviderLeaseSection {
|
||||
provider_prefix: provider_prefix.to_string(),
|
||||
leases,
|
||||
}
|
||||
});
|
||||
|
||||
PeerIpv6View {
|
||||
nodes,
|
||||
local_provider,
|
||||
}
|
||||
};
|
||||
|
||||
let results = self
|
||||
.collect_instance_results(|handler| Box::pin(handler.fetch_peer_ipv6_data()))
|
||||
.await?;
|
||||
|
||||
if self.verbose || *self.output_format == OutputFormat::Json {
|
||||
return self.print_json_results(
|
||||
results
|
||||
.into_iter()
|
||||
.map(|result| result.map(|data| build_view(&data)))
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
self.print_results(&results, |data| {
|
||||
let view = build_view(data);
|
||||
print_output(&view.nodes, self.output_format, &[], &[], self.no_trunc)?;
|
||||
|
||||
if let Some(local_provider) = view.local_provider {
|
||||
println!();
|
||||
println!("Local provider prefix: {}", local_provider.provider_prefix);
|
||||
if local_provider.leases.is_empty() {
|
||||
println!("No active provider leases");
|
||||
} else {
|
||||
print_output(
|
||||
&local_provider.leases,
|
||||
self.output_format,
|
||||
&[],
|
||||
&[],
|
||||
self.no_trunc,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
async fn handle_route_dump(&self) -> Result<(), Error> {
|
||||
let results = self
|
||||
.collect_instance_results(|handler| Box::pin(handler.fetch_route_dump()))
|
||||
@@ -2652,6 +2829,9 @@ async fn main() -> Result<(), Error> {
|
||||
Some(PeerSubCommand::List) => {
|
||||
handler.handle_peer_list().await?;
|
||||
}
|
||||
Some(PeerSubCommand::Ipv6) => {
|
||||
handler.handle_peer_ipv6().await?;
|
||||
}
|
||||
Some(PeerSubCommand::ListForeign { trusted_keys }) => {
|
||||
handler.handle_foreign_network_list(*trusted_keys).await?;
|
||||
}
|
||||
|
||||
@@ -1299,6 +1299,10 @@ impl PeerManager {
|
||||
self.get_route().get_my_public_ipv6_addr().await
|
||||
}
|
||||
|
||||
pub async fn get_local_public_ipv6_info(&self) -> instance::ListPublicIpv6InfoResponse {
|
||||
self.get_route().get_local_public_ipv6_info().await
|
||||
}
|
||||
|
||||
pub async fn dump_route(&self) -> String {
|
||||
self.get_route().dump().await
|
||||
}
|
||||
|
||||
@@ -369,6 +369,7 @@ impl From<RoutePeerInfo> for crate::proto::api::instance::Route {
|
||||
|
||||
ipv6_addr: val.ipv6_addr,
|
||||
public_ipv6_addr: val.ipv6_public_addr_lease,
|
||||
ipv6_public_addr_prefix: val.ipv6_public_addr_prefix,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3953,6 +3954,39 @@ impl Route for PeerRoute {
|
||||
self.public_ipv6_service.my_addr()
|
||||
}
|
||||
|
||||
async fn get_local_public_ipv6_info(
|
||||
&self,
|
||||
) -> crate::proto::api::instance::ListPublicIpv6InfoResponse {
|
||||
let Some((provider, leases)) = self.public_ipv6_service.local_provider_state() else {
|
||||
return crate::proto::api::instance::ListPublicIpv6InfoResponse::default();
|
||||
};
|
||||
|
||||
crate::proto::api::instance::ListPublicIpv6InfoResponse {
|
||||
provider_prefix: Some(
|
||||
Ipv6Inet::new(
|
||||
provider.prefix.first_address(),
|
||||
provider.prefix.network_length(),
|
||||
)
|
||||
.unwrap()
|
||||
.into(),
|
||||
),
|
||||
provider_leases: leases
|
||||
.into_iter()
|
||||
.map(|lease| crate::proto::api::instance::PublicIpv6LeaseInfo {
|
||||
peer_id: lease.peer_id,
|
||||
inst_id: lease.inst_id.to_string(),
|
||||
leased_addr: Some(lease.addr.into()),
|
||||
valid_until_unix_seconds: lease
|
||||
.valid_until
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs() as i64,
|
||||
reused: lease.reused,
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_peer_id_by_ipv4(&self, ipv4_addr: &Ipv4Addr) -> Option<PeerId> {
|
||||
let route_table = &self.service_impl.route_table;
|
||||
if let Some(p) = route_table.ipv4_peer_id_map.get(ipv4_addr) {
|
||||
|
||||
@@ -641,6 +641,20 @@ impl PublicIpv6Service {
|
||||
pub(crate) fn my_addr(&self) -> Option<Ipv6Inet> {
|
||||
*self.my_addr_cache.lock().unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn local_provider_state(
|
||||
&self,
|
||||
) -> Option<(PublicIpv6Provider, Vec<PublicIpv6ProviderLease>)> {
|
||||
let provider = self.selected_provider()?;
|
||||
if provider.peer_id != self.my_peer_id() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let state = Self::prune_expired_leases(&provider, self.current_provider_state());
|
||||
let mut leases = state.leases.into_values().collect::<Vec<_>>();
|
||||
leases.sort_by_key(|lease| (lease.peer_id, lease.inst_id, lease.addr));
|
||||
Some((provider, leases))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -9,10 +9,13 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
common::{PeerId, global_ctx::NetworkIdentity},
|
||||
proto::peer_rpc::{
|
||||
proto::{
|
||||
api::instance::ListPublicIpv6InfoResponse,
|
||||
peer_rpc::{
|
||||
ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey, PeerIdentityType,
|
||||
RouteForeignNetworkInfos, RouteForeignNetworkSummary, RoutePeerInfo,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
@@ -102,6 +105,10 @@ pub trait Route {
|
||||
None
|
||||
}
|
||||
|
||||
async fn get_local_public_ipv6_info(&self) -> ListPublicIpv6InfoResponse {
|
||||
ListPublicIpv6InfoResponse::default()
|
||||
}
|
||||
|
||||
async fn get_peer_id_by_ipv4(&self, _ipv4: &Ipv4Addr) -> Option<PeerId> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ use crate::{
|
||||
GetWhitelistRequest, GetWhitelistResponse, ListCredentialsRequest,
|
||||
ListCredentialsResponse, ListForeignNetworkRequest, ListForeignNetworkResponse,
|
||||
ListGlobalForeignNetworkRequest, ListGlobalForeignNetworkResponse, ListPeerRequest,
|
||||
ListPeerResponse, ListRouteRequest, ListRouteResponse, PeerInfo, PeerManageRpc,
|
||||
RevokeCredentialRequest, RevokeCredentialResponse, ShowNodeInfoRequest,
|
||||
ShowNodeInfoResponse,
|
||||
ListPeerResponse, ListPublicIpv6InfoRequest, ListPublicIpv6InfoResponse,
|
||||
ListRouteRequest, ListRouteResponse, PeerInfo, PeerManageRpc, RevokeCredentialRequest,
|
||||
RevokeCredentialResponse, ShowNodeInfoRequest, ShowNodeInfoResponse,
|
||||
},
|
||||
rpc_types::{self, controller::BaseController},
|
||||
},
|
||||
@@ -99,6 +99,16 @@ impl PeerManageRpc for PeerManagerRpcService {
|
||||
Ok(reply)
|
||||
}
|
||||
|
||||
async fn list_public_ipv6_info(
|
||||
&self,
|
||||
_: BaseController,
|
||||
_request: ListPublicIpv6InfoRequest,
|
||||
) -> Result<ListPublicIpv6InfoResponse, rpc_types::error::Error> {
|
||||
Ok(weak_upgrade(&self.peer_manager)?
|
||||
.get_local_public_ipv6_info()
|
||||
.await)
|
||||
}
|
||||
|
||||
async fn list_route(
|
||||
&self,
|
||||
_: BaseController,
|
||||
|
||||
@@ -82,6 +82,7 @@ message Route {
|
||||
|
||||
common.Ipv6Inet ipv6_addr = 15;
|
||||
common.Ipv6Inet public_ipv6_addr = 16;
|
||||
common.Ipv6Inet ipv6_public_addr_prefix = 17;
|
||||
}
|
||||
|
||||
message PeerRoutePair {
|
||||
@@ -109,6 +110,21 @@ message ShowNodeInfoRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ShowNodeInfoResponse { NodeInfo node_info = 1; }
|
||||
|
||||
message PublicIpv6LeaseInfo {
|
||||
uint32 peer_id = 1;
|
||||
string inst_id = 2;
|
||||
common.Ipv6Inet leased_addr = 3;
|
||||
int64 valid_until_unix_seconds = 4;
|
||||
bool reused = 5;
|
||||
}
|
||||
|
||||
message ListPublicIpv6InfoRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ListPublicIpv6InfoResponse {
|
||||
common.Ipv6Inet provider_prefix = 1;
|
||||
repeated PublicIpv6LeaseInfo provider_leases = 2;
|
||||
}
|
||||
|
||||
message ListRouteRequest { InstanceIdentifier instance = 1; }
|
||||
|
||||
message ListRouteResponse { repeated Route routes = 1; }
|
||||
@@ -170,6 +186,8 @@ message GetForeignNetworkSummaryResponse {
|
||||
|
||||
service PeerManageRpc {
|
||||
rpc ListPeer(ListPeerRequest) returns (ListPeerResponse);
|
||||
rpc ListPublicIpv6Info(ListPublicIpv6InfoRequest)
|
||||
returns (ListPublicIpv6InfoResponse);
|
||||
rpc ListRoute(ListRouteRequest) returns (ListRouteResponse);
|
||||
rpc DumpRoute(DumpRouteRequest) returns (DumpRouteResponse);
|
||||
rpc ListForeignNetwork(ListForeignNetworkRequest)
|
||||
|
||||
@@ -3,7 +3,10 @@ use std::sync::Arc;
|
||||
use crate::{
|
||||
instance_manager::NetworkInstanceManager,
|
||||
proto::{
|
||||
api::instance::{self, ListPeerRequest, ListPeerResponse, PeerManageRpc},
|
||||
api::instance::{
|
||||
self, ListPeerRequest, ListPeerResponse, ListPublicIpv6InfoRequest,
|
||||
ListPublicIpv6InfoResponse, PeerManageRpc,
|
||||
},
|
||||
rpc_types::controller::BaseController,
|
||||
},
|
||||
};
|
||||
@@ -34,6 +37,17 @@ impl PeerManageRpc for PeerManageRpcService {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_public_ipv6_info(
|
||||
&self,
|
||||
ctrl: Self::Controller,
|
||||
req: ListPublicIpv6InfoRequest,
|
||||
) -> crate::proto::rpc_types::error::Result<ListPublicIpv6InfoResponse> {
|
||||
super::get_instance_service(&self.instance_manager, &req.instance)?
|
||||
.get_peer_manage_service()
|
||||
.list_public_ipv6_info(ctrl, req)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_route(
|
||||
&self,
|
||||
ctrl: Self::Controller,
|
||||
|
||||
@@ -807,6 +807,32 @@ pub async fn public_ipv6_auto_addr_end_to_end() {
|
||||
.into()
|
||||
)
|
||||
);
|
||||
let provider_info = provider
|
||||
.get_peer_manager()
|
||||
.get_local_public_ipv6_info()
|
||||
.await;
|
||||
let client_peer_id = client.get_peer_manager().get_my_info().await.peer_id;
|
||||
assert_eq!(
|
||||
provider_info.provider_prefix,
|
||||
Some(
|
||||
cidr::Ipv6Inet::new(
|
||||
provider_prefix.first_address(),
|
||||
provider_prefix.network_length()
|
||||
)
|
||||
.unwrap()
|
||||
.into()
|
||||
)
|
||||
);
|
||||
assert_eq!(provider_info.provider_leases.len(), 1);
|
||||
assert_eq!(provider_info.provider_leases[0].peer_id, client_peer_id);
|
||||
assert_eq!(
|
||||
provider_info.provider_leases[0].inst_id,
|
||||
client_id.to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
provider_info.provider_leases[0].leased_addr,
|
||||
Some(leased.into())
|
||||
);
|
||||
assert!(
|
||||
leased.address().segments()[0] & 0xfe00 != 0xfc00,
|
||||
"leased address should not be unique-local: {leased}"
|
||||
|
||||
Reference in New Issue
Block a user