1#!/usr/bin/python 2from __future__ import (absolute_import, division, print_function) 3# Copyright 2019 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_firewall_dnstranslation 27short_description: Configure DNS translation 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 firewall feature and dnstranslation category. 31 Examples include all parameters and values need to be adjusted to datasources before usage. 32 Tested with FOS v6.0.5 33version_added: "2.8" 34author: 35 - Miguel Angel Munoz (@mamunozgonzalez) 36 - Nicolas Thomas (@thomnico) 37notes: 38 - Requires fortiosapi library developed by Fortinet 39 - Run as a local_action in your playbook 40requirements: 41 - fortiosapi>=0.9.8 42options: 43 host: 44 description: 45 - FortiOS or FortiGate IP address. 46 type: str 47 required: false 48 username: 49 description: 50 - FortiOS or FortiGate username. 51 type: str 52 required: false 53 password: 54 description: 55 - FortiOS or FortiGate password. 56 type: str 57 default: "" 58 vdom: 59 description: 60 - Virtual domain, among those defined previously. A vdom is a 61 virtual instance of the FortiGate that can be configured and 62 used as a different unit. 63 type: str 64 default: root 65 https: 66 description: 67 - Indicates if the requests towards FortiGate must use HTTPS protocol. 68 type: bool 69 default: true 70 ssl_verify: 71 description: 72 - Ensures FortiGate certificate must be verified by a proper CA. 73 type: bool 74 default: true 75 version_added: 2.9 76 state: 77 description: 78 - Indicates whether to create or remove the object. 79 This attribute was present already in previous version in a deeper level. 80 It has been moved out to this outer level. 81 type: str 82 required: false 83 choices: 84 - present 85 - absent 86 version_added: 2.9 87 firewall_dnstranslation: 88 description: 89 - Configure DNS translation. 90 default: null 91 type: dict 92 suboptions: 93 state: 94 description: 95 - B(Deprecated) 96 - Starting with Ansible 2.9 we recommend using the top-level 'state' parameter. 97 - HORIZONTALLINE 98 - Indicates whether to create or remove the object. 99 type: str 100 required: false 101 choices: 102 - present 103 - absent 104 dst: 105 description: 106 - IPv4 address or subnet on the external network to substitute for the resolved address in DNS query replies. Can be single IP address or 107 subnet on the external network, but number of addresses must equal number of mapped IP addresses in src. 108 type: str 109 id: 110 description: 111 - ID. 112 required: true 113 type: int 114 netmask: 115 description: 116 - If src and dst are subnets rather than single IP addresses, enter the netmask for both src and dst. 117 type: str 118 src: 119 description: 120 - IPv4 address or subnet on the internal network to compare with the resolved address in DNS query replies. If the resolved address 121 matches, the resolved address is substituted with dst. 122 type: str 123''' 124 125EXAMPLES = ''' 126- hosts: localhost 127 vars: 128 host: "192.168.122.40" 129 username: "admin" 130 password: "" 131 vdom: "root" 132 ssl_verify: "False" 133 tasks: 134 - name: Configure DNS translation. 135 fortios_firewall_dnstranslation: 136 host: "{{ host }}" 137 username: "{{ username }}" 138 password: "{{ password }}" 139 vdom: "{{ vdom }}" 140 https: "False" 141 state: "present" 142 firewall_dnstranslation: 143 dst: "<your_own_value>" 144 id: "4" 145 netmask: "<your_own_value>" 146 src: "<your_own_value>" 147''' 148 149RETURN = ''' 150build: 151 description: Build number of the fortigate image 152 returned: always 153 type: str 154 sample: '1547' 155http_method: 156 description: Last method used to provision the content into FortiGate 157 returned: always 158 type: str 159 sample: 'PUT' 160http_status: 161 description: Last result given by FortiGate on last operation applied 162 returned: always 163 type: str 164 sample: "200" 165mkey: 166 description: Master key (id) used in the last call to FortiGate 167 returned: success 168 type: str 169 sample: "id" 170name: 171 description: Name of the table used to fulfill the request 172 returned: always 173 type: str 174 sample: "urlfilter" 175path: 176 description: Path of the table used to fulfill the request 177 returned: always 178 type: str 179 sample: "webfilter" 180revision: 181 description: Internal revision number 182 returned: always 183 type: str 184 sample: "17.0.2.10658" 185serial: 186 description: Serial number of the unit 187 returned: always 188 type: str 189 sample: "FGVMEVYYQT3AB5352" 190status: 191 description: Indication of the operation's result 192 returned: always 193 type: str 194 sample: "success" 195vdom: 196 description: Virtual domain used 197 returned: always 198 type: str 199 sample: "root" 200version: 201 description: Version of the FortiGate 202 returned: always 203 type: str 204 sample: "v5.6.3" 205 206''' 207 208from ansible.module_utils.basic import AnsibleModule 209from ansible.module_utils.connection import Connection 210from ansible.module_utils.network.fortios.fortios import FortiOSHandler 211from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG 212 213 214def login(data, fos): 215 host = data['host'] 216 username = data['username'] 217 password = data['password'] 218 ssl_verify = data['ssl_verify'] 219 220 fos.debug('on') 221 if 'https' in data and not data['https']: 222 fos.https('off') 223 else: 224 fos.https('on') 225 226 fos.login(host, username, password, verify=ssl_verify) 227 228 229def filter_firewall_dnstranslation_data(json): 230 option_list = ['dst', 'id', 'netmask', 231 'src'] 232 dictionary = {} 233 234 for attribute in option_list: 235 if attribute in json and json[attribute] is not None: 236 dictionary[attribute] = json[attribute] 237 238 return dictionary 239 240 241def underscore_to_hyphen(data): 242 if isinstance(data, list): 243 for elem in data: 244 elem = underscore_to_hyphen(elem) 245 elif isinstance(data, dict): 246 new_data = {} 247 for k, v in data.items(): 248 new_data[k.replace('_', '-')] = underscore_to_hyphen(v) 249 data = new_data 250 251 return data 252 253 254def firewall_dnstranslation(data, fos): 255 vdom = data['vdom'] 256 if 'state' in data and data['state']: 257 state = data['state'] 258 elif 'state' in data['firewall_dnstranslation'] and data['firewall_dnstranslation']: 259 state = data['firewall_dnstranslation']['state'] 260 else: 261 state = True 262 firewall_dnstranslation_data = data['firewall_dnstranslation'] 263 filtered_data = underscore_to_hyphen(filter_firewall_dnstranslation_data(firewall_dnstranslation_data)) 264 265 if state == "present": 266 return fos.set('firewall', 267 'dnstranslation', 268 data=filtered_data, 269 vdom=vdom) 270 271 elif state == "absent": 272 return fos.delete('firewall', 273 'dnstranslation', 274 mkey=filtered_data['id'], 275 vdom=vdom) 276 277 278def is_successful_status(status): 279 return status['status'] == "success" or \ 280 status['http_method'] == "DELETE" and status['http_status'] == 404 281 282 283def fortios_firewall(data, fos): 284 285 if data['firewall_dnstranslation']: 286 resp = firewall_dnstranslation(data, fos) 287 288 return not is_successful_status(resp), \ 289 resp['status'] == "success", \ 290 resp 291 292 293def main(): 294 fields = { 295 "host": {"required": False, "type": "str"}, 296 "username": {"required": False, "type": "str"}, 297 "password": {"required": False, "type": "str", "default": "", "no_log": True}, 298 "vdom": {"required": False, "type": "str", "default": "root"}, 299 "https": {"required": False, "type": "bool", "default": True}, 300 "ssl_verify": {"required": False, "type": "bool", "default": True}, 301 "state": {"required": False, "type": "str", 302 "choices": ["present", "absent"]}, 303 "firewall_dnstranslation": { 304 "required": False, "type": "dict", "default": None, 305 "options": { 306 "state": {"required": False, "type": "str", 307 "choices": ["present", "absent"]}, 308 "dst": {"required": False, "type": "str"}, 309 "id": {"required": True, "type": "int"}, 310 "netmask": {"required": False, "type": "str"}, 311 "src": {"required": False, "type": "str"} 312 313 } 314 } 315 } 316 317 module = AnsibleModule(argument_spec=fields, 318 supports_check_mode=False) 319 320 # legacy_mode refers to using fortiosapi instead of HTTPAPI 321 legacy_mode = 'host' in module.params and module.params['host'] is not None and \ 322 'username' in module.params and module.params['username'] is not None and \ 323 'password' in module.params and module.params['password'] is not None 324 325 if not legacy_mode: 326 if module._socket_path: 327 connection = Connection(module._socket_path) 328 fos = FortiOSHandler(connection) 329 330 is_error, has_changed, result = fortios_firewall(module.params, fos) 331 else: 332 module.fail_json(**FAIL_SOCKET_MSG) 333 else: 334 try: 335 from fortiosapi import FortiOSAPI 336 except ImportError: 337 module.fail_json(msg="fortiosapi module is required") 338 339 fos = FortiOSAPI() 340 341 login(module.params, fos) 342 is_error, has_changed, result = fortios_firewall(module.params, fos) 343 fos.logout() 344 345 if not is_error: 346 module.exit_json(changed=has_changed, meta=result) 347 else: 348 module.fail_json(msg="Error in repo", meta=result) 349 350 351if __name__ == '__main__': 352 main() 353