1#!/usr/local/bin/python3.8 2from __future__ import (absolute_import, division, print_function) 3# Copyright 2019-2020 Fortinet, Inc. 4# 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18__metaclass__ = type 19 20ANSIBLE_METADATA = {'status': ['preview'], 21 'supported_by': 'community', 22 'metadata_version': '1.1'} 23 24DOCUMENTATION = ''' 25--- 26module: fortios_ips_settings 27short_description: Configure IPS VDOM parameter in Fortinet's FortiOS and FortiGate. 28description: 29 - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the 30 user to set and modify ips feature and settings category. 31 Examples include all parameters and values need to be adjusted to datasources before usage. 32 Tested with FOS v6.0.0 33version_added: "2.10" 34author: 35 - Link Zheng (@chillancezen) 36 - Jie Xue (@JieX19) 37 - Hongbin Lu (@fgtdev-hblu) 38 - Frank Shen (@frankshen01) 39 - Miguel Angel Munoz (@mamunozgonzalez) 40 - Nicolas Thomas (@thomnico) 41notes: 42 - Legacy fortiosapi has been deprecated, httpapi is the preferred way to run playbooks 43 44requirements: 45 - ansible>=2.9.0 46options: 47 access_token: 48 description: 49 - Token-based authentication. 50 Generated from GUI of Fortigate. 51 type: str 52 required: false 53 enable_log: 54 description: 55 - Enable/Disable logging for task. 56 type: bool 57 required: false 58 default: false 59 vdom: 60 description: 61 - Virtual domain, among those defined previously. A vdom is a 62 virtual instance of the FortiGate that can be configured and 63 used as a different unit. 64 type: str 65 default: root 66 67 ips_settings: 68 description: 69 - Configure IPS VDOM parameter. 70 default: null 71 type: dict 72 suboptions: 73 ips_packet_quota: 74 description: 75 - Maximum amount of disk space in MB for logged packets when logging to disk. Range depends on disk size. 76 type: int 77 packet_log_history: 78 description: 79 - Number of packets to capture before and including the one in which the IPS signature is detected (1 - 255). 80 type: int 81 packet_log_memory: 82 description: 83 - Maximum memory can be used by packet log (64 - 8192 kB). 84 type: int 85 packet_log_post_attack: 86 description: 87 - Number of packets to log after the IPS signature is detected (0 - 255). 88 type: int 89''' 90 91EXAMPLES = ''' 92- hosts: fortigates 93 collections: 94 - fortinet.fortios 95 connection: httpapi 96 vars: 97 vdom: "root" 98 ansible_httpapi_use_ssl: yes 99 ansible_httpapi_validate_certs: no 100 ansible_httpapi_port: 443 101 tasks: 102 - name: Configure IPS VDOM parameter. 103 fortios_ips_settings: 104 vdom: "{{ vdom }}" 105 ips_settings: 106 ips_packet_quota: "3" 107 packet_log_history: "4" 108 packet_log_memory: "5" 109 packet_log_post_attack: "6" 110 111''' 112 113RETURN = ''' 114build: 115 description: Build number of the fortigate image 116 returned: always 117 type: str 118 sample: '1547' 119http_method: 120 description: Last method used to provision the content into FortiGate 121 returned: always 122 type: str 123 sample: 'PUT' 124http_status: 125 description: Last result given by FortiGate on last operation applied 126 returned: always 127 type: str 128 sample: "200" 129mkey: 130 description: Master key (id) used in the last call to FortiGate 131 returned: success 132 type: str 133 sample: "id" 134name: 135 description: Name of the table used to fulfill the request 136 returned: always 137 type: str 138 sample: "urlfilter" 139path: 140 description: Path of the table used to fulfill the request 141 returned: always 142 type: str 143 sample: "webfilter" 144revision: 145 description: Internal revision number 146 returned: always 147 type: str 148 sample: "17.0.2.10658" 149serial: 150 description: Serial number of the unit 151 returned: always 152 type: str 153 sample: "FGVMEVYYQT3AB5352" 154status: 155 description: Indication of the operation's result 156 returned: always 157 type: str 158 sample: "success" 159vdom: 160 description: Virtual domain used 161 returned: always 162 type: str 163 sample: "root" 164version: 165 description: Version of the FortiGate 166 returned: always 167 type: str 168 sample: "v5.6.3" 169 170''' 171from ansible.module_utils.basic import AnsibleModule 172from ansible.module_utils.connection import Connection 173from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler 174from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi 175from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec 176from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning 177from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG 178from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison 179from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize 180 181 182def filter_ips_settings_data(json): 183 option_list = ['ips_packet_quota', 'packet_log_history', 'packet_log_memory', 184 'packet_log_post_attack'] 185 dictionary = {} 186 187 for attribute in option_list: 188 if attribute in json and json[attribute] is not None: 189 dictionary[attribute] = json[attribute] 190 191 return dictionary 192 193 194def underscore_to_hyphen(data): 195 if isinstance(data, list): 196 for i, elem in enumerate(data): 197 data[i] = underscore_to_hyphen(elem) 198 elif isinstance(data, dict): 199 new_data = {} 200 for k, v in data.items(): 201 new_data[k.replace('_', '-')] = underscore_to_hyphen(v) 202 data = new_data 203 204 return data 205 206 207def ips_settings(data, fos): 208 vdom = data['vdom'] 209 ips_settings_data = data['ips_settings'] 210 filtered_data = underscore_to_hyphen(filter_ips_settings_data(ips_settings_data)) 211 212 return fos.set('ips', 213 'settings', 214 data=filtered_data, 215 vdom=vdom) 216 217 218def is_successful_status(status): 219 return status['status'] == "success" or \ 220 status['http_method'] == "DELETE" and status['http_status'] == 404 221 222 223def fortios_ips(data, fos): 224 225 if data['ips_settings']: 226 resp = ips_settings(data, fos) 227 else: 228 fos._module.fail_json(msg='missing task body: %s' % ('ips_settings')) 229 230 return not is_successful_status(resp), \ 231 resp['status'] == "success" and \ 232 (resp['revision_changed'] if 'revision_changed' in resp else True), \ 233 resp 234 235 236versioned_schema = { 237 "type": "dict", 238 "children": { 239 "ips_packet_quota": { 240 "type": "integer", 241 "revisions": { 242 "v6.0.0": True, 243 "v7.0.0": True, 244 "v6.0.5": True, 245 "v6.4.4": True, 246 "v6.4.0": True, 247 "v6.4.1": True, 248 "v6.2.0": True, 249 "v6.2.3": True, 250 "v6.2.5": True, 251 "v6.2.7": True, 252 "v6.0.11": True 253 } 254 }, 255 "packet_log_history": { 256 "type": "integer", 257 "revisions": { 258 "v6.0.0": True, 259 "v7.0.0": True, 260 "v6.0.5": True, 261 "v6.4.4": True, 262 "v6.4.0": True, 263 "v6.4.1": True, 264 "v6.2.0": True, 265 "v6.2.3": True, 266 "v6.2.5": True, 267 "v6.2.7": True, 268 "v6.0.11": True 269 } 270 }, 271 "packet_log_post_attack": { 272 "type": "integer", 273 "revisions": { 274 "v6.0.0": True, 275 "v7.0.0": True, 276 "v6.0.5": True, 277 "v6.4.4": True, 278 "v6.4.0": True, 279 "v6.4.1": True, 280 "v6.2.0": True, 281 "v6.2.3": True, 282 "v6.2.5": True, 283 "v6.2.7": True, 284 "v6.0.11": True 285 } 286 }, 287 "packet_log_memory": { 288 "type": "integer", 289 "revisions": { 290 "v6.0.0": True, 291 "v7.0.0": True, 292 "v6.0.5": True, 293 "v6.4.4": True, 294 "v6.4.0": True, 295 "v6.4.1": True, 296 "v6.2.0": True, 297 "v6.2.3": True, 298 "v6.2.5": True, 299 "v6.2.7": True, 300 "v6.0.11": True 301 } 302 } 303 }, 304 "revisions": { 305 "v6.0.0": True, 306 "v7.0.0": True, 307 "v6.0.5": True, 308 "v6.4.4": True, 309 "v6.4.0": True, 310 "v6.4.1": True, 311 "v6.2.0": True, 312 "v6.2.3": True, 313 "v6.2.5": True, 314 "v6.2.7": True, 315 "v6.0.11": True 316 } 317} 318 319 320def main(): 321 module_spec = schema_to_module_spec(versioned_schema) 322 mkeyname = None 323 fields = { 324 "access_token": {"required": False, "type": "str", "no_log": True}, 325 "enable_log": {"required": False, "type": bool}, 326 "vdom": {"required": False, "type": "str", "default": "root"}, 327 "ips_settings": { 328 "required": False, "type": "dict", "default": None, 329 "options": { 330 } 331 } 332 } 333 for attribute_name in module_spec['options']: 334 fields["ips_settings"]['options'][attribute_name] = module_spec['options'][attribute_name] 335 if mkeyname and mkeyname == attribute_name: 336 fields["ips_settings"]['options'][attribute_name]['required'] = True 337 338 check_legacy_fortiosapi() 339 module = AnsibleModule(argument_spec=fields, 340 supports_check_mode=False) 341 342 versions_check_result = None 343 if module._socket_path: 344 connection = Connection(module._socket_path) 345 if 'access_token' in module.params: 346 connection.set_option('access_token', module.params['access_token']) 347 348 if 'enable_log' in module.params: 349 connection.set_option('enable_log', module.params['enable_log']) 350 else: 351 connection.set_option('enable_log', False) 352 fos = FortiOSHandler(connection, module, mkeyname) 353 versions_check_result = check_schema_versioning(fos, versioned_schema, "ips_settings") 354 355 is_error, has_changed, result = fortios_ips(module.params, fos) 356 357 else: 358 module.fail_json(**FAIL_SOCKET_MSG) 359 360 if versions_check_result and versions_check_result['matched'] is False: 361 module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv") 362 363 if not is_error: 364 if versions_check_result and versions_check_result['matched'] is False: 365 module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result) 366 else: 367 module.exit_json(changed=has_changed, meta=result) 368 else: 369 if versions_check_result and versions_check_result['matched'] is False: 370 module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result) 371 else: 372 module.fail_json(msg="Error in repo", meta=result) 373 374 375if __name__ == '__main__': 376 main() 377