Skip to content

Commit 67979ea

Browse files
authored
Merge pull request #215 from da-z97/master
feat: add basic fortiproxy functionality
2 parents 2644799 + 293d00c commit 67979ea

12 files changed

Lines changed: 1222 additions & 10 deletions

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ Setting up the local enviroment is done with [python poetry](https://python-poet
1313
After making code changes, please run the linters and fix all errors:
1414

1515
```
16-
> poetry run tox --elinter
16+
> poetry run tox -elinter
1717
```
1818

1919
### Auto formatting code
2020

2121
After making code changes, please run code formatters:
2222

2323
```
24-
> poetry runtox --eformatter
24+
> poetry run tox -eformatter
2525
```
2626

2727

fortilib/address.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ def render(self) -> dict:
6666
"type": "ipmask",
6767
"subnet": f"{self.subnet.network_address} {self.subnet.netmask}",
6868
"comment": self.comment,
69-
"associated-interface": self.interface.name if self.interface else "",
69+
"associated-interface": (
70+
self.interface.name if self.interface else ""
71+
),
7072
"color": self.color,
7173
}
7274

@@ -115,7 +117,9 @@ def render(self) -> dict:
115117
"start-ip": str(self.ip_start),
116118
"end-ip": str(self.ip_end),
117119
"comment": self.comment,
118-
"associated-interface": self.interface.name if self.interface else "",
120+
"associated-interface": (
121+
self.interface.name if self.interface else ""
122+
),
119123
"color": self.color,
120124
}
121125

@@ -156,6 +160,8 @@ def render(self) -> dict:
156160
"type": "fqdn",
157161
"fqdn": self.fqdn,
158162
"comment": self.comment,
159-
"associated-interface": self.interface.name if self.interface else "",
163+
"associated-interface": (
164+
self.interface.name if self.interface else ""
165+
),
160166
"color": self.color,
161167
}

fortilib/fortiproxy.py

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
from typing import List
2+
3+
from fortilib.firewall import FortigateFirewall
4+
from fortilib.fortigateapi import (
5+
FortiGateApiPolicyDirection,
6+
FortigateFirewallApi,
7+
)
8+
from fortilib.proxypolicy import FortiproxyPolicy
9+
10+
11+
class Fortiproxy(FortigateFirewall):
12+
"""Fortigate Firewall object.
13+
Representation of all firewall objects.
14+
15+
:param fortigateapi: Fortigate API object (:class:`fortilib.fortigateapi.FortigateFirewallApi`) for API Querys
16+
:ivar name: Name of fortigate firewall
17+
:ivar fortigate: Fortigate API object (:class:`fortilib.fortigateapi.FortigateFirewallApi`) for API Querys
18+
:ivar interfaces: List of :class:`fortilib.interface.FortigateInterface` (default: [])
19+
:ivar static_routes: List of :class:`fortilib.routes.FortigateStaticRoute` (default: [])
20+
:ivar addresses: List of :class:`fortilib.address.FortigateAddress` (default: [])
21+
:ivar address_groups: List of :class:`fortilib.addressgroup.FortigateAddressGroup` (default: [])
22+
:ivar vips: List of :class:`fortilib.vip.FortigateVIP` (default: [])
23+
:ivar vip_groups: List of :class:`fortilib.vipgroup.FortigateVIPGroup` (default: [])
24+
:ivar services: List of :class:`fortilib.service.FortigateService` (default: [])
25+
:ivar service_groups: List of :class:`fortilib.servicegroup.FortigateServiceGroup` (default: [])
26+
:ivar ippools: List of :class:`fortilib.ippool.FortigateIPPool` (default: [])
27+
:ivar policies: List of :class:`fortilib.policy.FortigatePolicy` (default: [])
28+
:ivar proxy_addresses: List of :class:`fortilib.proxyaddresses.FortigateProxyAddress` (default: [])
29+
:ivar proxy_address_groups: List of :class:`fortilib.proxyaddressgroup.FortigateProxyAddressGroup` (default: [])
30+
:ivar proxy_policies: None
31+
:ivar all_addresses: List of :class:`fortilib.proxyaddresses.FortigateProxyAddress` and :class:`fortilib.address.FortigateAddress` (default: [])
32+
:ivar phase1_interfaces: None
33+
:ivar phase2_interfaces: None
34+
"""
35+
36+
def __init__(self, name: str, fortigateapi: FortigateFirewallApi):
37+
super().__init__(name, fortigateapi)
38+
39+
self.policies: List[FortiproxyPolicy] = []
40+
41+
self.proxy_policies = None
42+
self.phase1_interfaces = None
43+
self.phase2_interfaces = None
44+
45+
def get_all_objects(self):
46+
"""Query Fortiproxy API for all firewall objects of the following list.
47+
48+
- Interfaces
49+
- Static Routes
50+
- Addresses
51+
- Address Groups
52+
- VIPs
53+
- VIP Groups
54+
- Services
55+
- Service Groups
56+
- IPPools
57+
- Policies
58+
- Proxy Addresses
59+
- Proxy Address Groups
60+
- Addresses and Proxy Addresses
61+
"""
62+
self.interfaces = self.get_interfaces()
63+
self.static_routes = self.get_static_routes()
64+
self.addresses = self.get_addresses()
65+
self.address_groups = self.get_address_groups()
66+
self.resolve_address_groups()
67+
self.proxy_addresses = self.get_proxy_addresses()
68+
self.proxy_address_groups = self.get_proxy_address_groups()
69+
self.resolve_proxy_address_groups()
70+
self.vips = self.get_vips()
71+
self.vip_groups = self.get_vip_groups()
72+
self.resolve_vip_groups()
73+
self.services = self.get_services()
74+
self.service_groups = self.get_service_groups()
75+
self.resolve_service_groups()
76+
self.ippools = self.get_ippools()
77+
self.policies = self.get_policies()
78+
self.all_addresses = self.get_all_addresses()
79+
80+
def get_policies(self) -> List[FortiproxyPolicy]:
81+
"""Query Fortiproxy API for policies
82+
:obj:`fortilib.policy.FortigatePolicy` and create list.
83+
"""
84+
policies: List[FortiproxyPolicy] = []
85+
for raw in self.fortigate.get_firewall_policies():
86+
policy = FortiproxyPolicy.from_dict(raw)
87+
88+
policy.find_interfaces(self.interfaces)
89+
policy.find_addresses(
90+
[
91+
self.addresses,
92+
self.address_groups,
93+
self.vips,
94+
self.vip_groups,
95+
self.proxy_addresses,
96+
self.proxy_address_groups,
97+
]
98+
)
99+
policy.find_services([self.services, self.service_groups])
100+
101+
policies.append(policy)
102+
103+
return policies
104+
105+
def create_firewall_policy(self, policy: FortiproxyPolicy):
106+
"""Create policy on fortigate with given :obj:`fortilib.proxypolicy.FortiproxyPolicy`."""
107+
status = self.fortigate.create_firewall_policy(
108+
int(policy.policyid), policy.render()
109+
)
110+
111+
policy.policyid = status["mkey"]
112+
113+
self.policies.append(policy)
114+
return status
115+
116+
def update_firewall_policy(self, policy: FortiproxyPolicy):
117+
"""Update policy on fortiproxy with given :obj:`fortilib.proxypolicy.FortiproxyPolicy`."""
118+
return self.fortigate.update_firewall_policy(
119+
policy.policyid, policy.render()
120+
)
121+
122+
def delete_firewall_policy(self, policy: FortiproxyPolicy):
123+
"""Delete policy on fortiproxy with given :obj:`fortilib.proxypolicy.FortiproxyPolicy`."""
124+
status = self.fortigate.delete_firewall_policy(policy.policyid)
125+
self.policies.remove(policy)
126+
return status
127+
128+
def move_firewall_policy(
129+
self,
130+
policy: FortiproxyPolicy,
131+
move_direction: FortiGateApiPolicyDirection,
132+
move_identifier_policy: FortiproxyPolicy,
133+
):
134+
"""move policy on fortiproxy to another position with given :obj:`fortilib.proxypolicy.FortiproxyPolicy`, :obj:`fortilib.fortigateapi.FortiGateApiPolicyDirection` and :obj:`fortilib.policy.FortigatePolicy`."""
135+
136+
return self.fortigate.move_firewall_policy(
137+
policy.policyid,
138+
move_direction,
139+
move_identifier_policy.policyid,
140+
)
141+
142+
def get_proxy_policies(self):
143+
raise AttributeError(
144+
f"{Fortiproxy} has no Method {self.get_proxy_policies.__name__}",
145+
obj=Fortiproxy,
146+
name=f"{self.get_proxy_policies.__name__}",
147+
)
148+
149+
def update_firewall_proxy_policy(self):
150+
raise AttributeError(
151+
f"{Fortiproxy} has no Method {self.update_firewall_proxy_policy.__name__}",
152+
obj=Fortiproxy,
153+
name=f"{self.update_firewall_proxy_policy.__name__}",
154+
)
155+
156+
def delete_firewall_proxy_policy(self):
157+
raise AttributeError(
158+
f"{Fortiproxy} has no Method {self.delete_firewall_proxy_policy.__name__}",
159+
obj=Fortiproxy,
160+
name=f"{self.delete_firewall_proxy_policy.__name__}",
161+
)
162+
163+
def move_firewall_proxy_policy(self):
164+
raise AttributeError(
165+
f"{Fortiproxy} has no Method {self.move_firewall_proxy_policy.__name__}",
166+
obj=Fortiproxy,
167+
name=f"{self.move_firewall_proxy_policy.__name__}",
168+
)
169+
170+
def get_phase1_interfaces(self):
171+
raise AttributeError(
172+
f"{Fortiproxy} has no Method {self.get_phase1_interfaces.__name__}",
173+
obj=Fortiproxy,
174+
name=f"{self.get_phase1_interfaces.__name__}",
175+
)
176+
177+
def create_firewall_phase1_interface(self):
178+
raise AttributeError(
179+
f"{Fortiproxy} has no Method {self.create_firewall_phase1_interface.__name__}",
180+
obj=Fortiproxy,
181+
name=f"{self.create_firewall_phase1_interface.__name__}",
182+
)
183+
184+
def update_firewall_phase1_interface(self):
185+
raise AttributeError(
186+
f"{Fortiproxy} has no Method {self.update_firewall_phase1_interface.__name__}",
187+
obj=Fortiproxy,
188+
name=f"{self.update_firewall_phase1_interface.__name__}",
189+
)
190+
191+
def delete_firewall_phase1_interface(self):
192+
raise AttributeError(
193+
f"{Fortiproxy} has no Method {self.delete_firewall_phase1_interface.__name__}",
194+
obj=Fortiproxy,
195+
name=f"{self.delete_firewall_phase1_interface.__name__}",
196+
)
197+
198+
def get_phase2_interfaces(self):
199+
raise AttributeError(
200+
f"{Fortiproxy} has no Method {self.get_phase2_interfaces.__name__}",
201+
obj=Fortiproxy,
202+
name=f"{self.get_phase2_interfaces.__name__}",
203+
)
204+
205+
def create_firewall_phase2_interface(self):
206+
raise AttributeError(
207+
f"{Fortiproxy} has no Method {self.create_firewall_phase2_interface.__name__}",
208+
obj=Fortiproxy,
209+
name=f"{self.create_firewall_phase2_interface.__name__}",
210+
)
211+
212+
def update_firewall_phase2_interface(self):
213+
raise AttributeError(
214+
f"{Fortiproxy} has no Method {self.update_firewall_phase2_interface.__name__}",
215+
obj=Fortiproxy,
216+
name=f"{self.update_firewall_phase2_interface.__name__}",
217+
)
218+
219+
def delete_firewall_phase2_interface(self):
220+
raise AttributeError(
221+
f"{Fortiproxy} has no Method {self.delete_firewall_phase2_interface.__name__}",
222+
obj=Fortiproxy,
223+
name=f"{self.delete_firewall_phase2_interface.__name__}",
224+
)

fortilib/proxypolicy.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,48 @@ def render(self) -> dict:
295295
"profile-group": self.profile_group,
296296
"comments": self.comment,
297297
}
298+
299+
300+
class FortiproxyPolicy(FortigateProxyPolicy):
301+
def __init__(self):
302+
super().__init__()
303+
304+
self.proxy = None
305+
self.type = "transparent"
306+
307+
def populate(self, object_data: dict):
308+
super().populate(object_data)
309+
310+
self.policyid = object_data.get("policyid", self.policyid)
311+
self.action = object_data.get("action", self.action)
312+
self.status = object_data.get("status", self.status)
313+
314+
self.schedule = object_data.get("schedule", self.schedule)
315+
self.type = object_data.get("type", self.type)
316+
self.logtraffic = object_data.get("logtraffic", self.logtraffic)
317+
self.utm_status = object_data.get("utm-status", self.utm_status)
318+
self.profile_type = object_data.get("profile-type", self.profile_type)
319+
self.profile_group = object_data.get(
320+
"profile-group", self.profile_group
321+
)
322+
self.comment = object_data.get("comments", self.comment)
323+
324+
def render(self) -> dict:
325+
return {
326+
"policyid": self.policyid,
327+
"name": self.name,
328+
"type": self.type,
329+
"srcintf": get_fortigate_member_array(self.srcintf),
330+
"dstintf": get_fortigate_member_array(self.dstintf),
331+
"srcaddr": get_fortigate_member_array(self.srcaddr),
332+
"dstaddr": get_fortigate_member_array(self.dstaddr),
333+
"service": get_fortigate_member_array(self.service),
334+
"action": self.action,
335+
"status": self.status,
336+
"schedule": self.schedule,
337+
"logtraffic": self.logtraffic,
338+
"utm-status": self.utm_status,
339+
"profile-type": self.profile_type,
340+
"profile-group": self.profile_group,
341+
"comments": self.comment,
342+
}

0 commit comments

Comments
 (0)