mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-13 17:35:37 +00:00
Implement ACL (#1140)
1. get acl stats
```
./easytier-cli acl stats
AclStats:
Global:
CacheHits: 4
CacheMaxSize: 10000
CacheSize: 5
DefaultAllows: 3
InboundPacketsAllowed: 2
InboundPacketsTotal: 2
OutboundPacketsAllowed: 7
OutboundPacketsTotal: 7
PacketsAllowed: 9
PacketsTotal: 9
RuleMatches: 2
ConnTrack:
[src: 10.14.11.1:57444, dst: 10.14.11.2:1000, proto: Tcp, state: New, pkts: 1, bytes: 60, created: 2025-07-24 10:13:39 +08:00, last_seen: 2025-07-24 10:13:39 +08:00]
Rules:
[name: 'tcp_whitelist', prio: 1000, action: Allow, enabled: true, proto: Tcp, ports: ["1000"], src_ports: [], src_ips: [], dst_ips: [], stateful: true, rate: 0, burst: 0] [pkts: 2, bytes: 120]
```
2. use tcp/udp whitelist to block unexpected traffic.
`sudo ./easytier-core -d --tcp-whitelist 1000`
3. use complete acl ability with config file:
```
[[acl.acl_v1.chains]]
name = "inbound_whitelist"
chain_type = 1
description = "Auto-generated inbound whitelist from CLI"
enabled = true
default_action = 2
[[acl.acl_v1.chains.rules]]
name = "tcp_whitelist"
description = "Auto-generated TCP whitelist rule"
priority = 1000
enabled = true
protocol = 1
ports = ["1000"]
source_ips = []
destination_ips = []
source_ports = []
action = 1
rate_limit = 0
burst_limit = 0
stateful = true
```
This commit is contained in:
@@ -27,11 +27,12 @@ use easytier::{
|
||||
},
|
||||
proto::{
|
||||
cli::{
|
||||
list_peer_route_pair, ConnectorManageRpc, ConnectorManageRpcClientFactory,
|
||||
DumpRouteRequest, GetVpnPortalInfoRequest, ListConnectorRequest,
|
||||
ListForeignNetworkRequest, ListGlobalForeignNetworkRequest, ListMappedListenerRequest,
|
||||
ListPeerRequest, ListPeerResponse, ListRouteRequest, ListRouteResponse,
|
||||
ManageMappedListenerRequest, MappedListenerManageAction, MappedListenerManageRpc,
|
||||
list_peer_route_pair, AclManageRpc, AclManageRpcClientFactory, ConnectorManageRpc,
|
||||
ConnectorManageRpcClientFactory, DumpRouteRequest, GetAclStatsRequest,
|
||||
GetVpnPortalInfoRequest, ListConnectorRequest, ListForeignNetworkRequest,
|
||||
ListGlobalForeignNetworkRequest, ListMappedListenerRequest, ListPeerRequest,
|
||||
ListPeerResponse, ListRouteRequest, ListRouteResponse, ManageMappedListenerRequest,
|
||||
MappedListenerManageAction, MappedListenerManageRpc,
|
||||
MappedListenerManageRpcClientFactory, NodeInfo, PeerManageRpc,
|
||||
PeerManageRpcClientFactory, ShowNodeInfoRequest, TcpProxyEntryState,
|
||||
TcpProxyEntryTransportType, TcpProxyRpc, TcpProxyRpcClientFactory, VpnPortalRpc,
|
||||
@@ -93,6 +94,8 @@ enum SubCommand {
|
||||
Service(ServiceArgs),
|
||||
#[command(about = "show tcp/kcp proxy status")]
|
||||
Proxy,
|
||||
#[command(about = "show ACL rules statistics")]
|
||||
Acl(AclArgs),
|
||||
#[command(about = t!("core_clap.generate_completions").to_string())]
|
||||
GenAutocomplete { shell: Shell },
|
||||
}
|
||||
@@ -179,6 +182,17 @@ struct NodeArgs {
|
||||
sub_command: Option<NodeSubCommand>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct AclArgs {
|
||||
#[command(subcommand)]
|
||||
sub_command: Option<AclSubCommand>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum AclSubCommand {
|
||||
Stats,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct ServiceArgs {
|
||||
#[arg(short, long, default_value = env!("CARGO_PKG_NAME"), help = "service name")]
|
||||
@@ -301,6 +315,18 @@ impl CommandHandler<'_> {
|
||||
.with_context(|| "failed to get vpn portal client")?)
|
||||
}
|
||||
|
||||
async fn get_acl_manager_client(
|
||||
&self,
|
||||
) -> Result<Box<dyn AclManageRpc<Controller = BaseController>>, Error> {
|
||||
Ok(self
|
||||
.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.scoped_client::<AclManageRpcClientFactory<BaseController>>("".to_string())
|
||||
.await
|
||||
.with_context(|| "failed to get acl manager client")?)
|
||||
}
|
||||
|
||||
async fn get_tcp_proxy_client(
|
||||
&self,
|
||||
transport_type: &str,
|
||||
@@ -688,6 +714,26 @@ impl CommandHandler<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_acl_stats(&self) -> Result<(), Error> {
|
||||
let client = self.get_acl_manager_client().await?;
|
||||
let request = GetAclStatsRequest::default();
|
||||
let response = client
|
||||
.get_acl_stats(BaseController::default(), request)
|
||||
.await?;
|
||||
|
||||
if let Some(acl_stats) = response.acl_stats {
|
||||
if self.output_format == &OutputFormat::Json {
|
||||
println!("{}", serde_json::to_string_pretty(&acl_stats)?);
|
||||
} else {
|
||||
println!("{}", acl_stats);
|
||||
}
|
||||
} else {
|
||||
println!("No ACL statistics available");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_mapped_listener_list(&self) -> Result<(), Error> {
|
||||
let client = self.get_mapped_listener_manager_client().await?;
|
||||
let request = ListMappedListenerRequest::default();
|
||||
@@ -1443,6 +1489,11 @@ async fn main() -> Result<(), Error> {
|
||||
|
||||
print_output(&table_rows, &cli.output_format)?;
|
||||
}
|
||||
SubCommand::Acl(acl_args) => match &acl_args.sub_command {
|
||||
Some(AclSubCommand::Stats) | None => {
|
||||
handler.handle_acl_stats().await?;
|
||||
}
|
||||
},
|
||||
SubCommand::GenAutocomplete { shell } => {
|
||||
let mut cmd = Cli::command();
|
||||
easytier::print_completions(shell, &mut cmd, "easytier-cli");
|
||||
|
||||
Reference in New Issue
Block a user