Skip to content

Commit 076e937

Browse files
authored
Merge pull request CactuseSecurity#2869 from alf-cactus/develop
extend fortinet importer
2 parents cf752f7 + 6734b07 commit 076e937

File tree

4 files changed

+69
-9
lines changed

4 files changed

+69
-9
lines changed

roles/importer/files/importer/fortiadom5ff/fmgr_gw_networking.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ def normalize_network_data(native_config, normalized_config, mgm_details):
6262
normalized_config['routing'].sort(key=getRouteDestination,reverse=True)
6363

6464
for interface in native_config['interfaces_per_device/' + full_vdom_name]:
65-
if interface['ipv6']['ip6-address']!='::/0':
65+
if 'ipv6' in interface and 'ip6-address' in interface['ipv6'] and interface['ipv6']['ip6-address']!='::/0':
6666
ipv6, netmask_bits = interface['ipv6']['ip6-address'].split('/')
6767
normIfV6 = Interface(dev_id, interface['name'], IPAddress(ipv6), netmask_bits, ip_version=6)
6868
normalized_config['interfaces'].append(normIfV6)
6969

70-
if interface['ip']!=['0.0.0.0','0.0.0.0']:
70+
if 'ip' in interface and interface['ip']!=['0.0.0.0','0.0.0.0']:
7171
ipv4 = IPAddress(interface['ip'][0])
7272
netmask_bits = IPAddress(interface['ip'][1]).netmask_bits()
7373
normIfV4 = Interface(dev_id, interface['name'], ipv4, netmask_bits, ip_version=4)

roles/importer/files/importer/fortiadom5ff/fmgr_network.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,22 @@ def normalize_nwobjects(full_config, config2import, import_id, nw_obj_types, jwt
103103
obj.update({'control_id': import_id})
104104
nw_objects.append(obj)
105105

106+
# dynamic objects have different return structure
107+
if 'response' in full_config['nw_obj_global_firewall/internet-service-basic'][0] and 'results' in full_config['nw_obj_global_firewall/internet-service-basic'][0]['response']:
108+
for obj_orig in full_config['nw_obj_global_firewall/internet-service-basic'][0]['response']['results']:
109+
if 'name' in obj_orig and 'q_origin_key' in obj_orig:
110+
obj = {
111+
'obj_name': obj_orig['name'],
112+
'obj_typ': 'network',
113+
'obj_ip': '0.0.0.0/0',
114+
'obj_uid': 'q_origin_key_' + str(obj_orig['q_origin_key']),
115+
'control_id': import_id,
116+
'obj_zone': 'global'
117+
}
118+
nw_objects.append(obj)
119+
else:
120+
logger.warning("internet service objects return format broken")
121+
106122
# finally add "Original" network object for natting
107123
original_obj_name = 'Original'
108124
original_obj_uid = 'Original'
@@ -189,7 +205,11 @@ def get_first_ip_of_destination(obj_ref, config2import):
189205

190206
for obj in config2import['network_objects']:
191207
if 'obj_uid' in obj and obj['obj_uid']==obj_ref:
192-
return obj['obj_ip']
208+
if 'obj_type' in obj and obj['obj_type']=='group':
209+
if 'obj_member_refs' in obj and list_delimiter in obj['obj_member_refs']:
210+
return get_first_ip_of_destination(obj['obj_member_refs'].split(list_delimiter)[0], config2import)
211+
elif 'obj_ip' in obj:
212+
return obj['obj_ip']
193213
logger.warning('src nat behind interface: found no IP info for destination object ' + obj_ref)
194214
return None
195215

@@ -210,13 +230,14 @@ def resolve_raw_objects (obj_name_string_list, delimiter, obj_dict, name_key, ui
210230
if rule_type is not None:
211231
if obj_type == 'network':
212232
if 'v4' in rule_type and 'global' in rule_type:
213-
object_tables = [obj_dict['nw_obj_global_firewall/address'], obj_dict['nw_obj_global_firewall/addrgrp']]
233+
object_tables = [obj_dict['nw_obj_global_firewall/address'], obj_dict['nw_obj_global_firewall/addrgrp'], obj_dict['nw_obj_global_firewall/internet-service-basic'][0]['response']['results']]
214234
elif 'v6' in rule_type and 'global' in rule_type:
215235
object_tables = [obj_dict['nw_obj_global_firewall/address6'], obj_dict['nw_obj_global_firewall/addrgrp6']]
216236
elif 'v4' in rule_type and 'adom' in rule_type:
217237
object_tables = [obj_dict['nw_obj_adom_firewall/address'], obj_dict['nw_obj_adom_firewall/addrgrp'], \
218238
obj_dict['nw_obj_global_firewall/address'], obj_dict['nw_obj_global_firewall/addrgrp'], \
219-
obj_dict['nw_obj_adom_firewall/vip'] ]
239+
obj_dict['nw_obj_adom_firewall/vip'], obj_dict['nw_obj_adom_system/external-resource'], \
240+
obj_dict['nw_obj_global_firewall/internet-service-basic'][0]['response']['results'] ]
220241
elif 'v6' in rule_type and 'adom' in rule_type:
221242
object_tables = [obj_dict['nw_obj_adom_firewall/address6'], obj_dict['nw_obj_adom_firewall/addrgrp6'], \
222243
obj_dict['nw_obj_global_firewall/address6'], obj_dict['nw_obj_global_firewall/addrgrp6']]
@@ -235,7 +256,13 @@ def resolve_raw_objects (obj_name_string_list, delimiter, obj_dict, name_key, ui
235256
else:
236257
for obj in tab:
237258
if obj[name_key] == el:
238-
ref_list.append(obj[uid_key])
259+
if uid_key in obj:
260+
ref_list.append(obj[uid_key])
261+
# in case of internet-service-object we find no uid field, but custom q_origin_key_
262+
elif 'q_origin_key' in obj:
263+
ref_list.append('q_origin_key_' + str(obj['q_origin_key']))
264+
else:
265+
logger.error('found object without expected uid')
239266
break_flag = True
240267
found = True
241268
break

roles/importer/files/importer/fortiadom5ff/fmgr_rule.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ def normalize_access_rules(full_config, config2import, import_id, mgm_details={}
184184
rule['rule_svc'] = extend_string_list(rule['rule_svc'], rule_orig, 'service', list_delimiter, jwt=jwt, import_id=import_id)
185185
rule['rule_src'] = extend_string_list(rule['rule_src'], rule_orig, 'srcaddr6', list_delimiter, jwt=jwt, import_id=import_id)
186186
rule['rule_dst'] = extend_string_list(rule['rule_dst'], rule_orig, 'dstaddr6', list_delimiter, jwt=jwt, import_id=import_id)
187+
rule['rule_src'] = extend_string_list(rule['rule_src'], rule_orig, 'internet-service-src-name', list_delimiter, jwt=jwt, import_id=import_id)
187188

188189
if len(rule_orig['srcintf'])>0:
189190
src_obj_zone = fmgr_zone.add_zone_if_missing (config2import, rule_orig['srcintf'][0], import_id)
@@ -194,6 +195,8 @@ def normalize_access_rules(full_config, config2import, import_id, mgm_details={}
194195

195196
if 'srcaddr-negate' in rule_orig:
196197
rule.update({ 'rule_src_neg': rule_orig['srcaddr-negate']=='disable'})
198+
elif 'internet-service-src-negate' in rule_orig:
199+
rule.update({ 'rule_src_neg': rule_orig['internet-service-src-negate']=='disable'})
197200
if 'dstaddr-negate' in rule_orig:
198201
rule.update({ 'rule_dst_neg': rule_orig['dstaddr-negate']=='disable'})
199202
if 'service-negate' in rule_orig:
@@ -411,9 +414,9 @@ def handle_combined_nat_rule(rule, rule_orig, config2import, nat_rule_number, im
411414
if hideInterface is not None:
412415
obj_name = 'hide_IF_ip_' + str(hideInterface) + '_' + str(destination_interface_ip)
413416
obj_comment = 'FWO auto-generated dummy object for source nat'
414-
if type(ipaddress.ip_address(str(destination_interface_ip))) is ipaddress.IPv6Address:
417+
if destination_interface_ip is not None and type(ipaddress.ip_address(str(destination_interface_ip))) is ipaddress.IPv6Address:
415418
HideNatIp = str(destination_interface_ip) + '/128'
416-
elif type(ipaddress.ip_address(str(destination_interface_ip))) is ipaddress.IPv4Address:
419+
elif destination_interface_ip is not None and type(ipaddress.ip_address(str(destination_interface_ip))) is ipaddress.IPv4Address:
417420
HideNatIp = str(destination_interface_ip) + '/32'
418421
else:
419422
HideNatIp = '0.0.0.0/32'

roles/importer/files/importer/fortiadom5ff/fwcommon.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
scope = ['global', 'adom']
1616
nw_obj_types = ['firewall/address', 'firewall/address6', 'firewall/addrgrp',
17-
'firewall/addrgrp6', 'firewall/ippool', 'firewall/vip']
17+
'firewall/addrgrp6', 'firewall/ippool', 'firewall/vip', 'system/external-resource']
1818
svc_obj_types = ['application/list', 'application/group', 'application/categories',
1919
'application/custom', 'firewall/service/custom', 'firewall/service/group']
2020

@@ -107,6 +107,7 @@ def get_config(config2import, full_config, current_import_id, mgm_details, limit
107107

108108

109109
def getObjects(sid, fm_api_url, raw_config, adom_name, limit, scope, nw_obj_types, svc_obj_types):
110+
logger = getFwoLogger()
110111
# get those objects that exist globally and on adom level
111112
for s in scope:
112113
# get network objects:
@@ -137,6 +138,35 @@ def getObjects(sid, fm_api_url, raw_config, adom_name, limit, scope, nw_obj_type
137138
adom_scope = s
138139
fmgr_getter.update_config_with_fortinet_api_call(
139140
raw_config, sid, fm_api_url, "/pm/config/"+adom_scope+"/obj/" + object_type, "user_obj_" + s + "_" + object_type, limit=limit)
141+
142+
# get one arbitrary device and vdom to get dynamic objects
143+
# they are equal across all adoms, vdoms, devices
144+
devices = fmgr_getter.fortinet_api_call(sid, fm_api_url, '/dvmdb/adom/' + adom_name + '/device')
145+
if len(devices)>0 and 'name' in devices[0] and 'vdom' in devices[0] and 'name' in devices[0]['vdom'][0]:
146+
arbitraryDevice = devices[0]['name']
147+
arbitraryVdom = devices[0]['vdom'][0]['name']
148+
else:
149+
logger.error('no device or vdom info for adom: ' + adom_name)
150+
151+
# get dynamic objects
152+
payload = {
153+
'params': [
154+
{
155+
'data': {
156+
'action': 'get',
157+
'resource': '/api/v2/monitor/firewall/internet-service-basic?vdom=' + arbitraryVdom,
158+
'target': [
159+
'adom/' + adom_name + '/device/' + arbitraryDevice
160+
]
161+
}
162+
}
163+
]
164+
}
165+
fmgr_getter.update_config_with_fortinet_api_call(
166+
raw_config, sid, fm_api_url, "sys/proxy/json", "nw_obj_global_firewall/internet-service-basic", limit=limit, payload=payload, method='exec')
167+
168+
169+
140170

141171

142172
# def getZones(sid, fm_api_url, raw_config, adom_name, limit, debug_level):

0 commit comments

Comments
 (0)