Пример #1
0
 def __init__(self):
     self.fw = FirewallClient()
     self.config = self.fw.config()
     if not self.config:
         log.warning('FirewallD is not running attempting to start...')
         import subprocess
         import time
         subprocess.check_output(
             ['systemctl', 'enable', '--now', 'firewalld'])
         # firewall-cmd synchronously waits for FirewallD startup
         subprocess.check_output(['firewall-cmd', '--state'])
         self.fw = FirewallClient()
         self.config = self.fw.config()
Пример #2
0
 def __init__(self, rules_id, ipv4_public_addr=None, ipv4_private_addr=None):
     self.fw = FirewallClient()
     self.config = self.fw.config()
     self.fw_direct = self.config.direct()
     self.prio = 0
     self.ipv = 'ipv4'
     self.table = 'filter'
     self.chain = 'FORWARD'
     self.rules_id = rules_id
     self.ipv4_public_addr = ipv4_public_addr
     self.ipv4_private_addr = ipv4_private_addr
     self.firewall_in_chain = FIREWALL_IN_NAME + str(rules_id)
     self.firewall_out_chain = FIREWALL_OUT_NAME + str(rules_id)
def main():

    module = AnsibleModule(
        argument_spec=dict(
            table=dict(required=False, default='filter'),
            chain=dict(required=True),
            priority=dict(required=False, default=0, type='int'),
            args=dict(required=True),
            type=dict(choices=['ipv4', 'ipv6', 'eb'], default='ipv4'),
            permanent=dict(type='bool', required=False, default=None),
            state=dict(choices=['present', 'absent'], required=True),
        ),
        supports_check_mode=True
    )

    if not HAVE_FIREWALLD:
        module.fail_json(msg='firewalld and the python module are required '
                             'for this module')

    if not FIREWALLD_RUNNING:
        module.fail_json(msg='firewalld is not running, and offline operations'
                             ' are not supported yet')

    table = module.params['table']
    chain = module.params['chain']
    priority = module.params['priority']
    args = module.params['args'].split(' ')
    address_type = module.params['type']
    permanent = module.params['permanent']
    state = module.params['state']

    if permanent:
        fw = FirewallClient().config().direct()
    else:
        fw = FirewallClient()
    rules = fw.getRules(ipv=address_type, table=table, chain=chain)

    changed = False
    if state == 'present':
        if (priority, args) not in rules:
            fw.addRule(ipv=address_type, table=table, chain=chain,
                       priority=priority, args=args)
            changed = True
    else:
        if (priority, args) in rules:
            fw.removeRule(ipv=address_type, table=table, chain=chain,
                          priority=priority, args=args)
            changed = True
    result = dict(changed=changed)
    module.exit_json(**result)
def main():

    module = AnsibleModule(
        argument_spec=dict(
            name=dict(required=True),
            state=dict(choices=['present', 'absent'], required=True),
            no_reload=dict(type='bool', default='no'),
        ),
        supports_check_mode=False
    )

    if not HAVE_FIREWALLD:
        module.fail_json(msg='firewalld and the python module are required '
                             'for this module')

    if not FIREWALLD_RUNNING:
        module.fail_json(msg='firewalld is not running, and offline operations'
                             ' are not supported yet')

    name = module.params['name']
    state = module.params['state']
    no_reload = module.params['no_reload']

    fw = FirewallClient().config()
    zones = fw.getZoneNames()

    changed = False
    if state == 'present':
        if name not in zones:
            fw.addZone(name, FirewallClientZoneSettings())
            changed = True
    else:
        if name in zones:
            z = fw.getZoneByName(name)
            z.remove()
            changed = True
    if changed and not no_reload:
        FirewallClient().reload()

    result = dict(changed=changed)
    module.exit_json(**result)
Пример #5
0
 def __init__(self):
     try:
         from firewall.client import FirewallClient
         self._fw = FirewallClient()
         if not self._fw.connected:
             debugprint("FirewallD seems to be installed but not running")
             self._fw = None
             self._zone = None
             self.running = False
             return
         zone_name = self._get_active_zone()
         if zone_name:
             self._zone = self._fw.config().getZoneByName(zone_name)
         else:
             self._zone = None
         self.running = True
         debugprint("Using /org/fedoraproject/FirewallD1")
     except (ImportError, dbus.exceptions.DBusException):
         self._fw = None
         self._zone = None
         self.running = False
 def __init__ (self):
     try:
         from firewall.client import FirewallClient
         self._fw = FirewallClient ()
         if not self._fw.connected:
             debugprint ("FirewallD seems to be installed but not running")
             self._fw = None
             self._zone = None
             self.running = False
             return
         zone_name = self._get_active_zone ()
         if zone_name:
             self._zone = self._fw.config().getZoneByName (zone_name)
         else:
             self._zone = None
         self.running = True
         debugprint ("Using /org/fedoraproject/FirewallD1")
     except (ImportError, dbus.exceptions.DBusException):
         self._fw = None
         self._zone = None
         self.running = False
Пример #7
0
def main():

    module = AnsibleModule(argument_spec=dict(
        name=dict(required=True),
        state=dict(choices=['present', 'absent'], required=True),
        no_reload=dict(type='bool', default='no'),
    ),
                           supports_check_mode=False)

    if not HAVE_FIREWALLD:
        module.fail_json(msg='firewalld and the python module are required '
                         'for this module')

    if not FIREWALLD_RUNNING:
        module.fail_json(msg='firewalld is not running, and offline operations'
                         ' are not supported yet')

    name = module.params['name']
    state = module.params['state']
    no_reload = module.params['no_reload']

    fw = FirewallClient().config()
    zones = fw.getZoneNames()

    changed = False
    if state == 'present':
        if name not in zones:
            fw.addZone(name, FirewallClientZoneSettings())
            changed = True
    else:
        if name in zones:
            z = fw.getZoneByName(name)
            z.remove()
            changed = True
    if changed and not no_reload:
        FirewallClient().reload()

    result = dict(changed=changed)
    module.exit_json(**result)
Пример #8
0
# Imports
try:
    import firewall.config
    FW_VERSION = firewall.config.VERSION

    from firewall.client import Rich_Rule
    from firewall.client import FirewallClient
    from firewall.client import FirewallClientZoneSettings
    from firewall.errors import FirewallError
    fw = None
    fw_offline = False
    import_failure = False

    try:
        fw = FirewallClient()
        fw.getDefaultZone()
    except (AttributeError, FirewallError):
        # Firewalld is not currently running, permanent-only operations
        fw_offline = True

        # Import other required parts of the firewalld API
        #
        # NOTE:
        #  online and offline operations do not share a common firewalld API
        from firewall.core.fw_test import Firewall_test
        fw = Firewall_test()
        fw.start()

except ImportError:
    import_failure = True
Пример #9
0
def main():
    global module

    ## make module global so we don't have to pass it to action_handler every
    ## function call
    global module
    module = AnsibleModule(
        argument_spec = dict(
            service=dict(required=False,default=None),
            port=dict(required=False,default=None),
            rich_rule=dict(required=False,default=None),
            zone=dict(required=False,default=None),
            immediate=dict(type='bool',default=False),
            source=dict(required=False,default=None),
            permanent=dict(type='bool',required=False,default=None),
            state=dict(choices=['enabled', 'disabled'], required=True),
            timeout=dict(type='int',required=False,default=0),
            interface=dict(required=False,default=None),
            masquerade=dict(required=False,default=None),
            offline=dict(type='bool',required=False,default=None),
        ),
        supports_check_mode=True
    )

    ## Handle running (online) daemon vs non-running (offline) daemon
    global fw
    global fw_offline
    global Rich_Rule
    global FirewallClientZoneSettings

    ## Imports
    try:
        import firewall.config
        FW_VERSION = firewall.config.VERSION

        from firewall.client import Rich_Rule
        from firewall.client import FirewallClient
        fw = None
        fw_offline = False

        try:
            fw = FirewallClient()
            fw.getDefaultZone()
        except AttributeError:
            ## Firewalld is not currently running, permanent-only operations

            ## Import other required parts of the firewalld API
            ##
            ## NOTE:
            ##  online and offline operations do not share a common firewalld API
            from firewall.core.fw_test import Firewall_test
            from firewall.client import FirewallClientZoneSettings
            fw = Firewall_test()
            fw.start()
            fw_offline = True

    except ImportError:
        ## Make python 2.4 shippable ci tests happy
        e = sys.exc_info()[1]
        module.fail_json(msg='firewalld and its python 2 module are required for this module, version 2.0.11 or newer required (3.0.9 or newer for offline operations) \n %s' % e)

    if fw_offline:
        ## Pre-run version checking
        if FW_VERSION < "0.3.9":
            module.fail_json(msg='unsupported version of firewalld, offline operations require >= 3.0.9')
    else:
        ## Pre-run version checking
        if FW_VERSION < "0.2.11":
            module.fail_json(msg='unsupported version of firewalld, requires >= 2.0.11')

        ## Check for firewalld running
        try:
            if fw.connected == False:
                module.fail_json(msg='firewalld service must be running, or try with offline=true')
        except AttributeError:
            module.fail_json(msg="firewalld connection can't be established,\
                    installed version (%s) likely too old. Requires firewalld >= 2.0.11" % FW_VERSION)


    ## Verify required params are provided
    if module.params['source'] == None and module.params['permanent'] == None:
        module.fail_json(msg='permanent is a required parameter')

    if module.params['interface'] != None and module.params['zone'] == None:
        module.fail(msg='zone is a required parameter')

    if module.params['immediate'] and fw_offline:
        module.fail(msg='firewall is not currently running, unable to perform immediate actions without a running firewall daemon')

    ## Global Vars
    changed=False
    msgs = []
    service = module.params['service']
    rich_rule = module.params['rich_rule']
    source = module.params['source']

    if module.params['port'] != None:
        port, protocol = module.params['port'].split('/')
        if protocol == None:
            module.fail_json(msg='improper port format (missing protocol?)')
    else:
        port = None

    if module.params['zone'] != None:
        zone = module.params['zone']
    else:
        if fw_offline:
            zone = fw.get_default_zone()
        else:
            zone = fw.getDefaultZone()

    permanent = module.params['permanent']
    desired_state = module.params['state']
    immediate = module.params['immediate']
    timeout = module.params['timeout']
    interface = module.params['interface']
    masquerade = module.params['masquerade']

    modification_count = 0
    if service != None:
        modification_count += 1
    if port != None:
        modification_count += 1
    if rich_rule != None:
        modification_count += 1
    if interface != None:
        modification_count += 1
    if masquerade != None:
        modification_count += 1

    if modification_count > 1:
        module.fail_json(msg='can only operate on port, service, rich_rule or interface at once')

    if service != None:
        if immediate and permanent:
            is_enabled_permanent = action_handler(
                get_service_enabled_permanent,
                (zone, service)
            )
            is_enabled_immediate = action_handler(
                get_service_enabled,
                (zone, service)
            )
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    action_handler(
                        set_service_enabled_permanent,
                        (zone, service)
                    )
                    changed=True
                if not is_enabled_immediate:
                    action_handler(
                        set_service_enabled,
                        (zone, service, timeout)
                    )
                    changed=True


            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    action_handler(
                        set_service_disabled_permanent,
                        (zone, service)
                    )
                    changed=True
                if is_enabled_immediate:
                    action_handler(
                        set_service_disabled,
                        (zone, service)
                    )
                    changed=True

        elif permanent and not immediate:
            is_enabled = action_handler(
                get_service_enabled_permanent,
                (zone, service)
            )
            msgs.append('Permanent operation')

            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_service_enabled_permanent,
                        (zone, service)
                    )
                    changed=True
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_service_disabled_permanent,
                        (zone, service)
                    )
                    changed=True
        elif immediate and not permanent:
            is_enabled = action_handler(
                get_service_enabled,
                (zone, service)
            )
            msgs.append('Non-permanent operation')


            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_service_enabled,
                        (zone, service, timeout)
                    )
                    changed=True
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_service_disabled,
                        (zone, service)
                    )
                    changed=True

        if changed == True:
            msgs.append("Changed service %s to %s" % (service, desired_state))

    # FIXME - source type does not handle non-permanent mode, this was an
    #         oversight in the past.
    if source != None:
        is_enabled = action_handler(get_source, (zone, source))
        if desired_state == "enabled":
            if is_enabled == False:
                if module.check_mode:
                    module.exit_json(changed=True)

                action_handler(add_source, (zone, source))
                changed=True
                msgs.append("Added %s to zone %s" % (source, zone))
        elif desired_state == "disabled":
            if is_enabled == True:
                if module.check_mode:
                    module.exit_json(changed=True)

                action_handler(remove_source, (zone, source))
                changed=True
                msgs.append("Removed %s from zone %s" % (source, zone))

    if port != None:
        if immediate and permanent:
            is_enabled_permanent = action_handler(
                get_port_enabled_permanent,
                (zone,[port, protocol])
            )
            is_enabled_immediate = action_handler(
                get_port_enabled,
                (zone, [port, protocol])
            )
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    action_handler(
                        set_port_enabled_permanent,
                        (zone, port, protocol)
                    )
                    changed=True
                if not is_enabled_immediate:
                    action_handler(
                        set_port_enabled,
                        (zone, port, protocol, timeout)
                    )
                    changed=True

            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    action_handler(
                        set_port_disabled_permanent,
                        (zone, port, protocol)
                    )
                    changed=True
                if is_enabled_immediate:
                    action_handler(
                        set_port_disabled,
                        (zone, port, protocol)
                    )
                    changed=True

        elif permanent and not immediate:
            is_enabled = action_handler(
                get_port_enabled_permanent,
                (zone, [port, protocol])
            )
            msgs.append('Permanent operation')

            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_port_enabled_permanent,
                        (zone, port, protocol)
                    )
                    changed=True
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_port_disabled_permanent,
                        (zone, port, protocol)
                    )
                    changed=True
        if immediate and not permanent:
            is_enabled = action_handler(
                get_port_enabled,
                (zone, [port,protocol])
            )
            msgs.append('Non-permanent operation')

            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_port_enabled,
                        (zone, port, protocol, timeout)
                    )
                    changed=True
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_port_disabled,
                        (zone, port, protocol)
                    )
                    changed=True

        if changed == True:
            msgs.append("Changed port %s to %s" % ("%s/%s" % (port, protocol), \
                        desired_state))

    if rich_rule != None:
        if immediate and permanent:
            is_enabled_permanent = action_handler(
                get_rich_rule_enabled_permanent,
                (zone, rich_rule)
            )
            is_enabled_immediate = action_handler(
                get_rich_rule_enabled,
                (zone, rich_rule)
            )
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    action_handler(
                        set_rich_rule_enabled_permanent,
                        (zone, rich_rule)
                    )
                    changed=True
                if not is_enabled_immediate:
                    action_handler(
                        set_rich_rule_enabled,
                        (zone, rich_rule, timeout)
                    )
                    changed=True

            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    action_handler(
                        set_rich_rule_disabled_permanent,
                        (zone, rich_rule)
                    )
                    changed=True
                if is_enabled_immediate:
                    action_handler(
                        set_rich_rule_disabled,
                        (zone, rich_rule)
                    )
                    changed=True
        if permanent and not immediate:
            is_enabled = action_handler(
                get_rich_rule_enabled_permanent,
                (zone, rich_rule)
            )
            msgs.append('Permanent operation')

            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_rich_rule_enabled_permanent,
                        (zone, rich_rule)
                    )
                    changed=True
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_rich_rule_disabled_permanent,
                        (zone, rich_rule)
                    )
                    changed=True
        if immediate and not permanent:
            is_enabled = action_handler(
                get_rich_rule_enabled,
                (zone, rich_rule)
            )
            msgs.append('Non-permanent operation')

            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_rich_rule_enabled,
                        (zone, rich_rule, timeout)
                    )
                    changed=True
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(
                        set_rich_rule_disabled,
                        (zone, rich_rule)
                    )
                    changed=True

        if changed == True:
            msgs.append("Changed rich_rule %s to %s" % (rich_rule, desired_state))

    if interface != None:
        if immediate and permanent:
            is_enabled_permanent = action_handler(
                get_interface_permanent,
                (zone, interface)
            )
            is_enabled_immediate = action_handler(
                get_interface,
                (zone, interface)
            )
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    change_zone_of_interface_permanent(zone, interface)
                    changed=True
                if not is_enabled_immediate:
                    change_zone_of_interface(zone, interface)
                    changed=True
                if changed:
                    msgs.append("Changed %s to zone %s" % (interface, zone))

            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    remove_interface_permanent(zone, interface)
                    changed=True
                if is_enabled_immediate:
                    remove_interface(zone, interface)
                    changed=True
                if changed:
                    msgs.append("Removed %s from zone %s" % (interface, zone))

        elif permanent and not immediate:
            is_enabled = action_handler(
                get_interface_permanent,
                (zone, interface)
            )
            msgs.append('Permanent operation')
            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    change_zone_of_interface_permanent(zone, interface)
                    changed=True
                    msgs.append("Changed %s to zone %s" % (interface, zone))
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    remove_interface_permanent(zone, interface)
                    changed=True
                    msgs.append("Removed %s from zone %s" % (interface, zone))
        elif immediate and not permanent:
            is_enabled = action_handler(
                get_interface,
                (zone, interface)
            )
            msgs.append('Non-permanent operation')
            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    change_zone_of_interface(zone, interface)
                    changed=True
                    msgs.append("Changed %s to zone %s" % (interface, zone))
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    remove_interface(zone, interface)
                    changed=True
                    msgs.append("Removed %s from zone %s" % (interface, zone))

    if masquerade != None:

        if immediate and permanent:
            is_enabled_permanent = action_handler(
                get_masquerade_enabled_permanent,
                (zone)
            )
            is_enabled_immediate = action_handler(get_masquerade_enabled, (zone))
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    action_handler(set_masquerade_permanent, (zone, True))
                    changed=True
                if not is_enabled_immediate:
                    action_handler(set_masquerade_enabled, (zone))
                    changed=True
                if changed:
                    msgs.append("Added masquerade to zone %s" % (zone))

            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    action_handler(set_masquerade_permanent, (zone, False))
                    changed=True
                if is_enabled_immediate:
                    action_handler(set_masquerade_disabled, (zone))
                    changed=True
                if changed:
                    msgs.append("Removed masquerade from zone %s" % (zone))

        elif permanent and not immediate:
            is_enabled = action_handler(get_masquerade_enabled_permanent, (zone))
            msgs.append('Permanent operation')

            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_masquerade_permanent, (zone, True))
                    changed=True
                    msgs.append("Added masquerade to zone %s" % (zone))
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_masquerade_permanent, (zone, False))
                    changed=True
                    msgs.append("Removed masquerade from zone %s" % (zone))
        elif immediate and not permanent:
            is_enabled = action_handler(get_masquerade_enabled, (zone))
            msgs.append('Non-permanent operation')

            if desired_state == "enabled":
                if is_enabled == False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_masquerade_enabled, (zone))
                    changed=True
                    msgs.append("Added masquerade to zone %s" % (zone))
            elif desired_state == "disabled":
                if is_enabled == True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_masquerade_disabled, (zone))
                    changed=True
                    msgs.append("Removed masquerade from zone %s" % (zone))

    if fw_offline:
        msgs.append("(offline operation: only on-disk configs were altered)")
    module.exit_json(changed=changed, msg=', '.join(msgs))
Пример #10
0
 def setUp(self):
     unittest.TestCase.setUp(self)
     self.fw = FirewallClient()
Пример #11
0
def getActiveZones():
    fw = FirewallClient()
    zones = fw.getActiveZones()
    return zones
Пример #12
0
def addServiceToZone(service, zone):
    fw = FirewallClient()
    fw_zone = fw.config().getZoneByName(zone)
    fw_settings = fw_zone.getSettings()
    fw_settings.addService(service)
    fw_zone.update(fw_settings)
Пример #13
0
def getActiveZones():
    fw = FirewallClient()
    zones = fw.getActiveZones()
    return zones
Пример #14
0
def addServiceToZone(service, zone):
    fw = FirewallClient()
    fw_zone = fw.config().getZoneByName(zone)
    fw_settings = fw_zone.getSettings()
    fw_settings.addService(service)
    fw_zone.update(fw_settings)
Пример #15
0
class FirewallWrapper:
    NETWORKBLOCK_IPSET4 = 'networkblock4'
    NETWORKBLOCK_IPSET6 = 'networkblock6'
    NETWORKBLOCK_IPSET_BASE_NAME = 'networkblock'

    def __init__(self):
        self.fw = FirewallClient()
        self.config = self.fw.config()
        if not self.config:
            log.warning('FirewallD is not running attempting to start...')
            import subprocess
            import time
            subprocess.check_output(
                ['systemctl', 'enable', '--now', 'firewalld'])
            # firewall-cmd synchronously waits for FirewallD startup
            subprocess.check_output(['firewall-cmd', '--state'])
            self.fw = FirewallClient()
            self.config = self.fw.config()

    def get_create_set(self, name, family='inet'):
        if name in self.config.getIPSetNames():
            return self.config.getIPSetByName(name)
        settings = FirewallClientIPSetSettings()
        settings.setType('hash:net')
        settings.setOptions({
            'maxelem': '1000000',
            'family': family,
            'hashsize': '4096'
        })
        return self.config.addIPSet(name, settings)

    def get_block_ipset4(self, name=None):
        if not name:
            name = FirewallWrapper.NETWORKBLOCK_IPSET_BASE_NAME
        name = name + '4'
        if name in self.config.getIPSetNames():
            return self.config.getIPSetByName(name)
        settings = FirewallClientIPSetSettings()
        settings.setType('hash:net')
        settings.setOptions({
            'maxelem': '1000000',
            'family': 'inet',
            'hashsize': '4096'
        })
        return self.config.addIPSet(name, settings)

    def get_block_ipset6(self, name=None):
        if not name:
            name = FirewallWrapper.NETWORKBLOCK_IPSET_BASE_NAME
        name = name + '6'
        if name in self.config.getIPSetNames():
            return self.config.getIPSetByName(name)
        settings = FirewallClientIPSetSettings()
        settings.setType('hash:net')
        settings.setOptions({
            'maxelem': '1000000',
            'family': 'inet6',
            'hashsize': '4096'
        })
        return self.config.addIPSet(name, settings)

    def get_block_ipset_for_ip(self, ip, name=None):
        if ip.version == 4:
            return self.get_block_ipset4(name)
        if ip.version == 6:
            return self.get_block_ipset6(name)
        return None

    @do_maybe_already_enabled
    def ensure_ipset_entries(self, ipset, entries):
        return ipset.setEntries(entries)

    @do_maybe_already_enabled
    def ensure_entry_in_ipset(self, ipset, entry):
        return ipset.addEntry(str(entry))

    @do_maybe_already_enabled
    def ensure_entry_not_in_ipset(self, ipset, entry):
        return ipset.removeEntry(str(entry))

    @do_maybe_already_enabled
    def ensure_block_ipset_in_drop_zone(self, ipset):
        # ensure that the block ipset is in drop zone:
        drop_zone = self.config.getZoneByName('drop')
        # self.config.getIPSetNames
        return drop_zone.addSource('ipset:{}'.format(
            ipset.get_property('name')))

    @do_maybe_already_enabled
    def add_service(self, name, zone='public'):
        self.fw.addService(zone, name)
        self.fw.runtimeToPermanent()

    @do_maybe_already_enabled
    def block_ip(self, ip, ipset_name=None, reload=True):
        block_ipset = self.get_block_ipset_for_ip(ip, ipset_name)
        if not block_ipset:
            # TODO err: unsupported protocol
            raise Exception('Unsupported protocol')
        self.ensure_block_ipset_in_drop_zone(block_ipset)
        log.info('Adding IP address {} to block set {}'.format(
            ip, block_ipset.get_property('name')))
        try:
            from aggregate6 import aggregate
            entries = []
            for entry in block_ipset.getEntries():
                entries.append(str(entry))
            entries.append(str(ip))
            block_ipset.setEntries(aggregate(entries))
        except ImportError:
            block_ipset.addEntry(str(ip))
        if reload:
            log.info('Reloading FirewallD to apply permanent configuration')
            self.fw.reload()
        log.info('Breaking connection with {}'.format(ip))
        from subprocess import CalledProcessError, check_output, STDOUT
        try:
            check_output(["/sbin/conntrack", "-D", "-s",
                          str(ip)],
                         stderr=STDOUT)
        except CalledProcessError as e:
            pass

    def get_blocked_ips4(self, name=None):
        block_ipset4 = self.get_block_ipset4(name)
        return block_ipset4.getEntries()

    def get_blocked_ips6(self, name=None):
        block_ipset6 = self.get_block_ipset6(name)
        return block_ipset6.getEntries()

    @do_maybe_not_enabled
    def remove_ipset_from_zone(self, zone, ipset_name):
        # drop_zone.removeSource('ipset:')
        zone.removeSource('ipset:{}'.format(ipset_name))

    @do_maybe_invalid_ipset
    def clear_ipset_by_name(self, ipset_name):
        try:
            # does not work: ipset.setEntries([])
            self.fw.setEntries(ipset_name, [])
        except dbus.exceptions.DBusException:
            pass

    @do_maybe_invalid_ipset
    def destroy_ipset_by_name(self, name):
        log.info('Destroying IPSet {}'.format(name))
        # firewalld up to this commit
        # https://github.com/firewalld/firewalld/commit/f5ed30ce71755155493e78c13fd9036be8f70fc4
        # does not delete runtime ipsets, so we have to clear them :(
        # they are not removed from runtime as still reported by ipset -L
        # although they *are* removed from FirewallD
        if name not in self.fw.getIPSets():
            return

        ipset = self.config.getIPSetByName(name)
        if ipset:
            self.clear_ipset_by_name(name)
            ipset.remove()

    def get_blocked_countries(self):
        blocked_countries = []
        all_ipsets = self.fw.getIPSets()
        from .Countries import Countries
        countries = Countries()
        for ipset_name in all_ipsets:
            if ipset_name.startswith('fds-'):
                country_code = ipset_name.split('-')[1]
                if country_code in countries.names_by_code:
                    blocked_countries.append(
                        countries.names_by_code[country_code])
        return blocked_countries

    def update_ipsets(self):
        need_reload = False
        all_ipsets = self.fw.getIPSets()
        from .Countries import Countries
        countries = Countries()
        is_tor_blocked = False
        for ipset_name in all_ipsets:
            if ipset_name.startswith('fds-tor-'):
                is_tor_blocked = True
            elif ipset_name.startswith('fds-'):
                country_code = ipset_name.split('-')[1]
                if country_code in countries.names_by_code:
                    country_name = countries.names_by_code[country_code]
                    country = countries.get_by_name(country_name)
                    self.block_country(country, reload=False)
                    need_reload = True
        if is_tor_blocked:
            self.block_tor(reload=False)
            need_reload = True
        if need_reload:
            self.fw.reload()
        return True

    def reset(self):
        drop_zone = self.config.getZoneByName('drop')

        self.remove_ipset_from_zone(drop_zone, self.NETWORKBLOCK_IPSET4)
        self.destroy_ipset_by_name(self.NETWORKBLOCK_IPSET4)

        self.remove_ipset_from_zone(drop_zone, self.NETWORKBLOCK_IPSET6)
        self.destroy_ipset_by_name(self.NETWORKBLOCK_IPSET6)

        all_ipsets = self.fw.getIPSets()
        # get any ipsets prefixed with "fds-"
        for ipset_name in all_ipsets:
            if ipset_name.startswith('fds-'):
                self.remove_ipset_from_zone(drop_zone, ipset_name)
                self.destroy_ipset_by_name(ipset_name)

        self.fw.reload()

    def block_tor(self, reload=True):
        log.info('Blocking Tor exit nodes')
        w = WebClient()
        tor4_exits = w.get_tor_exits(family=4)
        tor6_exits = w.get_tor_exits(family=6)

        tor4_ipset = self.get_create_set('fds-tor-4')
        self.ensure_ipset_entries(tor4_ipset, tor4_exits)

        tor6_ipset = self.get_create_set('fds-tor-6', family='inet6')
        self.ensure_ipset_entries(tor6_ipset, tor6_exits)

        self.ensure_block_ipset_in_drop_zone(tor4_ipset)
        self.ensure_block_ipset_in_drop_zone(tor6_ipset)
        if reload:
            log.info('Reloading FirewallD...')
            self.fw.reload()
        log.info('Done!')
        # while cron will do "sync" behavior"

    def block_country(self, country, reload=True):
        # print('address/netmask is invalid: %s' % sys.argv[1])
        # parse out as a country

        log.info('Blocking {} {}'.format(country.name, country.getFlag()))
        # print("\N{grinning face}")

        # TODO get aggregated zone file, save as cache,
        # do diff to know which stuff was changed and add/remove blocks
        # https://docs.python.org/2/library/difflib.html
        # TODO persist info on which countries were blocked (in the config file)
        # then sync zones via "fds cron"
        # TODO conditional get test on getpagespeed.com
        w = WebClient()
        country_networks = w.get_country_networks(country=country)

        ipset = self.get_create_set(country.get_set_name())
        self.ensure_ipset_entries(ipset, country_networks)

        # this is slow. setEntries is a lot faster
        # for network in tqdm(country_networks, unit='network',
        #                     desc='Adding {} networks to IPSet {}'.format(c.getNation(), c.get_set_name())):
        #     log.debug(network)
        #     fw.ensure_entry_in_ipset(ipset=ipset, entry=network)

        # TODO retry, timeout
        # this action re-adds all entries entirely
        # there should be "fds-<country.code>-<family>" ip set
        self.ensure_block_ipset_in_drop_zone(ipset)
        if reload:
            log.info('Reloading FirewallD...')
            self.fw.reload()
        log.info('Done!')
        # while cron will do "sync" behavior"

    def unblock_country(self, ip_or_country_name):
        # print('address/netmask is invalid: %s' % sys.argv[1])
        # parse out as a country
        from .Countries import Countries
        countries = Countries()
        c = countries.get_by_name(ip_or_country_name)

        if not c:
            log.error(
                '{} does not look like a correct IP or a country name'.format(
                    ip_or_country_name))
            return False

        drop_zone = self.config.getZoneByName('drop')

        log.info('Unblocking {} {}'.format(c.name, c.getFlag()))

        self.remove_ipset_from_zone(drop_zone, c.get_set_name())
        self.destroy_ipset_by_name(c.get_set_name())
        log.info('Reloading FirewallD...')
        self.fw.reload()
        log.info('Done!')
        # while cron will do "sync" behavior"

    def unblock_ip(self, ip_or_country_name):
        block_ipset = self.get_block_ipset_for_ip(ip_or_country_name)
        if not block_ipset:
            # TODO err: unsupported protocol
            raise Exception('Unsupported protocol')
        log.info('Removing {} from block set {}'.format(
            ip_or_country_name, block_ipset.get_property('name')))
        self.ensure_entry_not_in_ipset(block_ipset, ip_or_country_name)
        log.info('Reloading FirewallD to apply permanent configuration')
        self.fw.reload()
Пример #16
0
class FirewallMgr(object):

    def __init__(self, rules_id, ipv4_public_addr=None, ipv4_private_addr=None):
        self.fw = FirewallClient()
        self.config = self.fw.config()
        self.fw_direct = self.config.direct()
        self.prio = 0
        self.ipv = 'ipv4'
        self.table = 'filter'
        self.chain = 'FORWARD'
        self.rules_id = rules_id
        self.ipv4_public_addr = ipv4_public_addr
        self.ipv4_private_addr = ipv4_private_addr
        self.firewall_in_chain = FIREWALL_IN_NAME + str(rules_id)
        self.firewall_out_chain = FIREWALL_OUT_NAME + str(rules_id)

    def attach(self, rules_inbound, rules_outbound):
        err_msg = None
        if not self.is_locked():
            self.set_state()
            self.create_firewall()
            self.create_rule('inbound', rules_inbound)
            self.create_rule('outbound', rules_outbound)
            self.save()
        else:
            err_msg = 'Firewall closed connection by timeout %ssec.' % FIREWALLD_STATE_TIMEOUT
        return err_msg

    def detach(self):
        err_msg = None
        if not self.is_locked():
            self.set_state()
            self.remove_firewall()
            self.save()
        else:
            err_msg = 'Firewall closed connection by timeout %ssec.' % FIREWALLD_STATE_TIMEOUT
        return err_msg

    def add_rule(self, rules_inbound, rules_outbound):
        err_msg = None
        if not self.is_locked():
            self.set_state()
            if rules_inbound:
                self.create_rule('inbound', rules_inbound)
            if rules_outbound:
                self.create_rule('outbound', rules_outbound)
            self.save()
        else:
            err_msg = 'Firewall closed connection by timeout %ssec.' % FIREWALLD_STATE_TIMEOUT
        return err_msg

    def delete_rule(self, rules_inbound, rules_outbound):
        err_msg = None
        if not self.is_locked():
            self.set_state()
            if rules_inbound:
                self.remove_rule('inbound', rules_inbound)
            if rules_outbound:
                self.remove_rule('outbound', rules_outbound)
            self.save()
        else:
            err_msg = 'Firewall closed connection by timeout %ssec.' % FIREWALLD_STATE_TIMEOUT
        return err_msg

    def set_state(self):
        f = open(FIREWALLD_STATE_FILE, "w")
        f.write('1')
        f.close()

    def unset_state(self):
        f = open(FIREWALLD_STATE_FILE, "w")
        f.write('0')
        f.close()

    def read_state(self):
        if os.path.isfile(FIREWALLD_STATE_FILE):
            f = open(FIREWALLD_STATE_FILE, "r")
            f_data = f.read()
            f.close()
            if f_data:
                state = bool(f_data)
            else:
                self.unset_state()
                state = False
            return state
        else:
            return False

    def is_locked(self):
        if self.read_state():
            seconds = 0
            while self.read_state():
                seconds += 1
                time.sleep(1)
                if seconds >= FIREWALLD_STATE_TIMEOUT:
                    return True
        return False

    def save(self):
        self.fw_direct.update(self.fw_direct.getSettings())
        self.unset_state()

    def query_rule(self, args):
        chain = self.chain + FIREWALL_CHAIN_PREFIX
        ipt_cmd = 'iptables -t {0} -C {1} {2}'.format(self.table, chain, ' '.join(args))
        run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
        if run_ipt_cmd == 1:
            return False
        return True

    def query_rule_cfg(self, args):
        check = self.fw_direct.queryRule(self.ipv, self.table, self.chain, self.prio, args)
        return check

    def query_chain(self, chain):
        ipt_cmd = 'iptables -t {0} -L {1}'.format(self.table, chain)
        run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
        if run_ipt_cmd == 1:
            return False
        return True

    def query_chain_cfg(self, chain):
        check = self.fw_direct.queryChain(self.ipv, self.table, chain)
        return check

    def query_chain_rule(self, chain, args):
        ipt_cmd = 'iptables -t {0} -C {1} {2}'.format(self.table, chain, ' '.join(args))
        run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
        if run_ipt_cmd == 1:
            return False
        return True

    def query_chain_rule_cfg(self, chain, args):
        check = self.fw_direct.queryRule(self.ipv, self.table, chain, self.prio, args)
        return check

    def rule_args(self, chain, rule):
        src_dst = '-d'
        port = rule.get('port')
        action = rule.get('action')
        address = rule.get('address')
        protocol = rule.get('protocol')

        if chain == 'inbound':
            src_dst = '-s'
               
        if action == 'DROP':
            # Dirty hack for icmp request
            if protocol == 'icmp':
                args = ['-p', 'icmp', '-m', 'conntrack', '--ctstate', 'NEW', '-j', action]
            # Dirty hack for TCP dynamic socket ports 
            if protocol == 'tcp':
                args = ['-p', 'tcp', '-m', 'conntrack', '--ctstate', 'NEW', '-j', action]
            # Dirty hack for UDP dynamic socket ports
            if protocol == 'udp':
                args = ['-p', 'udp', '-m', 'conntrack', '--ctstate', 'NEW', '-j', action]
            # Block all type of protocols
            if not protocol:
                args = ['-m', 'conntrack', '--ctstate', 'NEW', '-j', action]
        
        if action == 'ACCEPT':
            if protocol == 'icmp':
                args = ['-p', protocol, src_dst, address, '-j', action]
            if protocol == 'tcp' or protocol == 'udp':
                if port:
                    args = ['-p', protocol, src_dst, address, '--dport', str(port), '-j', action]
                else:
                    args = ['-p', protocol, src_dst, address, '-j', action]
            # Allow all traffic from address
            if not protocol and not port:
                args = [src_dst, address, '-j', action]
        
        return args

    def create_firewall(self):
        ipv4_addrs = []

        # IPv4 Public
        if self.ipv4_public_addr:
            ipv4_addrs.append(self.ipv4_public_addr)
        # IPv4 Private
        if self.ipv4_private_addr:
            ipv4_addrs.append(self.ipv4_private_addr)

        for ipaddr in ipv4_addrs:
            in_args = ['-d', ipaddr, '-j', self.firewall_in_chain]
            out_args = ['-s', ipaddr, '-j', self.firewall_out_chain]

            # Create firewall IN chain
            if not self.query_chain(self.firewall_in_chain):
                ipt_cmd = 'iptables -N {0}'.format(self.firewall_in_chain)
                run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                if run_ipt_cmd == 0:
                    if not self.query_chain_cfg(self.firewall_in_chain):
                        self.fw_direct.addChain(self.ipv, self.table, self.firewall_in_chain)

            # Create firewall IN rule for instance
            if not self.query_rule(in_args):
                chain = self.chain + FIREWALL_CHAIN_PREFIX
                ipt_cmd = 'iptables -t {0} -I {1} {2} {3}'.format(self.table, chain,
                                                                  FIREWALL_INSERT_LINE, ' '.join(in_args))
                run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                if run_ipt_cmd == 0:
                    if not self.query_rule_cfg(in_args):
                        self.fw_direct.addRule(self.ipv, self.table, self.chain, self.prio, in_args)

            # Create firewall OUT chain
            if not self.query_chain(self.firewall_out_chain):
                ipt_cmd = 'iptables -N {0}'.format(self.firewall_out_chain)
                run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                if run_ipt_cmd == 0:
                    if not self.query_chain_cfg(self.firewall_out_chain):
                        self.fw_direct.addChain(self.ipv, self.table, self.firewall_out_chain)

            # Create firewall OUT rule for instance
            if not self.query_rule(out_args):
                chain = self.chain + FIREWALL_CHAIN_PREFIX
                ipt_cmd = 'iptables -t {0} -I {1} {2} {3}'.format(self.table, chain,
                                                                  FIREWALL_INSERT_LINE, ' '.join(out_args))
                run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                if run_ipt_cmd == 0:
                    if not self.query_rule_cfg(out_args):
                        self.fw_direct.addRule(self.ipv, self.table, self.chain, self.prio, out_args)

    def remove_firewall(self):
        ipv4_addrs = []

        # IPv4 Public
        if self.ipv4_public_addr:
            ipv4_addrs.append(self.ipv4_public_addr)
        # IPv4 Private
        if self.ipv4_private_addr:
            ipv4_addrs.append(self.ipv4_private_addr)

        for ipaddr in ipv4_addrs:
            in_args = ['-d', ipaddr, '-j', self.firewall_in_chain]
            out_args = ['-s', ipaddr, '-j', self.firewall_out_chain]

            # Remove firewall IN rule for instance
            if self.query_rule(in_args):
                chain = self.chain + FIREWALL_CHAIN_PREFIX
                ipt_cmd = 'iptables -t {0} -D {1} {2}'.format(self.table, chain, ' '.join(in_args))
                run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                if run_ipt_cmd == 0:
                    if self.query_rule_cfg(in_args):
                        self.fw_direct.removeRule(self.ipv, self.table, self.chain, self.prio, in_args)

            # Remove firewall OUT rule for instance
            if self.query_rule(out_args):
                chain = self.chain + FIREWALL_CHAIN_PREFIX
                ipt_cmd = 'iptables -t {0} -D {1} {2}'.format(self.table, chain, ' '.join(out_args))
                run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                if run_ipt_cmd == 0:
                    if self.query_rule_cfg(out_args):
                        self.fw_direct.removeRule(self.ipv, self.table, self.chain, self.prio, out_args)

            # Check unused firewall rule
            used_firewall_rules = False
            for rule in self.fw_direct.getAllRules():
                if self.chain in rule and self.firewall_in_chain in rule[4][3]:
                    used_firewall_rules = True

            # If firewall doesn't have any rules with instances than remove sgfirewallroup rules and chains
            if not used_firewall_rules:
                for rule in self.fw_direct.getAllRules():
                    if self.firewall_in_chain in rule:
                        ipt_cmd = 'iptables -t {0} -D {1} {2}'.format(self.table, self.firewall_in_chain, ' '.join(rule[4]))
                        run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                        if run_ipt_cmd == 0:
                            self.fw_direct.removeRule(rule[0], rule[1], rule[2], rule[3], rule[4])
                    if self.firewall_out_chain in rule:
                        ipt_cmd = 'iptables -t {0} -D {1} {2}'.format(self.table, self.firewall_out_chain, ' '.join(rule[4]))
                        run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                        if run_ipt_cmd == 0:
                            self.fw_direct.removeRule(rule[0], rule[1], rule[2], rule[3], rule[4])

                for chain in self.fw_direct.getAllChains():
                    if self.firewall_in_chain in chain:
                        ipt_cmd = 'iptables -X {0}'.format(self.firewall_in_chain)
                        run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                        if run_ipt_cmd == 0:
                            self.fw_direct.removeChain(chain[0], chain[1], chain[2])
                    if self.firewall_out_chain in chain:
                        ipt_cmd = 'iptables -X {0}'.format(self.firewall_out_chain)
                        run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                        if run_ipt_cmd == 0:
                            self.fw_direct.removeChain(chain[0], chain[1], chain[2])

    def create_rule(self, chain, rules):
        if chain == 'inbound':
            firewall_chain = self.firewall_in_chain
        else:
            firewall_chain = self.firewall_out_chain
        for rule in rules:
            args = self.rule_args(chain, rule)
            if not self.query_chain_rule(firewall_chain, args):
                ipt_cmd = 'iptables -t {0} -I {1} {2}'.format(self.table, firewall_chain, ' '.join(args))
                if 'DROP' in args:
                    ipt_cmd = 'iptables -t {0} -A {1} {2}'.format(self.table, firewall_chain, ' '.join(args))
                run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                if run_ipt_cmd == 0:
                    if 'DROP' in args:
                        self.prio = 1
                    else:
                        self.prio = 0
                    if not self.query_chain_rule_cfg(firewall_chain, args):
                        self.fw_direct.addRule(self.ipv, self.table, firewall_chain, self.prio, args)

    def remove_rule(self, chain, rules):
        if chain == 'inbound':
            firewall_chain = self.firewall_in_chain
        else:
            firewall_chain = self.firewall_out_chain
        for rule in rules:
            args = self.rule_args(chain, rule)
            if self.query_chain_rule(firewall_chain, args):
                ipt_cmd = 'iptables -t {0} -D {1} {2}'.format(self.table, firewall_chain, ' '.join(args))
                run_ipt_cmd = call(ipt_cmd.split(), stdout=DEVNULL, stderr=STDOUT)
                if run_ipt_cmd == 0:
                    if 'DROP' in args:
                        self.prio = 1
                    else:
                        self.prio = 0
                    if self.query_chain_rule_cfg(firewall_chain, args):
                        self.fw_direct.removeRule(self.ipv, self.table, firewall_chain, self.prio, args)
Пример #17
0
def main():
    module = AnsibleModule(argument_spec=dict(
        service=dict(required=False, type='list', default=[]),
        port=dict(required=False, type='list', default=[]),
        trust=dict(required=False, type='list', default=[]),
        trust_by_mac=dict(required=False, type='list', default=[]),
        masq=dict(required=False, type='list', default=[]),
        masq_by_mac=dict(required=False, type='list', default=[]),
        forward_port=dict(required=False, type='list', default=[]),
        forward_port_by_mac=dict(required=False, type='list', default=[]),
        state=dict(choices=['enabled', 'disabled'], required=True),
    ),
                           required_one_of=([
                               'service', 'port', 'trust', 'trust_by_mac',
                               'masq', 'masq_by_mac', 'forward_prot'
                           ], ),
                           supports_check_mode=True)

    if not HAS_FIREWALLD and not HAS_SYSTEM_CONFIG_FIREWALL:
        module.fail_json(msg='No firewall backend could be imported.')

    service = module.params['service']
    port = []
    for port_proto in module.params['port']:
        _port, _protocol = port_proto.split('/')
        if _protocol is None:
            module.fail_json(msg='improper port format (missing protocol?)')
        port.append((_port, _protocol))
    trust = module.params['trust']
    trust_by_mac = []
    for item in module.params['trust_by_mac']:
        _interface = get_device_for_mac(item)
        if _interface is None:
            module.fail_json(msg='MAC address not found %s' % item)
        trust_by_mac.append(_interface)
    masq = module.params['masq']
    masq_by_mac = []
    for item in module.params['masq_by_mac']:
        _interface = get_device_for_mac(item)
        if _interface is None:
            module.fail_json(msg='MAC address not found %s' % item)
        masq_by_mac.append(_interface)
    forward_port = []
    for item in module.params['forward_port']:
        args = item.split(";")
        if len(args) != 4:
            module.fail_json(msg='improper forward_port format: %s' % item)
        _interface, __port, _to_port, _to_addr = args
        _port, _protocol = __port.split('/')
        if _protocol is None:
            module.fail_json(msg='improper port format (missing protocol?)')
        if _to_port == "":
            _to_port = None
        if _to_addr == "":
            _to_addr = None
        forward_port.append((_interface, _port, _protocol, _to_port, _to_addr))

    forward_port_by_mac = []
    for item in module.params['forward_port_by_mac']:
        args = item.split(";")
        if len(args) != 4:
            module.fail_json(msg='improper forward_port_by_mac format')
        _mac_addr, __port, _to_port, _to_addr = args
        _port, _protocol = __port.split('/')
        if _protocol is None:
            module.fail_json(msg='improper port format (missing protocol?)')
        if _to_port == "":
            _to_port = None
        if _to_addr == "":
            _to_addr = None
        _interface = get_device_for_mac(_mac_addr)
        if _interface is None:
            module.fail_json(msg='MAC address not found %s' % _mac_addr)
        forward_port_by_mac.append(
            (_interface, _port, _protocol, _to_port, _to_addr))
    desired_state = module.params['state']

    if HAS_FIREWALLD:
        fw = FirewallClient()

        def exception_handler(exception_message):
            module.fail_json(msg=exception_message)

        fw.setExceptionHandler(exception_handler)

        if not fw.connected:
            module.fail_json(msg='firewalld service must be running')

        trusted_zone = "trusted"
        external_zone = "external"
        default_zone = fw.getDefaultZone()
        fw_zone = fw.config().getZoneByName(default_zone)
        fw_settings = fw_zone.getSettings()

        changed = False
        changed_zones = {}

        # service
        for item in service:
            if desired_state == "enabled":
                if not fw.queryService(default_zone, item):
                    fw.addService(default_zone, item)
                    changed = True
                if not fw_settings.queryService(item):
                    fw_settings.addService(item)
                    changed = True
                    changed_zones[fw_zone] = fw_settings
            elif desired_state == "disabled":
                if fw.queryService(default_zone, item):
                    fw.removeService(default_zone, item)
                if fw_settings.queryService(item):
                    fw_settings.removeService(item)
                    changed = True
                    changed_zones[fw_zone] = fw_settings

        # port
        for _port, _protocol in port:
            if desired_state == "enabled":
                if not fw.queryPort(default_zone, _port, _protocol):
                    fw.addPort(default_zone, _port, _protocol)
                    changed = True
                if not fw_settings.queryPort(_port, _protocol):
                    fw_settings.addPort(_port, _protocol)
                    changed = True
                    changed_zones[fw_zone] = fw_settings
            elif desired_state == "disabled":
                if fw.queryPort(default_zone, _port, _protocol):
                    fw.removePort(default_zone, _port, _protocol)
                    changed = True
                if fw_settings.queryPort(_port, _protocol):
                    fw_settings.removePort(_port, _protocol)
                    changed = True
                    changed_zones[fw_zone] = fw_settings

        # trust, trust_by_mac
        if len(trust) > 0 or len(trust_by_mac) > 0:
            items = trust
            if len(trust_by_mac) > 0:
                items.extend(trust_by_mac)

            if default_zone != trusted_zone:
                fw_zone = fw.config().getZoneByName(trusted_zone)
                fw_settings = fw_zone.getSettings()

            for item in items:
                if desired_state == "enabled":
                    if try_set_zone_of_interface(trusted_zone, item):
                        changed = True
                    else:
                        if not fw.queryInterface(trusted_zone, item):
                            fw.changeZoneOfInterface(trusted_zone, item)
                            changed = True
                        if not fw_settings.queryInterface(item):
                            fw_settings.addInterface(item)
                            changed = True
                            changed_zones[fw_zone] = fw_settings
                elif desired_state == "disabled":
                    if try_set_zone_of_interface("", item):
                        if module.check_mode:
                            module.exit_json(changed=True)
                    else:
                        if fw.queryInterface(trusted_zone, item):
                            fw.removeInterface(trusted_zone, item)
                            changed = True
                        if fw_settings.queryInterface(item):
                            fw_settings.removeInterface(item)
                            changed = True
                            changed_zones[fw_zone] = fw_settings

        # masq, masq_by_mac
        if len(masq) > 0 or len(masq_by_mac) > 0:
            items = masq
            if len(masq_by_mac) > 0:
                items.extend(masq_by_mac)

            if default_zone != external_zone:
                fw_zone = fw.config().getZoneByName(external_zone)
                fw_settings = fw_zone.getSettings()

            for item in items:
                if desired_state == "enabled":
                    if try_set_zone_of_interface(external_zone, item):
                        changed = True
                    else:
                        if not fw.queryInterface(external_zone, item):
                            fw.changeZoneOfInterface(external_zone, item)
                            changed = True
                        if not fw_settings.queryInterface(item):
                            fw_settings.addInterface(item)
                            changed = True
                            changed_zones[fw_zone] = fw_settings
                elif desired_state == "disabled":
                    if try_set_zone_of_interface("", item):
                        if module.check_mode:
                            module.exit_json(changed=True)
                    else:
                        if fw.queryInterface(external_zone, item):
                            fw.removeInterface(external_zone, item)
                            changed = True
                        if fw_settings.queryInterface(item):
                            fw_settings.removeInterface(item)
                            changed = True
                            changed_zones[fw_zone] = fw_settings

        # forward_port, forward_port_by_mac
        if len(forward_port) > 0 or len(forward_port_by_mac) > 0:
            items = forward_port
            if len(forward_port_by_mac) > 0:
                items.extend(forward_port_by_mac)

            for _interface, _port, _protocol, _to_port, _to_addr in items:
                if _interface != "":
                    _zone = fw.getZoneOfInterface(_interface)
                    if _zone != "" and _zone != default_zone:
                        fw_zone = fw.config().getZoneByName(_zone)
                        fw_settings = fw_zone.getSettings()

                if desired_state == "enabled":
                    if not fw.queryForwardPort(_zone, _port, _protocol,
                                               _to_port, _to_addr):
                        fw.addForwardPort(_zone, _port, _protocol, _to_port,
                                          _to_addr)
                        changed = True
                    if not fw_settings.queryForwardPort(
                            _port, _protocol, _to_port, _to_addr):
                        fw_settings.addForwardPort(_port, _protocol, _to_port,
                                                   _to_addr)
                        changed = True
                        changed_zones[fw_zone] = fw_settings
                elif desired_state == "disabled":
                    if fw.queryForwardPort(_zone, _port, _protocol, _to_port,
                                           _to_addr):
                        fw.removeForwardPort(_zone, _port, _protocol, _to_port,
                                             _to_addr)
                        changed = True
                    if fw_settings.queryForwardPort(_port, _protocol, _to_port,
                                                    _to_addr):
                        fw_settings.removeForwardPort(_port, _protocol,
                                                      _to_port, _to_addr)
                        changed = True
                        changed_zones[fw_zone] = fw_settings

        # apply changes
        if changed:
            for _zone in changed_zones:
                _zone.update(changed_zones[_zone])
            if module.check_mode:
                module.exit_json(changed=True)

    elif HAS_SYSTEM_CONFIG_FIREWALL:
        (config, old_config, _) = fw_lokkit.loadConfig(args=[],
                                                       dbus_parser=True)

        changed = False

        # service
        for item in service:
            if config.services is None:
                config.services = []

            if desired_state == "enabled":
                if item not in config.services:
                    config.services.append(item)
                    changed = True
            elif desired_state == "disabled":
                if item in config.services:
                    config.services.remove(item)
                    changed = True

        # port
        for _port, _protocol in port:
            if config.ports is None:
                config.ports = []

            _range = getPortRange(_port)
            if _range < 0:
                module.fail_json(msg='invalid port definition %s' % _port)
            elif _range is None:
                module.fail_json(msg='port _range is not unique.')
            elif len(_range) == 2 and _range[0] >= _range[1]:
                module.fail_json(msg='invalid port range %s' % _port)
            port_proto = (_range, _protocol)
            if desired_state == "enabled":
                if port_proto not in config.ports:
                    config.ports.append(port_proto)
                    changed = True
            elif desired_state == "disabled":
                if port_proto in config.ports:
                    config.ports.remove(port_proto)
                    changed = True

        # trust, trust_by_mac
        if len(trust) > 0 or len(trust_by_mac) > 0:
            if config.trust is None:
                config.trust = []

            items = trust
            if len(trust_by_mac) > 0:
                items.extend(trust_by_mac)

            for item in items:
                if desired_state == "enabled":
                    if item not in config.trust:
                        config.trust.append(item)
                        changed = True
                elif desired_state == "disabled":
                    if item in config.trust:
                        config.trust.remove(item)
                        changed = True

        # masq, masq_by_mac
        if len(masq) > 0 or len(masq_by_mac) > 0:
            if config.masq is None:
                config.masq = []

            items = masq
            if len(masq_by_mac) > 0:
                items.extend(masq_by_mac)

            for item in items:
                if desired_state == "enabled":
                    if item not in config.masq:
                        config.masq.append(item)
                        changed = True
                elif desired_state == "disabled":
                    if item in config.masq:
                        config.masq.remove(item)
                        changed = True

        # forward_port, forward_port_by_mac
        if len(forward_port) > 0 or len(forward_port_by_mac) > 0:
            if config.forward_port is None:
                config.forward_port = []

            items = forward_port
            if len(forward_port_by_mac) > 0:
                items.extend(forward_port_by_mac)

            for _interface, _port, _protocol, _to_port, _to_addr in items:
                _range = getPortRange(_port)
                if _range < 0:
                    module.fail_json(msg='invalid port definition')
                elif _range is None:
                    module.fail_json(msg='port _range is not unique.')
                elif len(_range) == 2 and _range[0] >= _range[1]:
                    module.fail_json(msg='invalid port range')
                fwd_port = {
                    "if": _interface,
                    "port": _range,
                    "proto": _protocol
                }
                if _to_port is not None:
                    _range = getPortRange(_to_port)
                    if _range < 0:
                        module.fail_json(msg='invalid port definition %s' % \
                                         _to_port)
                    elif _range is None:
                        module.fail_json(msg='port _range is not unique.')
                    elif len(_range) == 2 and _range[0] >= _range[1]:
                        module.fail_json(msg='invalid port range')
                    fwd_port["toport"] = _range
                if _to_addr is not None:
                    fwd_port["toaddr"] = _to_addr

                if desired_state == "enabled":
                    if fwd_port not in config.forward_port:
                        config.forward_port.append(fwd_port)
                        changed = True
                elif desired_state == "disabled":
                    if fwd_port in config.forward_port:
                        config.forward_port.remove(fwd_port)
                        changed = True

        # apply changes
        if changed:
            fw_lokkit.updateFirewall(config, old_config)
            if module.check_mode:
                module.exit_json(changed=True)

    else:
        module.fail_json(msg='No firewalld and system-config-firewall')

    module.exit_json(changed=False)
Пример #18
0
class TestFirewallDInterfaceConfig(unittest.TestCase):
    """
    For testing of permanent changes, ie. those that survive restart:
    """
    def setUp(self):
        unittest.TestCase.setUp(self)
        self.fw = FirewallClient()

    def tearDown(self):
        unittest.TestCase.tearDown(self)

    def test_zones(self):
        """
        /org/fedoraproject/FirewallD1/config
            listZones()
            getZoneByName(String name)
            addZone(String name, Dict of {String, Variant} zone_settings)
        /org/fedoraproject/FirewallD1/config/zone/<id>
           getSettings()
           loadDefaults()
           update()
           rename()
           remove()
        """

        print("\nGetting invalid zone")
        self.assertRaisesRegexp(Exception, 'INVALID_ZONE',
                                self.fw.config().getZoneByName, "dummyname")

        zone_version = "1.0"
        zone_short = "Testing"
        zone_description = "this is just a testing zone"
        zone_target = DEFAULT_ZONE_TARGET
        zone_services = ["dhcpv6-client", "ssh"]
        zone_ports = [("123", "tcp"), ("666-667", "udp")]
        zone_icmpblocks = ["redirect", "echo-reply"]
        zone_masquerade = False
        zone_forward_ports = [("443", "tcp", "441", "192.168.0.2"),
                              ("123", "udp", "321", "192.168.1.1")]
        settings = FirewallClientZoneSettings()
        settings.setVersion(zone_version)
        settings.setShort(zone_short)
        settings.setDescription(zone_description)
        settings.setTarget(zone_target)
        settings.setServices(zone_services)
        settings.setPorts(zone_ports)
        settings.setIcmpBlocks(zone_icmpblocks)
        settings.setMasquerade(zone_masquerade)
        settings.setForwardPorts(zone_forward_ports)

        print("Adding zone with name that already exists")
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT',
                                self.fw.config().addZone, "home", settings)
        print("Adding zone with empty name")
        self.assertRaisesRegexp(Exception, 'INVALID_NAME',
                                self.fw.config().addZone, "", settings)
        zone_name = "test"
        print("Adding proper zone")
        self.fw.config().addZone(zone_name, settings)

        print("Checking the saved (permanent) settings")
        config_zone = self.fw.config().getZoneByName(zone_name)
        self.assertIsInstance(config_zone,
                              firewall.client.FirewallClientConfigZone)
        zone_settings = config_zone.getSettings()
        self.assertIsInstance(zone_settings,
                              firewall.client.FirewallClientZoneSettings)
        self.assertEquals(zone_settings.getVersion(), zone_version)
        self.assertEquals(zone_settings.getShort(), zone_short)
        self.assertEquals(zone_settings.getDescription(), zone_description)
        self.assertEquals(zone_settings.getTarget(), "default")
        self.assertEquals(zone_settings.getServices().sort(),
                          zone_services.sort())
        self.assertEquals(zone_settings.getPorts().sort(), zone_ports.sort())
        self.assertEquals(zone_settings.getIcmpBlocks().sort(),
                          zone_icmpblocks.sort())
        self.assertEquals(zone_settings.getMasquerade(), zone_masquerade)
        self.assertEquals(zone_settings.getForwardPorts().sort(),
                          zone_forward_ports.sort())

        print("Updating settings")
        zone_services.append("mdns")
        zone_settings.setServices(zone_services)
        config_zone.update(zone_settings)

        print("Reloading firewalld")
        self.fw.reload()

        print("Checking of runtime settings")
        self.assertTrue(zone_name in self.fw.getZones())
        self.assertEquals(
            self.fw.getServices(zone_name).sort(), zone_services.sort())
        self.assertEquals(
            self.fw.getPorts(zone_name).sort(), zone_ports.sort())
        self.assertEquals(
            self.fw.getIcmpBlocks(zone_name).sort(), zone_icmpblocks.sort())
        self.assertEquals(self.fw.queryMasquerade(zone_name), zone_masquerade)
        self.assertEquals(
            self.fw.getForwardPorts(zone_name).sort(),
            zone_forward_ports.sort())

        print("Renaming zone to name that already exists")
        config_zone = self.fw.config().getZoneByName(zone_name)
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT', config_zone.rename,
                                "home")
        new_zone_name = "renamed"
        print("Renaming zone '%s' to '%s'" % (zone_name, new_zone_name))
        config_zone.rename(new_zone_name)

        print(
            "Checking whether the zone '%s' is accessible (it shouldn't be)" %
            zone_name)
        self.assertRaisesRegexp(Exception, 'INVALID_ZONE',
                                self.fw.config().getZoneByName, zone_name)
        print("Checking whether the zone '%s' is accessible" % new_zone_name)
        config_zone = self.fw.config().getZoneByName(new_zone_name)
        zone_settings = config_zone.getSettings()
        self.assertEquals(zone_settings.getVersion(), zone_version)
        self.assertEquals(zone_settings.getShort(), zone_short)
        self.assertEquals(zone_settings.getDescription(), zone_description)
        self.assertEquals(zone_settings.getTarget(), "default")
        self.assertEquals(zone_settings.getServices().sort(),
                          zone_services.sort())
        self.assertEquals(zone_settings.getPorts().sort(), zone_ports.sort())
        self.assertEquals(zone_settings.getIcmpBlocks().sort(),
                          zone_icmpblocks.sort())
        self.assertEquals(zone_settings.getMasquerade(), zone_masquerade)
        self.assertEquals(zone_settings.getForwardPorts().sort(),
                          zone_forward_ports.sort())

        print("Removing the zone '%s'" % new_zone_name)
        config_zone.remove()
        print(
            "Checking whether the removed zone is accessible (it shouldn't be)"
        )
        self.assertRaisesRegexp(Exception, 'INVALID_ZONE',
                                self.fw.config().getZoneByName, new_zone_name)

        # TODO test loadDefaults() ?

    def test_services(self):
        """
        /org/fedoraproject/FirewallD1/config
            listServices()
            getServiceByName(String name)
            addService(String name, Dict of {String, Variant} settings)
            
        /org/fedoraproject/FirewallD1/config/service/<id>
           getSettings()
           loadDefaults()
           update()
           rename()
           remove()
        """

        print("\nGetting invalid service")
        self.assertRaisesRegexp(Exception, 'INVALID_SERVICE',
                                self.fw.config().getServiceByName, "dummyname")

        service_version = "1.0"
        service_short = "Testing"
        service_description = "this is just a testing service"
        service_ports = [("123", "tcp"), ("666-667", "udp")]
        service_modules = ["nf_conntrack_tftp"]
        service_destinations = {'ipv4': '1.2.3.4', 'ipv6': 'dead::beef'}
        settings = FirewallClientServiceSettings()  # ["", "", "", [], [], {}]
        settings.setVersion(service_version)
        settings.setShort(service_short)
        settings.setDescription(service_description)
        settings.setPorts(service_ports)
        settings.setModules(service_modules)
        settings.setDestinations(service_destinations)

        print("Adding service with name that already exists")
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT',
                                self.fw.config().addService, "mdns", settings)
        print("Adding service with empty name")
        self.assertRaisesRegexp(Exception, 'INVALID_NAME',
                                self.fw.config().addService, "", settings)
        service_name = "test"
        print("Adding proper service")
        self.fw.config().addService(service_name, settings)

        print("Checking the saved (permanent) settings")
        config_service = self.fw.config().getServiceByName(service_name)
        self.assertIsInstance(config_service,
                              firewall.client.FirewallClientConfigService)
        service_settings = config_service.getSettings()
        self.assertIsInstance(service_settings,
                              firewall.client.FirewallClientServiceSettings)

        print("Updating settings")
        service_modules.append("nf_conntrack_sip")
        service_destinations["ipv6"] = "3ffe:501:ffff::"
        service_settings.setModules(service_modules)
        service_settings.setDestinations(service_destinations)
        config_service.update(service_settings)
        self.assertEquals(service_settings.getVersion(), service_version)
        self.assertEquals(service_settings.getShort(), service_short)
        self.assertEquals(service_settings.getDescription(),
                          service_description)
        self.assertEquals(service_settings.getPorts().sort(),
                          service_ports.sort())
        self.assertEquals(service_settings.getModules().sort(),
                          service_modules.sort())
        self.assertDictEqual(service_settings.getDestinations(),
                             service_destinations)

        print("Renaming service to name that already exists")
        config_service = self.fw.config().getServiceByName(service_name)
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT',
                                config_service.rename, "mdns")
        new_service_name = "renamed"
        print("Renaming service '%s' to '%s'" %
              (service_name, new_service_name))
        config_service.rename(new_service_name)

        print(
            "Checking whether the service '%s' is accessible (it shouldn't be)"
            % service_name)
        self.assertRaisesRegexp(Exception, 'INVALID_SERVICE',
                                self.fw.config().getServiceByName,
                                service_name)
        print("Checking whether the service '%s' is accessible" %
              new_service_name)
        config_service = self.fw.config().getServiceByName(new_service_name)
        service_settings = config_service.getSettings()
        self.assertEquals(service_settings.getVersion(), service_version)
        self.assertEquals(service_settings.getShort(), service_short)
        self.assertEquals(service_settings.getDescription(),
                          service_description)
        self.assertEquals(service_settings.getPorts().sort(),
                          service_ports.sort())
        self.assertEquals(service_settings.getModules().sort(),
                          service_modules.sort())
        self.assertDictEqual(service_settings.getDestinations(),
                             service_destinations)

        print("Removing the service '%s'" % new_service_name)
        config_service.remove()
        print(
            "Checking whether the removed service is accessible (it shouldn't be)"
        )
        self.assertRaisesRegexp(Exception, 'INVALID_SERVICE',
                                self.fw.config().getServiceByName,
                                new_service_name)

        # TODO test loadDefaults() ?

    def test_icmptypes(self):
        """
        /org/fedoraproject/FirewallD1/config
            listIcmpTypes()
            getIcmpTypeByName(String name)
            addIcmpType(String name, Dict of {String, Variant} settings)
            
        /org/fedoraproject/FirewallD1/config/icmptype/<id>
           getSettings()
           loadDefaults()
           update()
           rename()
           remove()
        """
        print("\nGetting invalid icmp-type")
        self.assertRaisesRegexp(Exception, 'INVALID_ICMPTYPE',
                                self.fw.config().getIcmpTypeByName,
                                "dummyname")

        icmptype_version = "1.0"
        icmptype_short = "Testing"
        icmptype_description = "this is just a testing icmp type"
        icmptype_destinations = ['ipv4']
        settings = FirewallClientIcmpTypeSettings()  # ["", "", "", []]
        settings.setVersion(icmptype_version)
        settings.setShort(icmptype_short)
        settings.setDescription(icmptype_description)
        settings.setDestinations(icmptype_destinations)

        print("Adding icmp type with name that already exists")
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT',
                                self.fw.config().addIcmpType, "echo-reply",
                                settings)
        print("Adding icmp type with empty name")
        self.assertRaisesRegexp(Exception, 'INVALID_NAME',
                                self.fw.config().addIcmpType, "", settings)
        icmptype_name = "test"
        print("Adding proper icmp type")
        self.fw.config().addIcmpType(icmptype_name, settings)

        print("Checking the saved (permanent) settings")
        config_icmptype = self.fw.config().getIcmpTypeByName(icmptype_name)
        self.assertIsInstance(config_icmptype,
                              firewall.client.FirewallClientConfigIcmpType)
        icmptype_settings = config_icmptype.getSettings()
        self.assertIsInstance(icmptype_settings,
                              firewall.client.FirewallClientIcmpTypeSettings)

        print("Updating settings")
        icmptype_destinations.append("ipv6")
        icmptype_settings.setDestinations(icmptype_destinations)
        config_icmptype.update(icmptype_settings)
        self.assertEquals(icmptype_settings.getVersion(), icmptype_version)
        self.assertEquals(icmptype_settings.getShort(), icmptype_short)
        self.assertEquals(icmptype_settings.getDescription(),
                          icmptype_description)
        self.assertEquals(icmptype_settings.getDestinations().sort(),
                          icmptype_destinations.sort())

        print("Renaming icmp type to name that already exists")
        config_icmptype = self.fw.config().getIcmpTypeByName(icmptype_name)
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT',
                                config_icmptype.rename, "echo-reply")
        new_icmptype_name = "renamed"
        print("Renaming icmp type '%s' to '%s'" %
              (icmptype_name, new_icmptype_name))
        config_icmptype.rename(new_icmptype_name)

        print(
            "Checking whether the icmp type '%s' is accessible (it shouldn't be)"
            % icmptype_name)
        self.assertRaisesRegexp(Exception, 'INVALID_ICMPTYPE',
                                self.fw.config().getIcmpTypeByName,
                                icmptype_name)
        print("Checking whether the icmp type '%s' is accessible" %
              new_icmptype_name)
        config_icmptype = self.fw.config().getIcmpTypeByName(new_icmptype_name)
        icmptype_settings = config_icmptype.getSettings()
        self.assertEquals(icmptype_settings.getVersion(), icmptype_version)
        self.assertEquals(icmptype_settings.getShort(), icmptype_short)
        self.assertEquals(icmptype_settings.getDescription(),
                          icmptype_description)
        self.assertEquals(icmptype_settings.getDestinations().sort(),
                          icmptype_destinations.sort())

        print("Removing the icmp type '%s'" % new_icmptype_name)
        config_icmptype.remove()
        print(
            "Checking whether the removed icmp type is accessible (it shouldn't be)"
        )
        self.assertRaisesRegexp(Exception, 'INVALID_ICMPTYPE',
                                self.fw.config().getIcmpTypeByName,
                                new_icmptype_name)
Пример #19
0
class TestFirewallDInterfaceConfig(unittest.TestCase):
    """
    For testing of permanent changes, ie. those that survive restart:
    """
    def setUp(self):
        unittest.TestCase.setUp(self)
        self.fw = FirewallClient()

    def tearDown(self):
        unittest.TestCase.tearDown(self)

    def test_zones(self):
        """
        /org/fedoraproject/FirewallD1/config
            listZones()
            getZoneByName(String name)
            addZone(String name, Dict of {String, Variant} zone_settings)
        /org/fedoraproject/FirewallD1/config/zone/<id>
           getSettings()
           loadDefaults()
           update()
           rename()
           remove()
        """

        print ("\nGetting invalid zone")
        self.assertRaisesRegexp(Exception, 'INVALID_ZONE', self.fw.config().getZoneByName, "dummyname")

        zone_version = "1.0"
        zone_short = "Testing"
        zone_description = "this is just a testing zone"
        zone_target = DEFAULT_ZONE_TARGET
        zone_services = ["dhcpv6-client", "ssh"]
        zone_ports = [("123", "tcp"), ("666-667", "udp")]
        zone_icmpblocks = ["redirect", "echo-reply"]
        zone_masquerade = False
        zone_forward_ports = [("443", "tcp", "441", "192.168.0.2"), ("123", "udp", "321", "192.168.1.1")]
        settings = FirewallClientZoneSettings()
        settings.setVersion(zone_version)
        settings.setShort(zone_short)
        settings.setDescription(zone_description)
        settings.setTarget(zone_target)
        settings.setServices(zone_services)
        settings.setPorts(zone_ports)
        settings.setIcmpBlocks(zone_icmpblocks)
        settings.setMasquerade(zone_masquerade)
        settings.setForwardPorts(zone_forward_ports)

        print ("Adding zone with name that already exists")
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT', self.fw.config().addZone, "home", settings)
        print ("Adding zone with empty name")
        self.assertRaisesRegexp(Exception, 'INVALID_NAME', self.fw.config().addZone, "", settings)
        zone_name = "test"
        print ("Adding proper zone")
        self.fw.config().addZone (zone_name, settings)

        print ("Checking the saved (permanent) settings")
        config_zone = self.fw.config().getZoneByName(zone_name)
        self.assertIsInstance(config_zone, firewall.client.FirewallClientConfigZone)
        zone_settings = config_zone.getSettings()
        self.assertIsInstance(zone_settings, firewall.client.FirewallClientZoneSettings)
        self.assertEquals(zone_settings.getVersion(), zone_version)
        self.assertEquals(zone_settings.getShort(), zone_short)
        self.assertEquals(zone_settings.getDescription(), zone_description)
        self.assertEquals(zone_settings.getTarget(), zone_target)
        self.assertEquals(zone_settings.getServices().sort(), zone_services.sort())
        self.assertEquals(zone_settings.getPorts().sort(), zone_ports.sort())
        self.assertEquals(zone_settings.getIcmpBlocks().sort(), zone_icmpblocks.sort())
        self.assertEquals(zone_settings.getMasquerade(), zone_masquerade)
        self.assertEquals(zone_settings.getForwardPorts().sort(), zone_forward_ports.sort())

        print ("Updating settings")
        zone_services.append("mdns")
        zone_settings.setServices(zone_services)
        config_zone.update(zone_settings)

        print ("Reloading firewalld")
        self.fw.reload()

        print ("Checking of runtime settings")
        self.assertTrue(zone_name in self.fw.getZones())
        self.assertEquals(self.fw.getServices(zone_name).sort(), zone_services.sort())
        self.assertEquals(self.fw.getPorts(zone_name).sort(), zone_ports.sort())
        self.assertEquals(self.fw.getIcmpBlocks(zone_name).sort(), zone_icmpblocks.sort())
        self.assertEquals(self.fw.queryMasquerade(zone_name), zone_masquerade)
        self.assertEquals(self.fw.getForwardPorts(zone_name).sort(), zone_forward_ports.sort())

        print ("Renaming zone to name that already exists")
        config_zone = self.fw.config().getZoneByName(zone_name)
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT', config_zone.rename, "home")
        new_zone_name = "renamed"
        print ("Renaming zone '%s' to '%s'" % (zone_name, new_zone_name))
        config_zone.rename(new_zone_name)

        print ("Checking whether the zone '%s' is accessible (it shouldn't be)" % zone_name)
        self.assertRaisesRegexp(Exception, 'INVALID_ZONE', self.fw.config().getZoneByName, zone_name)
        print ("Checking whether the zone '%s' is accessible" % new_zone_name)
        config_zone = self.fw.config().getZoneByName(new_zone_name)
        zone_settings = config_zone.getSettings()
        self.assertEquals(zone_settings.getVersion(), zone_version)
        self.assertEquals(zone_settings.getShort(), zone_short)
        self.assertEquals(zone_settings.getDescription(), zone_description)
        self.assertEquals(zone_settings.getTarget(), zone_target)
        self.assertEquals(zone_settings.getServices().sort(), zone_services.sort())
        self.assertEquals(zone_settings.getPorts().sort(), zone_ports.sort())
        self.assertEquals(zone_settings.getIcmpBlocks().sort(), zone_icmpblocks.sort())
        self.assertEquals(zone_settings.getMasquerade(), zone_masquerade)
        self.assertEquals(zone_settings.getForwardPorts().sort(), zone_forward_ports.sort())

        print ("Removing the zone '%s'" % new_zone_name)
        config_zone.remove()
        print ("Checking whether the removed zone is accessible (it shouldn't be)")
        self.assertRaisesRegexp(Exception, 'INVALID_ZONE', self.fw.config().getZoneByName, new_zone_name)

        # TODO test loadDefaults() ?

    def test_services(self):
        """
        /org/fedoraproject/FirewallD1/config
            listServices()
            getServiceByName(String name)
            addService(String name, Dict of {String, Variant} settings)
            
        /org/fedoraproject/FirewallD1/config/service/<id>
           getSettings()
           loadDefaults()
           update()
           rename()
           remove()
        """

        print ("\nGetting invalid service")
        self.assertRaisesRegexp(Exception, 'INVALID_SERVICE', self.fw.config().getServiceByName, "dummyname")

        service_version = "1.0"
        service_short = "Testing"
        service_description = "this is just a testing service"
        service_ports = [("123", "tcp"), ("666-667", "udp")]
        service_modules = ["nf_test_first", "nf_test_second"]
        service_destinations = {'ipv4': '1.2.3.4', 'ipv6': 'dead::beef'}
        settings = FirewallClientServiceSettings() # ["", "", "", [], [], {}]
        settings.setVersion(service_version)
        settings.setShort(service_short)
        settings.setDescription(service_description)
        settings.setPorts(service_ports)
        settings.setModules(service_modules)
        settings.setDestinations(service_destinations)

        print ("Adding service with name that already exists")
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT', self.fw.config().addService, "mdns", settings)
        print ("Adding service with empty name")
        self.assertRaisesRegexp(Exception, 'INVALID_NAME', self.fw.config().addService, "", settings)
        service_name = "test"
        print ("Adding proper service")
        self.fw.config().addService (service_name, settings)

        print ("Checking the saved (permanent) settings")
        config_service = self.fw.config().getServiceByName(service_name)
        self.assertIsInstance(config_service, firewall.client.FirewallClientConfigService)
        service_settings = config_service.getSettings()
        self.assertIsInstance(service_settings, firewall.client.FirewallClientServiceSettings)

        print ("Updating settings")
        service_modules.append("nf_test_third")
        service_destinations["ipv6"] = "3ffe:501:ffff::"
        service_settings.setModules(service_modules)
        service_settings.setDestinations(service_destinations)
        config_service.update(service_settings)
        self.assertEquals(service_settings.getVersion(), service_version)
        self.assertEquals(service_settings.getShort(), service_short)
        self.assertEquals(service_settings.getDescription(), service_description)
        self.assertEquals(service_settings.getPorts().sort(), service_ports.sort())
        self.assertEquals(service_settings.getModules().sort(), service_modules.sort())
        self.assertDictEqual(service_settings.getDestinations(), service_destinations)

        print ("Renaming service to name that already exists")
        config_service = self.fw.config().getServiceByName(service_name)
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT', config_service.rename, "mdns")
        new_service_name = "renamed"
        print ("Renaming service '%s' to '%s'" % (service_name, new_service_name))
        config_service.rename(new_service_name)

        print ("Checking whether the service '%s' is accessible (it shouldn't be)" % service_name)
        self.assertRaisesRegexp(Exception, 'INVALID_SERVICE', self.fw.config().getServiceByName, service_name)
        print ("Checking whether the service '%s' is accessible" % new_service_name)
        config_service = self.fw.config().getServiceByName(new_service_name)
        service_settings = config_service.getSettings()
        self.assertEquals(service_settings.getVersion(), service_version)
        self.assertEquals(service_settings.getShort(), service_short)
        self.assertEquals(service_settings.getDescription(), service_description)
        self.assertEquals(service_settings.getPorts().sort(), service_ports.sort())
        self.assertEquals(service_settings.getModules().sort(), service_modules.sort())
        self.assertDictEqual(service_settings.getDestinations(), service_destinations)

        print ("Removing the service '%s'" % new_service_name)
        config_service.remove()
        print ("Checking whether the removed service is accessible (it shouldn't be)")
        self.assertRaisesRegexp(Exception, 'INVALID_SERVICE', self.fw.config().getServiceByName, new_service_name)

        # TODO test loadDefaults() ?

    def test_icmptypes(self):
        """
        /org/fedoraproject/FirewallD1/config
            listIcmpTypes()
            getIcmpTypeByName(String name)
            addIcmpType(String name, Dict of {String, Variant} settings)
            
        /org/fedoraproject/FirewallD1/config/icmptype/<id>
           getSettings()
           loadDefaults()
           update()
           rename()
           remove()
        """
        print ("\nGetting invalid icmp-type")
        self.assertRaisesRegexp(Exception, 'INVALID_ICMPTYPE', self.fw.config().getIcmpTypeByName, "dummyname")

        icmptype_version = "1.0"
        icmptype_short = "Testing"
        icmptype_description = "this is just a testing icmp type"
        icmptype_destinations = ['ipv4']
        settings = FirewallClientIcmpTypeSettings() # ["", "", "", []]
        settings.setVersion(icmptype_version)
        settings.setShort(icmptype_short)
        settings.setDescription(icmptype_description)
        settings.setDestinations(icmptype_destinations)

        print ("Adding icmp type with name that already exists")
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT', self.fw.config().addIcmpType, "echo-reply", settings)
        print ("Adding icmp type with empty name")
        self.assertRaisesRegexp(Exception, 'INVALID_NAME', self.fw.config().addIcmpType, "", settings)
        icmptype_name = "test"
        print ("Adding proper icmp type")
        self.fw.config().addIcmpType (icmptype_name, settings)

        print ("Checking the saved (permanent) settings")
        config_icmptype = self.fw.config().getIcmpTypeByName(icmptype_name)
        self.assertIsInstance(config_icmptype, firewall.client.FirewallClientConfigIcmpType)
        icmptype_settings = config_icmptype.getSettings()
        self.assertIsInstance(icmptype_settings, firewall.client.FirewallClientIcmpTypeSettings)

        print ("Updating settings")
        icmptype_destinations.append("ipv6")
        icmptype_settings.setDestinations(icmptype_destinations)
        config_icmptype.update(icmptype_settings)
        self.assertEquals(icmptype_settings.getVersion(), icmptype_version)
        self.assertEquals(icmptype_settings.getShort(), icmptype_short)
        self.assertEquals(icmptype_settings.getDescription(), icmptype_description)
        self.assertEquals(icmptype_settings.getDestinations().sort(), icmptype_destinations.sort())

        print ("Renaming icmp type to name that already exists")
        config_icmptype = self.fw.config().getIcmpTypeByName(icmptype_name)
        self.assertRaisesRegexp(Exception, 'NAME_CONFLICT', config_icmptype.rename, "echo-reply")
        new_icmptype_name = "renamed"
        print ("Renaming icmp type '%s' to '%s'" % (icmptype_name, new_icmptype_name))
        config_icmptype.rename(new_icmptype_name)

        print ("Checking whether the icmp type '%s' is accessible (it shouldn't be)" % icmptype_name)
        self.assertRaisesRegexp(Exception, 'INVALID_ICMPTYPE', self.fw.config().getIcmpTypeByName, icmptype_name)
        print ("Checking whether the icmp type '%s' is accessible" % new_icmptype_name)
        config_icmptype = self.fw.config().getIcmpTypeByName(new_icmptype_name)
        icmptype_settings = config_icmptype.getSettings()
        self.assertEquals(icmptype_settings.getVersion(), icmptype_version)
        self.assertEquals(icmptype_settings.getShort(), icmptype_short)
        self.assertEquals(icmptype_settings.getDescription(), icmptype_description)
        self.assertEquals(icmptype_settings.getDestinations().sort(), icmptype_destinations.sort())

        print ("Removing the icmp type '%s'" % new_icmptype_name)
        config_icmptype.remove()
        print ("Checking whether the removed icmp type is accessible (it shouldn't be)")
        self.assertRaisesRegexp(Exception, 'INVALID_ICMPTYPE', self.fw.config().getIcmpTypeByName, new_icmptype_name)
Пример #20
0
class FirewallD:
    def __init__(self):
        try:
            from firewall.client import FirewallClient
            self._fw = FirewallClient()
            if not self._fw.connected:
                debugprint("FirewallD seems to be installed but not running")
                self._fw = None
                self._zone = None
                self.running = False
                return
            zone_name = self._get_active_zone()
            if zone_name:
                self._zone = self._fw.config().getZoneByName(zone_name)
            else:
                self._zone = None
            self.running = True
            debugprint("Using /org/fedoraproject/FirewallD1")
        except (ImportError, dbus.exceptions.DBusException):
            self._fw = None
            self._zone = None
            self.running = False

    def _get_active_zone(self):
        zones = self._fw.getActiveZones().keys()
        if not zones:
            debugprint("FirewallD: no changeable zone")
            return None
        elif len(zones) == 1:
            # most probable case
            return zones[0]
        else:
            # Do we need to handle the 'more active zones' case ?
            # It's quite unlikely case because that would mean that more
            # network connections are up and running and they are
            # in different network zones at the same time.
            debugprint("FirewallD returned more zones, taking first one")
            return zones[0]

    def _get_fw_data(self, reply_handler=None, error_handler=None):
        try:
            debugprint("%s in _get_fw_data: _fw_data is %s" %
                       (self, repr(self._fw_data.getServices())))
            if self._fw_data:
                debugprint("Using cached firewall data")
                if reply_handler:
                    reply_handler(self._fw_data)
        except AttributeError:
            try:
                self._fw_data = self._zone.getSettings()
                debugprint("Firewall data obtained")
                if reply_handler:
                    reply_handler(self._fw_data)
            except (dbus.exceptions.DBusException, AttributeError,
                    ValueError) as e:
                self._fw_data = None
                debugprint("Exception examining firewall")
                if error_handler:
                    error_handler(e)

        return self._fw_data

    def read(self, reply_handler=None, error_handler=None):
        if reply_handler:
            self._get_fw_data(reply_handler, error_handler)
        else:
            self._get_fw_data()

    def write(self):
        try:
            if self._zone:
                self._zone.update(self._fw_data)
            self._fw.reload()
        except dbus.exceptions.DBusException:
            nonfatalException()

    def add_service(self, service):
        if not self._get_fw_data():
            return

        self._fw_data.addService(service)

    def check_ipp_client_allowed(self):
        if not self._get_fw_data():
            return True

        return (IPP_CLIENT_SERVICE in self._fw_data.getServices()
                or [IPP_CLIENT_PORT, IPP_CLIENT_PROTOCOL
                    ] in self._fw_data.getPorts())

    def check_ipp_server_allowed(self):
        if not self._get_fw_data():
            return True

        return (IPP_SERVER_SERVICE in self._fw_data.getServices()
                or [IPP_SERVER_PORT, IPP_SERVER_PROTOCOL
                    ] in self._fw_data.getPorts())

    def check_samba_client_allowed(self):
        if not self._get_fw_data():
            return True

        return (SAMBA_CLIENT_SERVICE in self._fw_data.getServices())

    def check_mdns_allowed(self):
        if not self._get_fw_data():
            return True

        return (MDNS_SERVICE in self._fw_data.getServices()
                or [MDNS_PORT, MDNS_PROTOCOL] in self._fw_data.getPorts())
Пример #21
0
 def setUp(self):
     unittest.TestCase.setUp(self)
     self.fw = FirewallClient()
Пример #22
0
def main():
    module = AnsibleModule(
        argument_spec=dict(
            service=dict(required=False, type="list", default=[]),
            port=dict(required=False, type="list", default=[]),
            trust=dict(required=False, type="list", default=[]),
            trust_by_mac=dict(required=False, type="list", default=[]),
            masq=dict(required=False, type="list", default=[]),
            masq_by_mac=dict(required=False, type="list", default=[]),
            forward_port=dict(required=False, type="list", default=[]),
            forward_port_by_mac=dict(required=False, type="list", default=[]),
            zone=dict(required=False, type="str", default=None),
            state=dict(choices=["enabled", "disabled"], required=True),
        ),
        required_one_of=([
            "service",
            "port",
            "trust",
            "trust_by_mac",
            "masq",
            "masq_by_mac",
            "forward_prot",
        ], ),
        supports_check_mode=True,
    )

    if not HAS_FIREWALLD and not HAS_SYSTEM_CONFIG_FIREWALL:
        module.fail_json(msg="No firewall backend could be imported.")

    service = module.params["service"]
    port = []
    for port_proto in module.params["port"]:
        _port, _protocol = port_proto.split("/")
        if _protocol is None:
            module.fail_json(msg="improper port format (missing protocol?)")
        port.append((_port, _protocol))
    trust = module.params["trust"]
    trust_by_mac = []
    for item in module.params["trust_by_mac"]:
        _interface = get_device_for_mac(item)
        if _interface is None:
            module.fail_json(msg="MAC address not found %s" % item)
        trust_by_mac.append(_interface)
    masq = module.params["masq"]
    masq_by_mac = []
    for item in module.params["masq_by_mac"]:
        _interface = get_device_for_mac(item)
        if _interface is None:
            module.fail_json(msg="MAC address not found %s" % item)
        masq_by_mac.append(_interface)
    forward_port = []
    for item in module.params["forward_port"]:
        args = item.split(";")
        if len(args) == 4:
            _interface, __port, _to_port, _to_addr = args
        elif len(args) == 3:
            _interface = ""
            __port, _to_port, _to_addr = args
        else:
            module.fail_json(msg="improper forward_port format: %s" % item)
        _port, _protocol = __port.split("/")
        if _protocol is None:
            module.fail_json(
                msg="improper forward port format (missing protocol?)")
        if _to_port == "":
            _to_port = None
        if _to_addr == "":
            _to_addr = None
        forward_port.append((_interface, _port, _protocol, _to_port, _to_addr))

    forward_port_by_mac = []
    for item in module.params["forward_port_by_mac"]:
        args = item.split(";")
        if len(args) != 4:
            module.fail_json(msg="improper forward_port_by_mac format")
        _mac_addr, __port, _to_port, _to_addr = args
        _port, _protocol = __port.split("/")
        if _protocol is None:
            module.fail_json(
                msg="improper forward_port_by_mac format (missing protocol?)")
        if _to_port == "":
            _to_port = None
        if _to_addr == "":
            _to_addr = None
        _interface = get_device_for_mac(_mac_addr)
        if _interface is None:
            module.fail_json(msg="MAC address not found %s" % _mac_addr)
        forward_port_by_mac.append(
            (_interface, _port, _protocol, _to_port, _to_addr))
    zone = module.params["zone"]
    if HAS_SYSTEM_CONFIG_FIREWALL and zone is not None:
        module.fail_json(
            msg="Zone can not be used with system-config-firewall/lokkit.")
    desired_state = module.params["state"]

    if HAS_FIREWALLD:
        fw = FirewallClient()

        def exception_handler(exception_message):
            module.fail_json(msg=exception_message)

        fw.setExceptionHandler(exception_handler)

        if not fw.connected:
            module.fail_json(msg="firewalld service must be running")

        trusted_zone = "trusted"
        external_zone = "external"
        if zone is not None:
            if zone not in fw.getZones():
                module.fail_json(msg="Runtime zone '%s' does not exist." %
                                 zone)
            if zone not in fw.config().getZoneNames():
                module.fail_json(msg="Permanent zone '%s' does not exist." %
                                 zone)
        else:
            zone = fw.getDefaultZone()
        fw_zone = fw.config().getZoneByName(zone)
        fw_settings = fw_zone.getSettings()

        changed = False
        changed_zones = {}

        # service
        for item in service:
            if desired_state == "enabled":
                if not fw.queryService(zone, item):
                    fw.addService(zone, item)
                    changed = True
                if not fw_settings.queryService(item):
                    fw_settings.addService(item)
                    changed = True
                    changed_zones[fw_zone] = fw_settings
            elif desired_state == "disabled":
                if fw.queryService(zone, item):
                    fw.removeService(zone, item)
                if fw_settings.queryService(item):
                    fw_settings.removeService(item)
                    changed = True
                    changed_zones[fw_zone] = fw_settings

        # port
        for _port, _protocol in port:
            if desired_state == "enabled":
                if not fw.queryPort(zone, _port, _protocol):
                    fw.addPort(zone, _port, _protocol)
                    changed = True
                if not fw_settings.queryPort(_port, _protocol):
                    fw_settings.addPort(_port, _protocol)
                    changed = True
                    changed_zones[fw_zone] = fw_settings
            elif desired_state == "disabled":
                if fw.queryPort(zone, _port, _protocol):
                    fw.removePort(zone, _port, _protocol)
                    changed = True
                if fw_settings.queryPort(_port, _protocol):
                    fw_settings.removePort(_port, _protocol)
                    changed = True
                    changed_zones[fw_zone] = fw_settings

        # trust, trust_by_mac
        if len(trust) > 0 or len(trust_by_mac) > 0:
            items = trust
            if len(trust_by_mac) > 0:
                items.extend(trust_by_mac)

            if zone != trusted_zone:
                _fw_zone = fw.config().getZoneByName(trusted_zone)
                if _fw_zone in changed_zones:
                    _fw_settings = changed_zones[_fw_zone]
                else:
                    _fw_settings = _fw_zone.getSettings()
            else:
                _fw_zone = fw_zone
                _fw_settings = fw_settings

            for item in items:
                if desired_state == "enabled":
                    if try_set_zone_of_interface(trusted_zone, item):
                        changed = True
                    else:
                        if not fw.queryInterface(trusted_zone, item):
                            fw.changeZoneOfInterface(trusted_zone, item)
                            changed = True
                        if not _fw_settings.queryInterface(item):
                            _fw_settings.addInterface(item)
                            changed = True
                            changed_zones[_fw_zone] = _fw_settings
                elif desired_state == "disabled":
                    if try_set_zone_of_interface("", item):
                        if module.check_mode:
                            module.exit_json(changed=True)
                    else:
                        if fw.queryInterface(trusted_zone, item):
                            fw.removeInterface(trusted_zone, item)
                            changed = True
                        if _fw_settings.queryInterface(item):
                            _fw_settings.removeInterface(item)
                            changed = True
                            changed_zones[_fw_zone] = _fw_settings

        # masq, masq_by_mac
        if len(masq) > 0 or len(masq_by_mac) > 0:
            items = masq
            if len(masq_by_mac) > 0:
                items.extend(masq_by_mac)

            if zone != external_zone:
                _fw_zone = fw.config().getZoneByName(external_zone)
                if _fw_zone in changed_zones:
                    _fw_settings = changed_zones[_fw_zone]
                else:
                    _fw_settings = _fw_zone.getSettings()
            else:
                _fw_zone = fw_zone
                _fw_settings = fw_settings

            for item in items:
                if desired_state == "enabled":
                    if try_set_zone_of_interface(external_zone, item):
                        changed = True
                    else:
                        if not fw.queryInterface(external_zone, item):
                            fw.changeZoneOfInterface(external_zone, item)
                            changed = True
                        if not _fw_settings.queryInterface(item):
                            _fw_settings.addInterface(item)
                            changed = True
                            changed_zones[_fw_zone] = _fw_settings
                elif desired_state == "disabled":
                    if try_set_zone_of_interface("", item):
                        if module.check_mode:
                            module.exit_json(changed=True)
                    else:
                        if fw.queryInterface(external_zone, item):
                            fw.removeInterface(external_zone, item)
                            changed = True
                        if _fw_settings.queryInterface(item):
                            _fw_settings.removeInterface(item)
                            changed = True
                            changed_zones[_fw_zone] = _fw_settings

        # forward_port, forward_port_by_mac
        if len(forward_port) > 0 or len(forward_port_by_mac) > 0:
            items = forward_port
            if len(forward_port_by_mac) > 0:
                items.extend(forward_port_by_mac)

            for _interface, _port, _protocol, _to_port, _to_addr in items:
                if _interface != "":
                    _zone = fw.getZoneOfInterface(_interface)
                else:
                    _zone = zone
                if _zone != "" and _zone != zone:
                    _fw_zone = fw.config().getZoneByName(_zone)
                    if _fw_zone in changed_zones:
                        _fw_settings = changed_zones[_fw_zone]
                    else:
                        _fw_settings = _fw_zone.getSettings()
                else:
                    _fw_zone = fw_zone
                    _fw_settings = fw_settings

                if desired_state == "enabled":
                    if not fw.queryForwardPort(_zone, _port, _protocol,
                                               _to_port, _to_addr):
                        fw.addForwardPort(_zone, _port, _protocol, _to_port,
                                          _to_addr)
                        changed = True
                    if not _fw_settings.queryForwardPort(
                            _port, _protocol, _to_port, _to_addr):
                        _fw_settings.addForwardPort(_port, _protocol, _to_port,
                                                    _to_addr)
                        changed = True
                        changed_zones[_fw_zone] = _fw_settings
                elif desired_state == "disabled":
                    if fw.queryForwardPort(_zone, _port, _protocol, _to_port,
                                           _to_addr):
                        fw.removeForwardPort(_zone, _port, _protocol, _to_port,
                                             _to_addr)
                        changed = True
                    if _fw_settings.queryForwardPort(_port, _protocol,
                                                     _to_port, _to_addr):
                        _fw_settings.removeForwardPort(_port, _protocol,
                                                       _to_port, _to_addr)
                        changed = True
                        changed_zones[_fw_zone] = _fw_settings

        # apply changes
        if changed:
            for _zone in changed_zones:
                _zone.update(changed_zones[_zone])
            module.exit_json(changed=True)

    elif HAS_SYSTEM_CONFIG_FIREWALL:
        (config, old_config, _) = fw_lokkit.loadConfig(args=[],
                                                       dbus_parser=True)

        changed = False

        # service
        for item in service:
            if config.services is None:
                config.services = []

            if desired_state == "enabled":
                if item not in config.services:
                    config.services.append(item)
                    changed = True
            elif desired_state == "disabled":
                if item in config.services:
                    config.services.remove(item)
                    changed = True

        # port
        for _port, _protocol in port:
            if config.ports is None:
                config.ports = []

            _range = getPortRange(_port)
            if _range < 0:
                module.fail_json(msg="invalid port definition %s" % _port)
            elif _range is None:
                module.fail_json(msg="port _range is not unique.")
            elif len(_range) == 2 and _range[0] >= _range[1]:
                module.fail_json(msg="invalid port range %s" % _port)
            port_proto = (_range, _protocol)
            if desired_state == "enabled":
                if port_proto not in config.ports:
                    config.ports.append(port_proto)
                    changed = True
            elif desired_state == "disabled":
                if port_proto in config.ports:
                    config.ports.remove(port_proto)
                    changed = True

        # trust, trust_by_mac
        if len(trust) > 0 or len(trust_by_mac) > 0:
            if config.trust is None:
                config.trust = []

            items = trust
            if len(trust_by_mac) > 0:
                items.extend(trust_by_mac)

            for item in items:
                if desired_state == "enabled":
                    if item not in config.trust:
                        config.trust.append(item)
                        changed = True
                elif desired_state == "disabled":
                    if item in config.trust:
                        config.trust.remove(item)
                        changed = True

        # masq, masq_by_mac
        if len(masq) > 0 or len(masq_by_mac) > 0:
            if config.masq is None:
                config.masq = []

            items = masq
            if len(masq_by_mac) > 0:
                items.extend(masq_by_mac)

            for item in items:
                if desired_state == "enabled":
                    if item not in config.masq:
                        config.masq.append(item)
                        changed = True
                elif desired_state == "disabled":
                    if item in config.masq:
                        config.masq.remove(item)
                        changed = True

        # forward_port, forward_port_by_mac
        if len(forward_port) > 0 or len(forward_port_by_mac) > 0:
            if config.forward_port is None:
                config.forward_port = []

            items = forward_port
            if len(forward_port_by_mac) > 0:
                items.extend(forward_port_by_mac)

            for _interface, _port, _protocol, _to_port, _to_addr in items:
                _range = getPortRange(_port)
                if _range < 0:
                    module.fail_json(msg="invalid port definition")
                elif _range is None:
                    module.fail_json(msg="port _range is not unique.")
                elif len(_range) == 2 and _range[0] >= _range[1]:
                    module.fail_json(msg="invalid port range")
                fwd_port = {
                    "if": _interface,
                    "port": _range,
                    "proto": _protocol
                }
                if _to_port is not None:
                    _range = getPortRange(_to_port)
                    if _range < 0:
                        module.fail_json(msg="invalid port definition %s" %
                                         _to_port)
                    elif _range is None:
                        module.fail_json(msg="port _range is not unique.")
                    elif len(_range) == 2 and _range[0] >= _range[1]:
                        module.fail_json(msg="invalid port range")
                    fwd_port["toport"] = _range
                if _to_addr is not None:
                    fwd_port["toaddr"] = _to_addr

                if desired_state == "enabled":
                    if fwd_port not in config.forward_port:
                        config.forward_port.append(fwd_port)
                        changed = True
                elif desired_state == "disabled":
                    if fwd_port in config.forward_port:
                        config.forward_port.remove(fwd_port)
                        changed = True

        # apply changes
        if changed:
            fw_lokkit.updateFirewall(config, old_config)
            if module.check_mode:
                module.exit_json(changed=True)

    else:
        module.fail_json(msg="No firewalld and system-config-firewall")

    module.exit_json(changed=False)
Пример #23
0
    def installFirewall(self):
        """install firewall"""
        log.debug1("%s.installFirewall()", self._log_prefix)

        # are there any firewall settings to apply?
        if len(self._settings["firewall"]["services"]) + \
           len(self._settings["firewall"]["ports"]) < 1:
            return

        # create firewall client
        fw = FirewallClient()
        log.debug2("TRACE: Firewall client created")

        # Make sure firewalld is running by getting the
        # default zone
        try:
            default_zone = fw.getDefaultZone()
        except DBusException:
            # firewalld is not running
            log.error("Firewalld is not running or rolekit cannot access it")
            raise

        # save changes to the firewall
        try:
            fw_changes = self._settings["firewall-changes"]
        except KeyError:
            fw_changes = { }

        log.debug2("TRACE: Checking for zones: {}".format(self._settings))

        try:
            zones = self._settings["firewall_zones"]
        except KeyError:
            zones = []

        # if firewall_zones setting is empty, use default zone
        if len(zones) < 1:
            zones = [ default_zone ]

        log.debug2("TRACE: default zone {}".format(zones[0]))

        for zone in zones:
            log.debug2("TRACE: Processing zone {0}".format(zone))
            # get permanent zone settings, run-time settings do not need a
            # special treatment
            z_perm = fw.config().getZoneByName(zone).getSettings()

            for service in self._settings["firewall"]["services"]:
                try:
                    fw.addService(zone, service, 0)
                except Exception as e:
                    if not "ALREADY_ENABLED" in str(e):
                        raise
                else:
                    fw_changes.setdefault(zone, {}).setdefault("services", {}).setdefault(service, []).append("runtime")

                if not z_perm.queryService(service):
                    z_perm.addService(service)
                    fw_changes.setdefault(zone, {}).setdefault("services", {}).setdefault(service, []).append("permanent")

            for port_proto in self._settings["firewall"]["ports"]:
                port, proto = port_proto.split("/")

                try:
                    fw.addPort(zone, port, proto, 0)
                except Exception as e:
                    if not "ALREADY_ENABLED" in str(e):
                        raise
                else:
                    fw_changes.setdefault(zone, {}).setdefault("ports", {}).setdefault(port_proto, []).append("runtime")

                if not z_perm.queryPort(port, proto):
                    z_perm.addPort(port, proto)
                    fw_changes.setdefault(zone, {}).setdefault("ports", {}).setdefault(port_proto, []).append("permanent")

            fw.config().getZoneByName(zone).update(z_perm)

        self._settings["firewall-changes"] = fw_changes
        self._settings.write()
Пример #24
0
def main():
    global module

    ## make module global so we don't have to pass it to action_handler every
    ## function call
    global module
    module = AnsibleModule(argument_spec=dict(
        service=dict(required=False, default=None),
        port=dict(required=False, default=None),
        rich_rule=dict(required=False, default=None),
        zone=dict(required=False, default=None),
        immediate=dict(type='bool', default=False),
        source=dict(required=False, default=None),
        permanent=dict(type='bool', required=False, default=None),
        state=dict(choices=['enabled', 'disabled'], required=True),
        timeout=dict(type='int', required=False, default=0),
        interface=dict(required=False, default=None),
        masquerade=dict(required=False, default=None),
        offline=dict(type='bool', required=False, default=None),
    ),
                           supports_check_mode=True)

    ## Handle running (online) daemon vs non-running (offline) daemon
    global fw
    global fw_offline
    global Rich_Rule
    global FirewallClientZoneSettings

    ## Imports
    try:
        import firewall.config
        FW_VERSION = firewall.config.VERSION

        from firewall.client import Rich_Rule
        from firewall.client import FirewallClient
        fw = None
        fw_offline = False

        try:
            fw = FirewallClient()
            fw.getDefaultZone()
        except AttributeError:
            ## Firewalld is not currently running, permanent-only operations

            ## Import other required parts of the firewalld API
            ##
            ## NOTE:
            ##  online and offline operations do not share a common firewalld API
            from firewall.core.fw_test import Firewall_test
            from firewall.client import FirewallClientZoneSettings
            fw = Firewall_test()
            fw.start()
            fw_offline = True

    except ImportError:
        ## Make python 2.4 shippable ci tests happy
        e = sys.exc_info()[1]
        module.fail_json(
            msg=
            'firewalld and its python 2 module are required for this module, version 2.0.11 or newer required '
            '(3.0.9 or newer for offline operations) \n %s' % e)

    if fw_offline:
        ## Pre-run version checking
        if FW_VERSION < "0.3.9":
            module.fail_json(
                msg=
                'unsupported version of firewalld, offline operations require >= 3.0.9'
            )
    else:
        ## Pre-run version checking
        if FW_VERSION < "0.2.11":
            module.fail_json(
                msg='unsupported version of firewalld, requires >= 2.0.11')

        ## Check for firewalld running
        try:
            if fw.connected is False:
                module.fail_json(
                    msg=
                    'firewalld service must be running, or try with offline=true'
                )
        except AttributeError:
            module.fail_json(msg="firewalld connection can't be established,\
                    installed version (%s) likely too old. Requires firewalld >= 2.0.11"
                             % FW_VERSION)

    ## Verify required params are provided
    if module.params['source'] is None and module.params['permanent'] is None:
        module.fail_json(msg='permanent is a required parameter')

    if module.params['interface'] is not None and module.params['zone'] is None:
        module.fail(msg='zone is a required parameter')

    if module.params['immediate'] and fw_offline:
        module.fail(
            msg=
            'firewall is not currently running, unable to perform immediate actions without a running firewall daemon'
        )

    ## Global Vars
    changed = False
    msgs = []
    service = module.params['service']
    rich_rule = module.params['rich_rule']
    source = module.params['source']

    if module.params['port'] is not None:
        port, protocol = module.params['port'].split('/')
        if protocol is None:
            module.fail_json(msg='improper port format (missing protocol?)')
    else:
        port = None

    if module.params['zone'] is not None:
        zone = module.params['zone']
    else:
        if fw_offline:
            zone = fw.get_default_zone()
        else:
            zone = fw.getDefaultZone()

    permanent = module.params['permanent']
    desired_state = module.params['state']
    immediate = module.params['immediate']
    timeout = module.params['timeout']
    interface = module.params['interface']
    masquerade = module.params['masquerade']

    modification_count = 0
    if service is not None:
        modification_count += 1
    if port is not None:
        modification_count += 1
    if rich_rule is not None:
        modification_count += 1
    if interface is not None:
        modification_count += 1
    if masquerade is not None:
        modification_count += 1

    if modification_count > 1:
        module.fail_json(
            msg=
            'can only operate on port, service, rich_rule or interface at once'
        )

    if service is not None:
        if immediate and permanent:
            is_enabled_permanent = action_handler(
                get_service_enabled_permanent, (zone, service))
            is_enabled_immediate = action_handler(get_service_enabled,
                                                  (zone, service))
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    action_handler(set_service_enabled_permanent,
                                   (zone, service))
                    changed = True
                if not is_enabled_immediate:
                    action_handler(set_service_enabled,
                                   (zone, service, timeout))
                    changed = True

            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    action_handler(set_service_disabled_permanent,
                                   (zone, service))
                    changed = True
                if is_enabled_immediate:
                    action_handler(set_service_disabled, (zone, service))
                    changed = True

        elif permanent and not immediate:
            is_enabled = action_handler(get_service_enabled_permanent,
                                        (zone, service))
            msgs.append('Permanent operation')

            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_service_enabled_permanent,
                                   (zone, service))
                    changed = True
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_service_disabled_permanent,
                                   (zone, service))
                    changed = True
        elif immediate and not permanent:
            is_enabled = action_handler(get_service_enabled, (zone, service))
            msgs.append('Non-permanent operation')

            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_service_enabled,
                                   (zone, service, timeout))
                    changed = True
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_service_disabled, (zone, service))
                    changed = True

        if changed is True:
            msgs.append("Changed service %s to %s" % (service, desired_state))

    # FIXME - source type does not handle non-permanent mode, this was an
    #         oversight in the past.
    if source is not None:
        is_enabled = action_handler(get_source, (zone, source))
        if desired_state == "enabled":
            if is_enabled is False:
                if module.check_mode:
                    module.exit_json(changed=True)

                action_handler(add_source, (zone, source))
                changed = True
                msgs.append("Added %s to zone %s" % (source, zone))
        elif desired_state == "disabled":
            if is_enabled is True:
                if module.check_mode:
                    module.exit_json(changed=True)

                action_handler(remove_source, (zone, source))
                changed = True
                msgs.append("Removed %s from zone %s" % (source, zone))

    if port is not None:
        if immediate and permanent:
            is_enabled_permanent = action_handler(get_port_enabled_permanent,
                                                  (zone, [port, protocol]))
            is_enabled_immediate = action_handler(get_port_enabled,
                                                  (zone, [port, protocol]))
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    action_handler(set_port_enabled_permanent,
                                   (zone, port, protocol))
                    changed = True
                if not is_enabled_immediate:
                    action_handler(set_port_enabled,
                                   (zone, port, protocol, timeout))
                    changed = True

            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    action_handler(set_port_disabled_permanent,
                                   (zone, port, protocol))
                    changed = True
                if is_enabled_immediate:
                    action_handler(set_port_disabled, (zone, port, protocol))
                    changed = True

        elif permanent and not immediate:
            is_enabled = action_handler(get_port_enabled_permanent,
                                        (zone, [port, protocol]))
            msgs.append('Permanent operation')

            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_port_enabled_permanent,
                                   (zone, port, protocol))
                    changed = True
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_port_disabled_permanent,
                                   (zone, port, protocol))
                    changed = True
        if immediate and not permanent:
            is_enabled = action_handler(get_port_enabled,
                                        (zone, [port, protocol]))
            msgs.append('Non-permanent operation')

            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_port_enabled,
                                   (zone, port, protocol, timeout))
                    changed = True
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_port_disabled, (zone, port, protocol))
                    changed = True

        if changed is True:
            msgs.append("Changed port %s to %s" % ("%s/%s" % (port, protocol), \
                        desired_state))

    if rich_rule is not None:
        if immediate and permanent:
            is_enabled_permanent = action_handler(
                get_rich_rule_enabled_permanent, (zone, rich_rule))
            is_enabled_immediate = action_handler(get_rich_rule_enabled,
                                                  (zone, rich_rule))
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    action_handler(set_rich_rule_enabled_permanent,
                                   (zone, rich_rule))
                    changed = True
                if not is_enabled_immediate:
                    action_handler(set_rich_rule_enabled,
                                   (zone, rich_rule, timeout))
                    changed = True

            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    action_handler(set_rich_rule_disabled_permanent,
                                   (zone, rich_rule))
                    changed = True
                if is_enabled_immediate:
                    action_handler(set_rich_rule_disabled, (zone, rich_rule))
                    changed = True
        if permanent and not immediate:
            is_enabled = action_handler(get_rich_rule_enabled_permanent,
                                        (zone, rich_rule))
            msgs.append('Permanent operation')

            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_rich_rule_enabled_permanent,
                                   (zone, rich_rule))
                    changed = True
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_rich_rule_disabled_permanent,
                                   (zone, rich_rule))
                    changed = True
        if immediate and not permanent:
            is_enabled = action_handler(get_rich_rule_enabled,
                                        (zone, rich_rule))
            msgs.append('Non-permanent operation')

            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_rich_rule_enabled,
                                   (zone, rich_rule, timeout))
                    changed = True
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_rich_rule_disabled, (zone, rich_rule))
                    changed = True

        if changed is True:
            msgs.append("Changed rich_rule %s to %s" %
                        (rich_rule, desired_state))

    if interface is not None:
        if immediate and permanent:
            is_enabled_permanent = action_handler(get_interface_permanent,
                                                  (zone, interface))
            is_enabled_immediate = action_handler(get_interface,
                                                  (zone, interface))
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    change_zone_of_interface_permanent(zone, interface)
                    changed = True
                if not is_enabled_immediate:
                    change_zone_of_interface(zone, interface)
                    changed = True
                if changed:
                    msgs.append("Changed %s to zone %s" % (interface, zone))

            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    remove_interface_permanent(zone, interface)
                    changed = True
                if is_enabled_immediate:
                    remove_interface(zone, interface)
                    changed = True
                if changed:
                    msgs.append("Removed %s from zone %s" % (interface, zone))

        elif permanent and not immediate:
            is_enabled = action_handler(get_interface_permanent,
                                        (zone, interface))
            msgs.append('Permanent operation')
            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    change_zone_of_interface_permanent(zone, interface)
                    changed = True
                    msgs.append("Changed %s to zone %s" % (interface, zone))
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    remove_interface_permanent(zone, interface)
                    changed = True
                    msgs.append("Removed %s from zone %s" % (interface, zone))
        elif immediate and not permanent:
            is_enabled = action_handler(get_interface, (zone, interface))
            msgs.append('Non-permanent operation')
            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    change_zone_of_interface(zone, interface)
                    changed = True
                    msgs.append("Changed %s to zone %s" % (interface, zone))
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    remove_interface(zone, interface)
                    changed = True
                    msgs.append("Removed %s from zone %s" % (interface, zone))

    if masquerade is not None:

        if immediate and permanent:
            is_enabled_permanent = action_handler(
                get_masquerade_enabled_permanent, (zone, ))
            is_enabled_immediate = action_handler(get_masquerade_enabled,
                                                  (zone, ))
            msgs.append('Permanent and Non-Permanent(immediate) operation')

            if desired_state == "enabled":
                if not is_enabled_permanent or not is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if not is_enabled_permanent:
                    action_handler(set_masquerade_permanent, (zone, True))
                    changed = True
                if not is_enabled_immediate:
                    action_handler(set_masquerade_enabled, (zone, ))
                    changed = True
                if changed:
                    msgs.append("Added masquerade to zone %s" % (zone))

            elif desired_state == "disabled":
                if is_enabled_permanent or is_enabled_immediate:
                    if module.check_mode:
                        module.exit_json(changed=True)
                if is_enabled_permanent:
                    action_handler(set_masquerade_permanent, (zone, False))
                    changed = True
                if is_enabled_immediate:
                    action_handler(set_masquerade_disabled, (zone, ))
                    changed = True
                if changed:
                    msgs.append("Removed masquerade from zone %s" % (zone))

        elif permanent and not immediate:
            is_enabled = action_handler(get_masquerade_enabled_permanent,
                                        (zone, ))
            msgs.append('Permanent operation')

            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_masquerade_permanent, (zone, True))
                    changed = True
                    msgs.append("Added masquerade to zone %s" % (zone))
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_masquerade_permanent, (zone, False))
                    changed = True
                    msgs.append("Removed masquerade from zone %s" % (zone))
        elif immediate and not permanent:
            is_enabled = action_handler(get_masquerade_enabled, (zone, ))
            msgs.append('Non-permanent operation')

            if desired_state == "enabled":
                if is_enabled is False:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_masquerade_enabled, (zone))
                    changed = True
                    msgs.append("Added masquerade to zone %s" % (zone))
            elif desired_state == "disabled":
                if is_enabled is True:
                    if module.check_mode:
                        module.exit_json(changed=True)

                    action_handler(set_masquerade_disabled, (zone))
                    changed = True
                    msgs.append("Removed masquerade from zone %s" % (zone))

    if fw_offline:
        msgs.append("(offline operation: only on-disk configs were altered)")
    module.exit_json(changed=changed, msg=', '.join(msgs))
Пример #25
0
    def uninstallFirewall(self):
        """uninstall firewall"""
        log.debug1("%s.uninstallFirewall()", self._log_prefix)

        # Removes the settings that have been added in the installFirewall call

        # get applied changes from installFirewall call
        if "firewall-changes" in self._settings:
            fw_changes = self._settings["firewall-changes"]
        else:
            # fallback if there was a severe error in deploy before or while
            # installing the firewall
            fw_changes = { }

        # only continue if there are any changes
        if len(fw_changes) < 1:
            return

        # create firewall client
        fw = FirewallClient()

        # for all zones
        for zone in fw_changes:
            z_perm = fw.config().getZoneByName(zone).getSettings()

            if "services" in fw_changes[zone]:
                services = fw_changes[zone]["services"]
                for service in services:
                    if "runtime" in services[service]:
                        try:
                            fw.removeService(zone, service)
                        except Exception as e:
                            if not "NOT_ENABLED" in str(e):
                                raise
                    if "permanent" in services[service]:
                        try:
                            z_perm.removeService(service)
                        except Exception as e:
                            if not "NOT_ENABLED" in str(e):
                                raise

            if "ports" in fw_changes[zone]:
                ports = fw_changes[zone]["ports"]
                for port_proto in ports:
                    port, proto = port_proto.split("/")
                    if "runtime" in ports[port_proto]:
                        try:
                            fw.removePort(zone, port, proto)
                        except Exception as e:
                            if not "NOT_ENABLED" in str(e):
                                raise
                    if "permanent" in ports[port_proto]:
                        try:
                            z_perm.removePort(port, proto)
                        except Exception as e:
                            if not "NOT_ENABLED" in str(e):
                                raise

            fw.config().getZoneByName(zone).update(z_perm)

        # clear fw_changes and save it in _settings
        fw_changes.clear()
        self._settings["firewall-changes"] = fw_changes
        self._settings.write()
# (c) 2017, Michael Scherer ([email protected])

#TODO DOCUMENTATION, example, license

from ansible.module_utils.basic import AnsibleModule

HAVE_FIREWALLD = True
FIREWALLD_RUNNING = True
try:
    import firewall.config
    FW_VERSION = firewall.config.VERSION

    from firewall.client import FirewallClient, FirewallClientZoneSettings
    try:
        fw = FirewallClient()
        fw.getDefaultZone()
    except AttributeError:
        FIREWALLD_RUNNING = False
except ImportError:
    HAVE_FIREWALLD = False


def main():

    module = AnsibleModule(
        argument_spec=dict(
            name=dict(required=True),
            state=dict(choices=['present', 'absent'], required=True),
            no_reload=dict(type='bool', default='no'),
        ),
Пример #27
0
# globals
module = None

# Imports
try:
    import firewall.config
    FW_VERSION = firewall.config.VERSION

    from firewall.client import Rich_Rule
    from firewall.client import FirewallClient
    fw = None
    fw_offline = False
    import_failure = False

    try:
        fw = FirewallClient()
        fw.getDefaultZone()
    except AttributeError:
        # Firewalld is not currently running, permanent-only operations

        # Import other required parts of the firewalld API
        #
        # NOTE:
        #  online and offline operations do not share a common firewalld API
        from firewall.core.fw_test import Firewall_test
        from firewall.client import FirewallClientZoneSettings
        fw = Firewall_test()
        fw.start()
        fw_offline = True

except ImportError as e:
class FirewallD:
    def __init__ (self):
        try:
            from firewall.client import FirewallClient
            self._fw = FirewallClient ()
            if not self._fw.connected:
                debugprint ("FirewallD seems to be installed but not running")
                self._fw = None
                self._zone = None
                self.running = False
                return
            zone_name = self._get_active_zone ()
            if zone_name:
                self._zone = self._fw.config().getZoneByName (zone_name)
            else:
                self._zone = None
            self.running = True
            debugprint ("Using /org/fedoraproject/FirewallD1")
        except (ImportError, dbus.exceptions.DBusException):
            self._fw = None
            self._zone = None
            self.running = False

    def _get_active_zone (self):
        zones = list(self._fw.getActiveZones().keys())
        if not zones:
            debugprint ("FirewallD: no changeable zone")
            return None
        elif len (zones) == 1:
            # most probable case
            return zones[0]
        else:
            # Do we need to handle the 'more active zones' case ?
            # It's quite unlikely case because that would mean that more
            # network connections are up and running and they are
            # in different network zones at the same time.
            debugprint ("FirewallD returned more zones, taking first one")
            return zones[0]

    def _get_fw_data (self, reply_handler=None, error_handler=None):
        try:
            debugprint ("%s in _get_fw_data: _fw_data is %s" %
                        (self, repr(self._fw_data.getServices())))
            if self._fw_data:
                debugprint ("Using cached firewall data")
                if reply_handler:
                    reply_handler (self._fw_data)
        except AttributeError:
            try:
                self._fw_data = self._zone.getSettings ()
                debugprint ("Firewall data obtained")
                if reply_handler:
                    reply_handler (self._fw_data) 
            except (dbus.exceptions.DBusException, AttributeError, ValueError) as e:
                self._fw_data = None
                debugprint ("Exception examining firewall")
                if error_handler:
                    error_handler (e)

        return self._fw_data

    def read (self, reply_handler=None, error_handler=None):
        if reply_handler:
            self._get_fw_data (reply_handler,
                               error_handler)
        else:
            self._get_fw_data ()

    def write (self):
        try:
            if self._zone:
                self._zone.update (self._fw_data)
            self._fw.reload ()
        except dbus.exceptions.DBusException:
            nonfatalException ()

    def add_service (self, service):
        if not self._get_fw_data ():
            return

        self._fw_data.addService (service)

    def check_ipp_client_allowed (self):
        if not self._get_fw_data ():
            return True

        return (IPP_CLIENT_SERVICE in self._fw_data.getServices () or
               [IPP_CLIENT_PORT, IPP_CLIENT_PROTOCOL] in self._fw_data.getPorts ())

    def check_ipp_server_allowed (self):
        if not self._get_fw_data ():
            return True

        return (IPP_SERVER_SERVICE in self._fw_data.getServices () or
               [IPP_SERVER_PORT, IPP_SERVER_PROTOCOL] in self._fw_data.getPorts ())

    def check_samba_client_allowed (self):
        if not self._get_fw_data ():
            return True

        return (SAMBA_CLIENT_SERVICE in self._fw_data.getServices ())

    def check_mdns_allowed (self):
        if not self._get_fw_data ():
            return True

        return (MDNS_SERVICE in self._fw_data.getServices () or
               [MDNS_PORT, MDNS_PROTOCOL] in self._fw_data.getPorts ())
Пример #29
0
def fw(retries=6):
    '''
    firewalld interface is nice, but due to DBUS, it is
    a great field for various errors and hickups.

    We then try to get a viable connexion, but also be really
    smart on establishing one
    '''
    # after 2 success full calls to the firewall
    # we assume it is correctly configured
    if _cache.get('f') is not None:
        if _cache.get('f_call', 0) < 2:
            try:
                if _cache['f'].getZones() is None:
                    time.sleep(0.05)
                    assert _cache['f'].getZones() is not None
                _cache.setdefault('f_call', 0)
                _cache['f_call'] += 1
            except (Exception, ):
                remove_client()
    if _cache.get('f') is None:
        state = 'notready'
        ttl = time.time() + TIMEOUT
        attempt = 0
        established = False
        loggued = False
        while time.time() < ttl:
            # if we have an instance, we have to wait until the firewall
            # is in the running state
            try:
                attempt += 1
                remove_client()
                _cache['f'] = FirewallClient()
                state = _cache['f'].get_property('state')
                # if we have first contacted the firewall without being
                # in running mode, there is a great chance for the dbus
                # interface to be bugged.
                # So there are two cases,
                # - we assume that the connexion is established only if we
                #   get directly a running state.
                # - In other cases, we assume the firewall to be ready for
                #   commands only on the second successful connection
                #   on the dbus interface.
                if state in RUNNINGS:
                    stop = False
                    if attempt == 1:
                        stop = True
                    elif not established:
                        established = True
                    else:
                        stop = True
                    if stop:
                        log.info('firewalld seems now ready')
                        break
                    continue
                else:
                    established = False
                time.sleep(0.4)
            except (Exception, ):
                log.error(traceback.format_exc())
                state = 'unknown'
                # DBUS doent like at all retry spam
                time.sleep(5)
            if not loggued:
                log.error('firewalld is not ready yet,'
                          ' waiting ({0})'.format(state))
                loggued = True
    if _cache.get('f') is None:
        if not retries:
            raise IOError('Cant contact firewalld daemon interface')
        else:
            return fw(retries - 1)
    return _cache['f']
Пример #30
0
- firewalld: port=8081/tcp permanent=true state=disabled
- firewalld: port=161-162/udp permanent=true state=enabled
- firewalld: zone=dmz service=http permanent=true state=enabled
- firewalld: rich_rule='rule service name="ftp" audit limit value="1/m" accept' permanent=true state=enabled
- firewalld: source='192.168.1.0/24' zone=internal state=enabled
'''

import os
import re

try:
    import firewall.config
    FW_VERSION = firewall.config.VERSION

    from firewall.client import FirewallClient
    fw = FirewallClient()
    HAS_FIREWALLD = True
except ImportError:
    HAS_FIREWALLD = False


################
# port handling
#
def get_port_enabled(zone, port_proto):
    if port_proto in fw.getPorts(zone):
        return True
    else:
        return False

Пример #31
0
def main():
    module_args = dict(
        name=dict(type="str", required=True),
        state=dict(choices=["present", "absent"], required=True),
        settype=dict(
            choices=[
                "hash:ip",
                "hash:ip,port",
                "hash:ip,port,ip",
                "hash:ip,port,net",
                "hash:ip,mark",
                "hash:net",
                "hash:net,net",
                "hash:net,port",
                "hash:net,port,net",
                "hash:net,iface",
                "hash:mac",
            ],
            required=True,
        ),
        permanent=dict(type="bool", required=False, default=False),
        immediate=dict(type="bool", required=False, default=False),
        addresses=dict(type="list", required=False),
    )

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
    FirewallTransaction.sanity_check(module)

    # setup the FirewallDClient
    client = FirewallClient()
    sets = client.getIPSets()
    settings = FirewallClientIPSetSettings()
    settings.setType(module.params["settype"])
    config = client.config()

    # construct return data
    result = {"firewalld_ipset_name": module.params["name"]}
    # Modifying a preexisting ipset
    if module.params["name"] in sets and module.params["state"] == "present":
        client_ipset_config = config.getIPSetByName(module.params["name"])
        original_entries = client_ipset_config.getEntries()

        # when we're in check mode we shouldn't commit anything to the
        # state of the target. Just output what would happen.
        if module.check_mode:
            new_entries = module.params["addresses"]
        else:
            client_ipset_config.setEntries(module.params["addresses"])
            firewalld_state(client, module.params)
            new_entries = client_ipset_config.getEntries()

        result["changed"] = new_entries != original_entries
        result["firewalld_ipset_addresses"] = new_entries

    # Creating a new ipset because the one proposed in the module declaration
    # does not exist already.
    elif module.params["name"] not in sets and module.params["state"] == "present":
        if module.check_mode:
            result["firewalld_ipset_addresses"] = module.params["addresses"]
        else:
            client_ipset_config = config.addIPSet(module.params["name"], settings)
            client_ipset_config.setEntries(module.params["addresses"])
            firewalld_state(client, module.params)
            new_entries = client_ipset_config.getEntries()

            result["firewalld_ipset_addresses"] = new_entries
        result["changed"] = True

    # Removing an ipset that exists right now. If an ipset is asked to be
    # removed when it doesn't exist, we should just return an "unchanged"
    # state.
    elif module.params["name"] in sets and module.params["state"] == "absent":
        client_ipset_config = config.getIPSetByName(module.params["name"])
        # avoid stateful actions in check mode
        if not module.check_mode:
            original_entries = client_ipset_config.remove()
            firewalld_state(client, module.params)
        result["changed"] = True
        result["firewalld_ipset_addresses"] = []

    module.exit_json(**result)