1use crate::integration_types;
2use crate::model::common::DataSource;
3use crate::model::entity_id::EntityId;
4use crate::model::firewall::{
5 AclAction, AclRule, AclRuleType, FirewallAction, FirewallPolicy, FirewallZone, IpSpec,
6 PolicyEndpoint, PortSpec, TrafficFilter,
7};
8
9use super::helpers::origin_from_metadata;
10
11impl From<integration_types::FirewallPolicyResponse> for FirewallPolicy {
14 fn from(p: integration_types::FirewallPolicyResponse) -> Self {
15 let action = p.action.get("type").and_then(|v| v.as_str()).map_or(
16 FirewallAction::Block,
17 |a| match a {
18 "ALLOW" => FirewallAction::Allow,
19 "REJECT" => FirewallAction::Reject,
20 _ => FirewallAction::Block,
21 },
22 );
23
24 #[allow(clippy::as_conversions, clippy::cast_possible_truncation)]
25 let index = p
26 .extra
27 .get("index")
28 .and_then(serde_json::Value::as_i64)
29 .map(|i| i as i32);
30
31 let source_endpoint =
32 convert_policy_endpoint(p.source.as_ref(), p.extra.get("sourceFirewallZoneId"));
33 let destination_endpoint = convert_dest_policy_endpoint(
34 p.destination.as_ref(),
35 p.extra.get("destinationFirewallZoneId"),
36 );
37
38 let source_summary = source_endpoint.filter.as_ref().map(TrafficFilter::summary);
39 let destination_summary = destination_endpoint
40 .filter
41 .as_ref()
42 .map(TrafficFilter::summary);
43
44 let ip_version = p
45 .ip_protocol_scope
46 .as_ref()
47 .and_then(|v| v.get("ipVersion"))
48 .and_then(|v| v.as_str())
49 .map_or(crate::model::firewall::IpVersion::Both, |s| match s {
50 "IPV4_ONLY" | "IPV4" => crate::model::firewall::IpVersion::Ipv4,
51 "IPV6_ONLY" | "IPV6" => crate::model::firewall::IpVersion::Ipv6,
52 _ => crate::model::firewall::IpVersion::Both,
53 });
54
55 let ipsec_mode = p
56 .extra
57 .get("ipsecFilter")
58 .and_then(|v| v.as_str())
59 .map(String::from);
60
61 let connection_states = p
62 .extra
63 .get("connectionStateFilter")
64 .and_then(|v| v.as_array())
65 .map(|arr| {
66 arr.iter()
67 .filter_map(|v| v.as_str().map(String::from))
68 .collect()
69 })
70 .unwrap_or_default();
71
72 FirewallPolicy {
73 id: EntityId::Uuid(p.id),
74 name: p.name,
75 description: p.description,
76 enabled: p.enabled,
77 index,
78 action,
79 ip_version,
80 source: source_endpoint,
81 destination: destination_endpoint,
82 source_summary,
83 destination_summary,
84 protocol_summary: None,
85 schedule: None,
86 ipsec_mode,
87 connection_states,
88 logging_enabled: p.logging_enabled,
89 origin: p.metadata.as_ref().and_then(origin_from_metadata),
90 data_source: DataSource::IntegrationApi,
91 }
92 }
93}
94
95fn convert_policy_endpoint(
96 endpoint: Option<&integration_types::FirewallPolicySource>,
97 flat_zone_id: Option<&serde_json::Value>,
98) -> PolicyEndpoint {
99 if let Some(ep) = endpoint {
100 PolicyEndpoint {
101 zone_id: ep.zone_id.map(EntityId::Uuid),
102 filter: ep
103 .traffic_filter
104 .as_ref()
105 .map(convert_source_traffic_filter),
106 }
107 } else {
108 let zone_id = flat_zone_id
109 .and_then(|v| v.as_str())
110 .and_then(|s| uuid::Uuid::parse_str(s).ok())
111 .map(EntityId::Uuid);
112 PolicyEndpoint {
113 zone_id,
114 filter: None,
115 }
116 }
117}
118
119fn convert_dest_policy_endpoint(
120 endpoint: Option<&integration_types::FirewallPolicyDestination>,
121 flat_zone_id: Option<&serde_json::Value>,
122) -> PolicyEndpoint {
123 if let Some(ep) = endpoint {
124 PolicyEndpoint {
125 zone_id: ep.zone_id.map(EntityId::Uuid),
126 filter: ep.traffic_filter.as_ref().map(convert_dest_traffic_filter),
127 }
128 } else {
129 let zone_id = flat_zone_id
130 .and_then(|v| v.as_str())
131 .and_then(|s| uuid::Uuid::parse_str(s).ok())
132 .map(EntityId::Uuid);
133 PolicyEndpoint {
134 zone_id,
135 filter: None,
136 }
137 }
138}
139
140fn convert_source_traffic_filter(f: &integration_types::SourceTrafficFilter) -> TrafficFilter {
141 use integration_types::SourceTrafficFilter as S;
142 match f {
143 S::Network {
144 network_filter,
145 mac_address_filter,
146 port_filter,
147 } => TrafficFilter::Network {
148 network_ids: network_filter
149 .network_ids
150 .iter()
151 .copied()
152 .map(EntityId::Uuid)
153 .collect(),
154 match_opposite: network_filter.match_opposite,
155 mac_addresses: mac_address_filter
156 .as_ref()
157 .map(|m| m.mac_addresses.clone())
158 .unwrap_or_default(),
159 ports: port_filter.as_ref().map(convert_port_filter),
160 },
161 S::IpAddress {
162 ip_address_filter,
163 mac_address_filter,
164 port_filter,
165 } => TrafficFilter::IpAddress {
166 addresses: convert_ip_address_filter(ip_address_filter),
167 match_opposite: ip_filter_match_opposite(ip_address_filter),
168 mac_addresses: mac_address_filter
169 .as_ref()
170 .map(|m| m.mac_addresses.clone())
171 .unwrap_or_default(),
172 ports: port_filter.as_ref().map(convert_port_filter),
173 },
174 S::MacAddress {
175 mac_address_filter,
176 port_filter,
177 } => TrafficFilter::MacAddress {
178 mac_addresses: mac_address_filter.mac_addresses.clone(),
179 ports: port_filter.as_ref().map(convert_port_filter),
180 },
181 S::Port { port_filter } => TrafficFilter::Port {
182 ports: convert_port_filter(port_filter),
183 },
184 S::Region {
185 region_filter,
186 port_filter,
187 } => TrafficFilter::Region {
188 regions: region_filter.regions.clone(),
189 ports: port_filter.as_ref().map(convert_port_filter),
190 },
191 S::Unknown => TrafficFilter::Other {
192 raw_type: "UNKNOWN".into(),
193 },
194 }
195}
196
197fn convert_dest_traffic_filter(f: &integration_types::DestTrafficFilter) -> TrafficFilter {
198 use integration_types::DestTrafficFilter as D;
199 match f {
200 D::Network {
201 network_filter,
202 port_filter,
203 } => TrafficFilter::Network {
204 network_ids: network_filter
205 .network_ids
206 .iter()
207 .copied()
208 .map(EntityId::Uuid)
209 .collect(),
210 match_opposite: network_filter.match_opposite,
211 mac_addresses: Vec::new(),
212 ports: port_filter.as_ref().map(convert_port_filter),
213 },
214 D::IpAddress {
215 ip_address_filter,
216 port_filter,
217 } => TrafficFilter::IpAddress {
218 addresses: convert_ip_address_filter(ip_address_filter),
219 match_opposite: ip_filter_match_opposite(ip_address_filter),
220 mac_addresses: Vec::new(),
221 ports: port_filter.as_ref().map(convert_port_filter),
222 },
223 D::Port { port_filter } => TrafficFilter::Port {
224 ports: convert_port_filter(port_filter),
225 },
226 D::Region {
227 region_filter,
228 port_filter,
229 } => TrafficFilter::Region {
230 regions: region_filter.regions.clone(),
231 ports: port_filter.as_ref().map(convert_port_filter),
232 },
233 D::Application {
234 application_filter,
235 port_filter,
236 } => TrafficFilter::Application {
237 application_ids: application_filter.application_ids.clone(),
238 ports: port_filter.as_ref().map(convert_port_filter),
239 },
240 D::ApplicationCategory {
241 application_category_filter,
242 port_filter,
243 } => TrafficFilter::ApplicationCategory {
244 category_ids: application_category_filter.application_category_ids.clone(),
245 ports: port_filter.as_ref().map(convert_port_filter),
246 },
247 D::Domain {
248 domain_filter,
249 port_filter,
250 } => {
251 let domains = match domain_filter {
252 integration_types::DomainFilter::Specific { domains } => domains.clone(),
253 integration_types::DomainFilter::Unknown => Vec::new(),
254 };
255 TrafficFilter::Domain {
256 domains,
257 ports: port_filter.as_ref().map(convert_port_filter),
258 }
259 }
260 D::Unknown => TrafficFilter::Other {
261 raw_type: "UNKNOWN".into(),
262 },
263 }
264}
265
266fn convert_port_filter(pf: &integration_types::PortFilter) -> PortSpec {
267 match pf {
268 integration_types::PortFilter::Ports {
269 items,
270 match_opposite,
271 } => PortSpec::Values {
272 items: items
273 .iter()
274 .map(|item| match item {
275 integration_types::PortItem::Number { value } => value.clone(),
276 integration_types::PortItem::Range {
277 start_port,
278 end_port,
279 } => format!("{start_port}-{end_port}"),
280 integration_types::PortItem::Unknown => "?".into(),
281 })
282 .collect(),
283 match_opposite: *match_opposite,
284 },
285 integration_types::PortFilter::TrafficMatchingList {
286 traffic_matching_list_id,
287 match_opposite,
288 } => PortSpec::MatchingList {
289 list_id: EntityId::Uuid(*traffic_matching_list_id),
290 match_opposite: *match_opposite,
291 },
292 integration_types::PortFilter::Unknown => PortSpec::Values {
293 items: Vec::new(),
294 match_opposite: false,
295 },
296 }
297}
298
299fn convert_ip_address_filter(f: &integration_types::IpAddressFilter) -> Vec<IpSpec> {
300 match f {
301 integration_types::IpAddressFilter::Specific { items, .. } => items
302 .iter()
303 .map(|item| match item {
304 integration_types::IpAddressItem::Address { value } => IpSpec::Address {
305 value: value.clone(),
306 },
307 integration_types::IpAddressItem::Range { start, stop } => IpSpec::Range {
308 start: start.clone(),
309 stop: stop.clone(),
310 },
311 integration_types::IpAddressItem::Subnet { value } => IpSpec::Subnet {
312 value: value.clone(),
313 },
314 })
315 .collect(),
316 integration_types::IpAddressFilter::TrafficMatchingList {
317 traffic_matching_list_id,
318 ..
319 } => vec![IpSpec::MatchingList {
320 list_id: EntityId::Uuid(*traffic_matching_list_id),
321 }],
322 integration_types::IpAddressFilter::Unknown => Vec::new(),
323 }
324}
325
326fn ip_filter_match_opposite(f: &integration_types::IpAddressFilter) -> bool {
327 match f {
328 integration_types::IpAddressFilter::Specific { match_opposite, .. }
329 | integration_types::IpAddressFilter::TrafficMatchingList { match_opposite, .. } => {
330 *match_opposite
331 }
332 integration_types::IpAddressFilter::Unknown => false,
333 }
334}
335
336impl From<integration_types::FirewallZoneResponse> for FirewallZone {
339 fn from(z: integration_types::FirewallZoneResponse) -> Self {
340 FirewallZone {
341 id: EntityId::Uuid(z.id),
342 name: z.name,
343 network_ids: z.network_ids.into_iter().map(EntityId::Uuid).collect(),
344 origin: origin_from_metadata(&z.metadata),
345 source: DataSource::IntegrationApi,
346 }
347 }
348}
349
350impl From<integration_types::AclRuleResponse> for AclRule {
353 fn from(r: integration_types::AclRuleResponse) -> Self {
354 let rule_type = match r.rule_type.as_str() {
355 "MAC" => AclRuleType::Mac,
356 _ => AclRuleType::Ipv4,
357 };
358
359 let action = match r.action.as_str() {
360 "ALLOW" => AclAction::Allow,
361 _ => AclAction::Block,
362 };
363
364 AclRule {
365 id: EntityId::Uuid(r.id),
366 name: r.name,
367 enabled: r.enabled,
368 rule_type,
369 action,
370 source_summary: None,
371 destination_summary: None,
372 origin: origin_from_metadata(&r.metadata),
373 source: DataSource::IntegrationApi,
374 }
375 }
376}