narrowlink_types/
policy.rs1use std::net::IpAddr;
2
3use regex_lite::Regex;
4use serde::{Deserialize, Serialize};
5use validator::{Validate, ValidationError, ValidationErrors};
6use wildmatch::WildMatch;
7
8use crate::generic::{Connect, Protocol};
9
10#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
11pub enum Target {
12 Any,
13 Agent(String),
14}
15
16#[derive(Debug, Serialize, Deserialize, Clone)]
17pub enum PolicyItem {
18 Domain(Target, String, u16, Protocol),
19 Ip(Target, ipnet::IpNet, u16, Protocol),
20}
21#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
22pub enum PolicyType {
23 BlackList,
24 WhiteList,
25}
26
27#[derive(Debug, Serialize, Deserialize, Clone)]
28pub struct Policy {
29 #[serde(rename = "type")]
30 pub policy_type: PolicyType,
31 pub policies: Vec<PolicyItem>,
32}
33
34impl Policy {
35 pub fn permit(&self, con: &Connect) -> bool {
36 let contains = self.policies.iter().any(|p| p.contains(con));
37 match self.policy_type {
38 PolicyType::BlackList => !contains,
39 PolicyType::WhiteList => contains,
40 }
41 }
42 pub fn is_agent_visible(&self, peer_agent_name: &str) -> bool {
43 self.policies.iter().any(|p| {
44 let target = match p {
45 PolicyItem::Domain(t, _, _, _) => t,
46 PolicyItem::Ip(t, _, _, _) => t,
47 };
48 target == &Target::Any || target == &Target::Agent(peer_agent_name.to_string())
49 })
50 }
51 pub fn retain_ip(&mut self) {
52 self.policies
53 .retain(|p| matches!(p, PolicyItem::Ip(_, _, _, _)));
54 }
55 pub fn agent_policies(&self, peer_agent_name: &str) -> Self {
56 Self {
57 policy_type: self.policy_type.clone(),
58 policies: self
59 .policies
60 .iter()
61 .filter(|p| {
62 let target = match p {
63 PolicyItem::Domain(t, _, _, _) => t,
64 PolicyItem::Ip(t, _, _, _) => t,
65 };
66 target == &Target::Any || target == &Target::Agent(peer_agent_name.to_string())
67 })
68 .cloned()
69 .collect(),
70 }
71 }
72}
73
74impl Validate for Policy {
75 fn validate(&self) -> Result<(), ValidationErrors> {
76 for policy in self.policies.iter() {
77 policy.validate()?;
78 }
79 Ok(())
80 }
81}
82
83impl PolicyItem {
84 pub fn contains(&self, con: &Connect) -> bool {
85 let (address_status, policy_port, protocol) = match self {
86 Self::Domain(_, domain, policy_port, protocol) => (
87 WildMatch::new(domain).matches(&con.host),
89 policy_port,
90 protocol,
91 ),
92 Self::Ip(_, ip, port, protocol) => (
93 if let Ok(state) = con.host.parse::<IpAddr>().map(|addr| ip.contains(&addr)) {
94 state
95 } else {
96 false
97 },
98 port,
99 protocol,
100 ),
101 };
102
103 address_status
104 && (policy_port == &con.port || policy_port == &0)
105 && protocol == &con.protocol
106 }
107}
108
109impl Validate for PolicyItem {
110 fn validate(&self) -> Result<(), ValidationErrors> {
111 if let PolicyItem::Domain(_agent_id, addr, _port, _protocol) = self {
112 if let Ok(re) = Regex::new(r"^[^.][a-z0-9-.*?]{1,256}$") {
113 if re.is_match(addr) {
114 return Ok(());
115 }
116 }
117 let mut err = ValidationErrors::new();
118 err.add("Domain", ValidationError::new("Invalid Domain Name"));
119 return Err(err);
120 }
121 Ok(())
122 }
123}