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_firewall_ipv6_eh_filter
27short_description: Configure IPv6 extension header filter 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 ipv6_eh_filter 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    firewall_ipv6_eh_filter:
68        description:
69            - Configure IPv6 extension header filter.
70        default: null
71        type: dict
72        suboptions:
73            auth:
74                description:
75                    - Enable/disable blocking packets with the Authentication header .
76                type: str
77                choices:
78                    - enable
79                    - disable
80            dest_opt:
81                description:
82                    - Enable/disable blocking packets with Destination Options headers .
83                type: str
84                choices:
85                    - enable
86                    - disable
87            fragment:
88                description:
89                    - Enable/disable blocking packets with the Fragment header .
90                type: str
91                choices:
92                    - enable
93                    - disable
94            hdopt_type:
95                description:
96                    - Block specific Hop-by-Hop and/or Destination Option types (max. 7 types, each between 0 and 255).
97                type: int
98            hop_opt:
99                description:
100                    - Enable/disable blocking packets with the Hop-by-Hop Options header .
101                type: str
102                choices:
103                    - enable
104                    - disable
105            no_next:
106                description:
107                    - Enable/disable blocking packets with the No Next header
108                type: str
109                choices:
110                    - enable
111                    - disable
112            routing:
113                description:
114                    - Enable/disable blocking packets with Routing headers .
115                type: str
116                choices:
117                    - enable
118                    - disable
119            routing_type:
120                description:
121                    - Block specific Routing header types (max. 7 types, each between 0 and 255).
122                type: int
123'''
124
125EXAMPLES = '''
126- hosts: fortigates
127  collections:
128    - fortinet.fortios
129  connection: httpapi
130  vars:
131   vdom: "root"
132   ansible_httpapi_use_ssl: yes
133   ansible_httpapi_validate_certs: no
134   ansible_httpapi_port: 443
135  tasks:
136  - name: Configure IPv6 extension header filter.
137    fortios_firewall_ipv6_eh_filter:
138      vdom:  "{{ vdom }}"
139      firewall_ipv6_eh_filter:
140        auth: "enable"
141        dest_opt: "enable"
142        fragment: "enable"
143        hdopt_type: "6"
144        hop_opt: "enable"
145        no_next: "enable"
146        routing: "enable"
147        routing_type: "10"
148
149'''
150
151RETURN = '''
152build:
153  description: Build number of the fortigate image
154  returned: always
155  type: str
156  sample: '1547'
157http_method:
158  description: Last method used to provision the content into FortiGate
159  returned: always
160  type: str
161  sample: 'PUT'
162http_status:
163  description: Last result given by FortiGate on last operation applied
164  returned: always
165  type: str
166  sample: "200"
167mkey:
168  description: Master key (id) used in the last call to FortiGate
169  returned: success
170  type: str
171  sample: "id"
172name:
173  description: Name of the table used to fulfill the request
174  returned: always
175  type: str
176  sample: "urlfilter"
177path:
178  description: Path of the table used to fulfill the request
179  returned: always
180  type: str
181  sample: "webfilter"
182revision:
183  description: Internal revision number
184  returned: always
185  type: str
186  sample: "17.0.2.10658"
187serial:
188  description: Serial number of the unit
189  returned: always
190  type: str
191  sample: "FGVMEVYYQT3AB5352"
192status:
193  description: Indication of the operation's result
194  returned: always
195  type: str
196  sample: "success"
197vdom:
198  description: Virtual domain used
199  returned: always
200  type: str
201  sample: "root"
202version:
203  description: Version of the FortiGate
204  returned: always
205  type: str
206  sample: "v5.6.3"
207
208'''
209from ansible.module_utils.basic import AnsibleModule
210from ansible.module_utils.connection import Connection
211from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler
212from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi
213from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec
214from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning
215from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
216from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison
217from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize
218
219
220def filter_firewall_ipv6_eh_filter_data(json):
221    option_list = ['auth', 'dest_opt', 'fragment',
222                   'hdopt_type', 'hop_opt', 'no_next',
223                   'routing', 'routing_type']
224    dictionary = {}
225
226    for attribute in option_list:
227        if attribute in json and json[attribute] is not None:
228            dictionary[attribute] = json[attribute]
229
230    return dictionary
231
232
233def underscore_to_hyphen(data):
234    if isinstance(data, list):
235        for i, elem in enumerate(data):
236            data[i] = underscore_to_hyphen(elem)
237    elif isinstance(data, dict):
238        new_data = {}
239        for k, v in data.items():
240            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
241        data = new_data
242
243    return data
244
245
246def firewall_ipv6_eh_filter(data, fos):
247    vdom = data['vdom']
248    firewall_ipv6_eh_filter_data = data['firewall_ipv6_eh_filter']
249    filtered_data = underscore_to_hyphen(filter_firewall_ipv6_eh_filter_data(firewall_ipv6_eh_filter_data))
250
251    return fos.set('firewall',
252                   'ipv6-eh-filter',
253                   data=filtered_data,
254                   vdom=vdom)
255
256
257def is_successful_status(status):
258    return status['status'] == "success" or \
259        status['http_method'] == "DELETE" and status['http_status'] == 404
260
261
262def fortios_firewall(data, fos):
263
264    if data['firewall_ipv6_eh_filter']:
265        resp = firewall_ipv6_eh_filter(data, fos)
266    else:
267        fos._module.fail_json(msg='missing task body: %s' % ('firewall_ipv6_eh_filter'))
268
269    return not is_successful_status(resp), \
270        resp['status'] == "success" and \
271        (resp['revision_changed'] if 'revision_changed' in resp else True), \
272        resp
273
274
275versioned_schema = {
276    "type": "dict",
277    "children": {
278        "dest_opt": {
279            "type": "string",
280            "options": [
281                {
282                    "value": "enable",
283                    "revisions": {
284                        "v6.0.0": True,
285                        "v7.0.0": True,
286                        "v6.0.5": True,
287                        "v6.4.4": True,
288                        "v6.4.0": True,
289                        "v6.4.1": True,
290                        "v6.2.0": True,
291                        "v6.2.3": True,
292                        "v6.2.5": True,
293                        "v6.2.7": True,
294                        "v6.0.11": True
295                    }
296                },
297                {
298                    "value": "disable",
299                    "revisions": {
300                        "v6.0.0": True,
301                        "v7.0.0": True,
302                        "v6.0.5": True,
303                        "v6.4.4": True,
304                        "v6.4.0": True,
305                        "v6.4.1": True,
306                        "v6.2.0": True,
307                        "v6.2.3": True,
308                        "v6.2.5": True,
309                        "v6.2.7": True,
310                        "v6.0.11": True
311                    }
312                }
313            ],
314            "revisions": {
315                "v6.0.0": True,
316                "v7.0.0": True,
317                "v6.0.5": True,
318                "v6.4.4": True,
319                "v6.4.0": True,
320                "v6.4.1": True,
321                "v6.2.0": True,
322                "v6.2.3": True,
323                "v6.2.5": True,
324                "v6.2.7": True,
325                "v6.0.11": True
326            }
327        },
328        "hop_opt": {
329            "type": "string",
330            "options": [
331                {
332                    "value": "enable",
333                    "revisions": {
334                        "v6.0.0": True,
335                        "v7.0.0": True,
336                        "v6.0.5": True,
337                        "v6.4.4": True,
338                        "v6.4.0": True,
339                        "v6.4.1": True,
340                        "v6.2.0": True,
341                        "v6.2.3": True,
342                        "v6.2.5": True,
343                        "v6.2.7": True,
344                        "v6.0.11": True
345                    }
346                },
347                {
348                    "value": "disable",
349                    "revisions": {
350                        "v6.0.0": True,
351                        "v7.0.0": True,
352                        "v6.0.5": True,
353                        "v6.4.4": True,
354                        "v6.4.0": True,
355                        "v6.4.1": True,
356                        "v6.2.0": True,
357                        "v6.2.3": True,
358                        "v6.2.5": True,
359                        "v6.2.7": True,
360                        "v6.0.11": True
361                    }
362                }
363            ],
364            "revisions": {
365                "v6.0.0": True,
366                "v7.0.0": True,
367                "v6.0.5": True,
368                "v6.4.4": True,
369                "v6.4.0": True,
370                "v6.4.1": True,
371                "v6.2.0": True,
372                "v6.2.3": True,
373                "v6.2.5": True,
374                "v6.2.7": True,
375                "v6.0.11": True
376            }
377        },
378        "fragment": {
379            "type": "string",
380            "options": [
381                {
382                    "value": "enable",
383                    "revisions": {
384                        "v6.0.0": True,
385                        "v7.0.0": True,
386                        "v6.0.5": True,
387                        "v6.4.4": True,
388                        "v6.4.0": True,
389                        "v6.4.1": True,
390                        "v6.2.0": True,
391                        "v6.2.3": True,
392                        "v6.2.5": True,
393                        "v6.2.7": True,
394                        "v6.0.11": True
395                    }
396                },
397                {
398                    "value": "disable",
399                    "revisions": {
400                        "v6.0.0": True,
401                        "v7.0.0": True,
402                        "v6.0.5": True,
403                        "v6.4.4": True,
404                        "v6.4.0": True,
405                        "v6.4.1": True,
406                        "v6.2.0": True,
407                        "v6.2.3": True,
408                        "v6.2.5": True,
409                        "v6.2.7": True,
410                        "v6.0.11": True
411                    }
412                }
413            ],
414            "revisions": {
415                "v6.0.0": True,
416                "v7.0.0": True,
417                "v6.0.5": True,
418                "v6.4.4": True,
419                "v6.4.0": True,
420                "v6.4.1": True,
421                "v6.2.0": True,
422                "v6.2.3": True,
423                "v6.2.5": True,
424                "v6.2.7": True,
425                "v6.0.11": True
426            }
427        },
428        "routing_type": {
429            "type": "integer",
430            "revisions": {
431                "v6.0.0": True,
432                "v7.0.0": True,
433                "v6.0.5": True,
434                "v6.4.4": True,
435                "v6.4.0": True,
436                "v6.4.1": True,
437                "v6.2.0": True,
438                "v6.2.3": True,
439                "v6.2.5": True,
440                "v6.2.7": True,
441                "v6.0.11": True
442            }
443        },
444        "auth": {
445            "type": "string",
446            "options": [
447                {
448                    "value": "enable",
449                    "revisions": {
450                        "v6.0.0": True,
451                        "v7.0.0": True,
452                        "v6.0.5": True,
453                        "v6.4.4": True,
454                        "v6.4.0": True,
455                        "v6.4.1": True,
456                        "v6.2.0": True,
457                        "v6.2.3": True,
458                        "v6.2.5": True,
459                        "v6.2.7": True,
460                        "v6.0.11": True
461                    }
462                },
463                {
464                    "value": "disable",
465                    "revisions": {
466                        "v6.0.0": True,
467                        "v7.0.0": True,
468                        "v6.0.5": True,
469                        "v6.4.4": True,
470                        "v6.4.0": True,
471                        "v6.4.1": True,
472                        "v6.2.0": True,
473                        "v6.2.3": True,
474                        "v6.2.5": True,
475                        "v6.2.7": True,
476                        "v6.0.11": True
477                    }
478                }
479            ],
480            "revisions": {
481                "v6.0.0": True,
482                "v7.0.0": True,
483                "v6.0.5": True,
484                "v6.4.4": True,
485                "v6.4.0": True,
486                "v6.4.1": True,
487                "v6.2.0": True,
488                "v6.2.3": True,
489                "v6.2.5": True,
490                "v6.2.7": True,
491                "v6.0.11": True
492            }
493        },
494        "hdopt_type": {
495            "type": "integer",
496            "revisions": {
497                "v6.0.0": True,
498                "v7.0.0": True,
499                "v6.0.5": True,
500                "v6.4.4": True,
501                "v6.4.0": True,
502                "v6.4.1": True,
503                "v6.2.0": True,
504                "v6.2.3": True,
505                "v6.2.5": True,
506                "v6.2.7": True,
507                "v6.0.11": True
508            }
509        },
510        "routing": {
511            "type": "string",
512            "options": [
513                {
514                    "value": "enable",
515                    "revisions": {
516                        "v6.0.0": True,
517                        "v7.0.0": True,
518                        "v6.0.5": True,
519                        "v6.4.4": True,
520                        "v6.4.0": True,
521                        "v6.4.1": True,
522                        "v6.2.0": True,
523                        "v6.2.3": True,
524                        "v6.2.5": True,
525                        "v6.2.7": True,
526                        "v6.0.11": True
527                    }
528                },
529                {
530                    "value": "disable",
531                    "revisions": {
532                        "v6.0.0": True,
533                        "v7.0.0": True,
534                        "v6.0.5": True,
535                        "v6.4.4": True,
536                        "v6.4.0": True,
537                        "v6.4.1": True,
538                        "v6.2.0": True,
539                        "v6.2.3": True,
540                        "v6.2.5": True,
541                        "v6.2.7": True,
542                        "v6.0.11": True
543                    }
544                }
545            ],
546            "revisions": {
547                "v6.0.0": True,
548                "v7.0.0": True,
549                "v6.0.5": True,
550                "v6.4.4": True,
551                "v6.4.0": True,
552                "v6.4.1": True,
553                "v6.2.0": True,
554                "v6.2.3": True,
555                "v6.2.5": True,
556                "v6.2.7": True,
557                "v6.0.11": True
558            }
559        },
560        "no_next": {
561            "type": "string",
562            "options": [
563                {
564                    "value": "enable",
565                    "revisions": {
566                        "v6.0.0": True,
567                        "v7.0.0": True,
568                        "v6.0.5": True,
569                        "v6.4.4": True,
570                        "v6.4.0": True,
571                        "v6.4.1": True,
572                        "v6.2.0": True,
573                        "v6.2.3": True,
574                        "v6.2.5": True,
575                        "v6.2.7": True,
576                        "v6.0.11": True
577                    }
578                },
579                {
580                    "value": "disable",
581                    "revisions": {
582                        "v6.0.0": True,
583                        "v7.0.0": True,
584                        "v6.0.5": True,
585                        "v6.4.4": True,
586                        "v6.4.0": True,
587                        "v6.4.1": True,
588                        "v6.2.0": True,
589                        "v6.2.3": True,
590                        "v6.2.5": True,
591                        "v6.2.7": True,
592                        "v6.0.11": True
593                    }
594                }
595            ],
596            "revisions": {
597                "v6.0.0": True,
598                "v7.0.0": True,
599                "v6.0.5": True,
600                "v6.4.4": True,
601                "v6.4.0": True,
602                "v6.4.1": True,
603                "v6.2.0": True,
604                "v6.2.3": True,
605                "v6.2.5": True,
606                "v6.2.7": True,
607                "v6.0.11": True
608            }
609        }
610    },
611    "revisions": {
612        "v6.0.0": True,
613        "v7.0.0": True,
614        "v6.0.5": True,
615        "v6.4.4": True,
616        "v6.4.0": True,
617        "v6.4.1": True,
618        "v6.2.0": True,
619        "v6.2.3": True,
620        "v6.2.5": True,
621        "v6.2.7": True,
622        "v6.0.11": True
623    }
624}
625
626
627def main():
628    module_spec = schema_to_module_spec(versioned_schema)
629    mkeyname = None
630    fields = {
631        "access_token": {"required": False, "type": "str", "no_log": True},
632        "enable_log": {"required": False, "type": bool},
633        "vdom": {"required": False, "type": "str", "default": "root"},
634        "firewall_ipv6_eh_filter": {
635            "required": False, "type": "dict", "default": None,
636            "options": {
637            }
638        }
639    }
640    for attribute_name in module_spec['options']:
641        fields["firewall_ipv6_eh_filter"]['options'][attribute_name] = module_spec['options'][attribute_name]
642        if mkeyname and mkeyname == attribute_name:
643            fields["firewall_ipv6_eh_filter"]['options'][attribute_name]['required'] = True
644
645    check_legacy_fortiosapi()
646    module = AnsibleModule(argument_spec=fields,
647                           supports_check_mode=False)
648
649    versions_check_result = None
650    if module._socket_path:
651        connection = Connection(module._socket_path)
652        if 'access_token' in module.params:
653            connection.set_option('access_token', module.params['access_token'])
654
655        if 'enable_log' in module.params:
656            connection.set_option('enable_log', module.params['enable_log'])
657        else:
658            connection.set_option('enable_log', False)
659        fos = FortiOSHandler(connection, module, mkeyname)
660        versions_check_result = check_schema_versioning(fos, versioned_schema, "firewall_ipv6_eh_filter")
661
662        is_error, has_changed, result = fortios_firewall(module.params, fos)
663
664    else:
665        module.fail_json(**FAIL_SOCKET_MSG)
666
667    if versions_check_result and versions_check_result['matched'] is False:
668        module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv")
669
670    if not is_error:
671        if versions_check_result and versions_check_result['matched'] is False:
672            module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result)
673        else:
674            module.exit_json(changed=has_changed, meta=result)
675    else:
676        if versions_check_result and versions_check_result['matched'] is False:
677            module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result)
678        else:
679            module.fail_json(msg="Error in repo", meta=result)
680
681
682if __name__ == '__main__':
683    main()
684