|
Packit |
a8ec6b |
# -*- coding: utf-8 -*-
|
|
Packit |
a8ec6b |
#
|
|
Packit |
a8ec6b |
# Copyright (C) 2011-2016 Red Hat, Inc.
|
|
Packit |
a8ec6b |
#
|
|
Packit |
a8ec6b |
# Authors:
|
|
Packit |
a8ec6b |
# Thomas Woerner <twoerner@redhat.com>
|
|
Packit |
a8ec6b |
#
|
|
Packit |
a8ec6b |
# This program is free software; you can redistribute it and/or modify
|
|
Packit |
a8ec6b |
# it under the terms of the GNU General Public License as published by
|
|
Packit |
a8ec6b |
# the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
a8ec6b |
# (at your option) any later version.
|
|
Packit |
a8ec6b |
#
|
|
Packit |
a8ec6b |
# This program is distributed in the hope that it will be useful,
|
|
Packit |
a8ec6b |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a8ec6b |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
a8ec6b |
# GNU General Public License for more details.
|
|
Packit |
a8ec6b |
#
|
|
Packit |
a8ec6b |
# You should have received a copy of the GNU General Public License
|
|
Packit |
a8ec6b |
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
a8ec6b |
#
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
__all__ = [ "Zone", "zone_reader", "zone_writer" ]
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
import xml.sax as sax
|
|
Packit |
a8ec6b |
import os
|
|
Packit |
a8ec6b |
import io
|
|
Packit |
a8ec6b |
import shutil
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
from firewall import config
|
|
Packit |
a8ec6b |
from firewall.functions import checkIP, checkIP6, checkIPnMask, checkIP6nMask, checkInterface, uniqify, max_zone_name_len, u2b_if_py2, check_mac, portStr
|
|
Packit |
a8ec6b |
from firewall.core.base import DEFAULT_ZONE_TARGET, ZONE_TARGETS
|
|
Packit |
a8ec6b |
from firewall.core.io.io_object import PY2, IO_Object, \
|
|
Packit |
a8ec6b |
IO_Object_ContentHandler, IO_Object_XMLGenerator, check_port, \
|
|
Packit |
a8ec6b |
check_tcpudp, check_protocol
|
|
Packit |
a8ec6b |
from firewall.core import rich
|
|
Packit |
a8ec6b |
from firewall.core.logger import log
|
|
Packit |
a8ec6b |
from firewall import errors
|
|
Packit |
a8ec6b |
from firewall.errors import FirewallError
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
class Zone(IO_Object):
|
|
Packit |
a8ec6b |
""" Zone class """
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
IMPORT_EXPORT_STRUCTURE = (
|
|
Packit |
a8ec6b |
( "version", "" ), # s
|
|
Packit |
a8ec6b |
( "short", "" ), # s
|
|
Packit |
a8ec6b |
( "description", "" ), # s
|
|
Packit |
a8ec6b |
( "UNUSED", False ), # b
|
|
Packit |
a8ec6b |
( "target", "" ), # s
|
|
Packit |
a8ec6b |
( "services", [ "", ], ), # as
|
|
Packit |
a8ec6b |
( "ports", [ ( "", "" ), ], ), # a(ss)
|
|
Packit |
a8ec6b |
( "icmp_blocks", [ "", ], ), # as
|
|
Packit |
a8ec6b |
( "masquerade", False ), # b
|
|
Packit |
a8ec6b |
( "forward_ports", [ ( "", "", "", "" ), ], ), # a(ssss)
|
|
Packit |
a8ec6b |
( "interfaces", [ "" ] ), # as
|
|
Packit |
a8ec6b |
( "sources", [ "" ] ), # as
|
|
Packit |
a8ec6b |
( "rules_str", [ "" ] ), # as
|
|
Packit |
a8ec6b |
( "protocols", [ "", ], ), # as
|
|
Packit |
a8ec6b |
( "source_ports", [ ( "", "" ), ], ), # a(ss)
|
|
Packit |
a8ec6b |
( "icmp_block_inversion", False ), # b
|
|
Packit |
a8ec6b |
)
|
|
Packit |
a8ec6b |
DBUS_SIGNATURE = '(sssbsasa(ss)asba(ssss)asasasasa(ss)b)'
|
|
Packit |
a8ec6b |
ADDITIONAL_ALNUM_CHARS = [ "_", "-", "/" ]
|
|
Packit |
a8ec6b |
PARSER_REQUIRED_ELEMENT_ATTRS = {
|
|
Packit |
a8ec6b |
"short": None,
|
|
Packit |
a8ec6b |
"description": None,
|
|
Packit |
a8ec6b |
"zone": None,
|
|
Packit |
a8ec6b |
"service": [ "name" ],
|
|
Packit |
a8ec6b |
"port": [ "port", "protocol" ],
|
|
Packit |
a8ec6b |
"icmp-block": [ "name" ],
|
|
Packit |
a8ec6b |
"icmp-type": [ "name" ],
|
|
Packit |
a8ec6b |
"forward-port": [ "port", "protocol" ],
|
|
Packit |
a8ec6b |
"interface": [ "name" ],
|
|
Packit |
a8ec6b |
"rule": None,
|
|
Packit |
a8ec6b |
"source": None,
|
|
Packit |
a8ec6b |
"destination": [ "address" ],
|
|
Packit |
a8ec6b |
"protocol": [ "value" ],
|
|
Packit |
a8ec6b |
"source-port": [ "port", "protocol" ],
|
|
Packit |
a8ec6b |
"log": None,
|
|
Packit |
a8ec6b |
"audit": None,
|
|
Packit |
a8ec6b |
"accept": None,
|
|
Packit |
a8ec6b |
"reject": None,
|
|
Packit |
a8ec6b |
"drop": None,
|
|
Packit |
a8ec6b |
"mark": [ "set" ],
|
|
Packit |
a8ec6b |
"limit": [ "value" ],
|
|
Packit |
a8ec6b |
"icmp-block-inversion": None,
|
|
Packit |
a8ec6b |
}
|
|
Packit |
a8ec6b |
PARSER_OPTIONAL_ELEMENT_ATTRS = {
|
|
Packit |
a8ec6b |
"zone": [ "name", "immutable", "target", "version" ],
|
|
Packit |
a8ec6b |
"masquerade": [ "enabled" ],
|
|
Packit |
a8ec6b |
"forward-port": [ "to-port", "to-addr" ],
|
|
Packit |
a8ec6b |
"rule": [ "family", "priority" ],
|
|
Packit |
a8ec6b |
"source": [ "address", "mac", "invert", "family", "ipset" ],
|
|
Packit |
a8ec6b |
"destination": [ "invert" ],
|
|
Packit |
a8ec6b |
"log": [ "prefix", "level" ],
|
|
Packit |
a8ec6b |
"reject": [ "type" ],
|
|
Packit |
a8ec6b |
}
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
@staticmethod
|
|
Packit |
a8ec6b |
def index_of(element):
|
|
Packit |
a8ec6b |
for i, (el, dummy) in enumerate(Zone.IMPORT_EXPORT_STRUCTURE):
|
|
Packit |
a8ec6b |
if el == element:
|
|
Packit |
a8ec6b |
return i
|
|
Packit |
a8ec6b |
raise FirewallError(errors.UNKNOWN_ERROR, "index_of()")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def __init__(self):
|
|
Packit |
a8ec6b |
super(Zone, self).__init__()
|
|
Packit |
a8ec6b |
self.version = ""
|
|
Packit |
a8ec6b |
self.short = ""
|
|
Packit |
a8ec6b |
self.description = ""
|
|
Packit |
a8ec6b |
self.UNUSED = False
|
|
Packit |
a8ec6b |
self.target = DEFAULT_ZONE_TARGET
|
|
Packit |
a8ec6b |
self.services = [ ]
|
|
Packit |
a8ec6b |
self.ports = [ ]
|
|
Packit |
a8ec6b |
self.protocols = [ ]
|
|
Packit |
a8ec6b |
self.icmp_blocks = [ ]
|
|
Packit |
a8ec6b |
self.masquerade = False
|
|
Packit |
a8ec6b |
self.forward_ports = [ ]
|
|
Packit |
a8ec6b |
self.source_ports = [ ]
|
|
Packit |
a8ec6b |
self.interfaces = [ ]
|
|
Packit |
a8ec6b |
self.sources = [ ]
|
|
Packit |
a8ec6b |
self.fw_config = None # to be able to check services and a icmp_blocks
|
|
Packit |
a8ec6b |
self.rules = [ ]
|
|
Packit |
a8ec6b |
self.icmp_block_inversion = False
|
|
Packit |
a8ec6b |
self.combined = False
|
|
Packit |
a8ec6b |
self.applied = False
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def cleanup(self):
|
|
Packit |
a8ec6b |
self.version = ""
|
|
Packit |
a8ec6b |
self.short = ""
|
|
Packit |
a8ec6b |
self.description = ""
|
|
Packit |
a8ec6b |
self.UNUSED = False
|
|
Packit |
a8ec6b |
self.target = DEFAULT_ZONE_TARGET
|
|
Packit |
a8ec6b |
del self.services[:]
|
|
Packit |
a8ec6b |
del self.ports[:]
|
|
Packit |
a8ec6b |
del self.protocols[:]
|
|
Packit |
a8ec6b |
del self.icmp_blocks[:]
|
|
Packit |
a8ec6b |
self.masquerade = False
|
|
Packit |
a8ec6b |
del self.forward_ports[:]
|
|
Packit |
a8ec6b |
del self.source_ports[:]
|
|
Packit |
a8ec6b |
del self.interfaces[:]
|
|
Packit |
a8ec6b |
del self.sources[:]
|
|
Packit |
a8ec6b |
self.fw_config = None # to be able to check services and a icmp_blocks
|
|
Packit |
a8ec6b |
del self.rules[:]
|
|
Packit |
a8ec6b |
self.icmp_block_inversion = False
|
|
Packit |
a8ec6b |
self.combined = False
|
|
Packit |
a8ec6b |
self.applied = False
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def encode_strings(self):
|
|
Packit |
a8ec6b |
""" HACK. I haven't been able to make sax parser return
|
|
Packit |
a8ec6b |
strings encoded (because of python 2) instead of in unicode.
|
|
Packit |
a8ec6b |
Get rid of it once we throw out python 2 support."""
|
|
Packit |
a8ec6b |
self.version = u2b_if_py2(self.version)
|
|
Packit |
a8ec6b |
self.short = u2b_if_py2(self.short)
|
|
Packit |
a8ec6b |
self.description = u2b_if_py2(self.description)
|
|
Packit |
a8ec6b |
self.target = u2b_if_py2(self.target)
|
|
Packit |
a8ec6b |
self.services = [u2b_if_py2(s) for s in self.services]
|
|
Packit |
a8ec6b |
self.ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr) in self.ports]
|
|
Packit |
a8ec6b |
self.protocols = [u2b_if_py2(pr) for pr in self.protocols]
|
|
Packit |
a8ec6b |
self.icmp_blocks = [u2b_if_py2(i) for i in self.icmp_blocks]
|
|
Packit |
a8ec6b |
self.forward_ports = [(u2b_if_py2(p1),u2b_if_py2(p2),u2b_if_py2(p3),u2b_if_py2(p4)) for (p1,p2,p3,p4) in self.forward_ports]
|
|
Packit |
a8ec6b |
self.source_ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr)
|
|
Packit |
a8ec6b |
in self.source_ports]
|
|
Packit |
a8ec6b |
self.interfaces = [u2b_if_py2(i) for i in self.interfaces]
|
|
Packit |
a8ec6b |
self.sources = [u2b_if_py2(s) for s in self.sources]
|
|
Packit |
a8ec6b |
self.rules = [u2b_if_py2(s) for s in self.rules]
|
|
Packit Service |
9bd718 |
|
|
Packit Service |
9bd718 |
def __getattr__(self, name):
|
|
Packit Service |
9bd718 |
if name == "rules_str":
|
|
Packit Service |
9bd718 |
rules_str = [str(rule) for rule in self.rules]
|
|
Packit Service |
9bd718 |
return rules_str
|
|
Packit Service |
9bd718 |
else:
|
|
Packit Service |
9bd718 |
return getattr(super(Zone, self), name)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def __setattr__(self, name, value):
|
|
Packit |
a8ec6b |
if name == "rules_str":
|
|
Packit |
a8ec6b |
self.rules = [rich.Rich_Rule(rule_str=s) for s in value]
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
super(Zone, self).__setattr__(name, value)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def _check_config(self, config, item):
|
|
Packit |
a8ec6b |
if item == "services" and self.fw_config:
|
|
Packit |
a8ec6b |
existing_services = self.fw_config.get_services()
|
|
Packit |
a8ec6b |
for service in config:
|
|
Packit |
a8ec6b |
if service not in existing_services:
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_SERVICE,
|
|
Packit |
a8ec6b |
"'%s' not among existing services" % \
|
|
Packit |
a8ec6b |
service)
|
|
Packit |
a8ec6b |
elif item == "ports":
|
|
Packit |
a8ec6b |
for port in config:
|
|
Packit |
a8ec6b |
check_port(port[0])
|
|
Packit |
a8ec6b |
check_tcpudp(port[1])
|
|
Packit |
a8ec6b |
elif item == "protocols":
|
|
Packit |
a8ec6b |
for proto in config:
|
|
Packit |
a8ec6b |
check_protocol(proto)
|
|
Packit |
a8ec6b |
elif item == "icmp_blocks" and self.fw_config:
|
|
Packit |
a8ec6b |
existing_icmptypes = self.fw_config.get_icmptypes()
|
|
Packit |
a8ec6b |
for icmptype in config:
|
|
Packit |
a8ec6b |
if icmptype not in existing_icmptypes:
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_ICMPTYPE,
|
|
Packit |
a8ec6b |
"'%s' not among existing icmp types" % \
|
|
Packit |
a8ec6b |
icmptype)
|
|
Packit |
a8ec6b |
elif item == "forward_ports":
|
|
Packit |
a8ec6b |
for fwd_port in config:
|
|
Packit |
a8ec6b |
check_port(fwd_port[0])
|
|
Packit |
a8ec6b |
check_tcpudp(fwd_port[1])
|
|
Packit |
a8ec6b |
if not fwd_port[2] and not fwd_port[3]:
|
|
Packit |
a8ec6b |
raise FirewallError(
|
|
Packit |
a8ec6b |
errors.INVALID_FORWARD,
|
|
Packit |
a8ec6b |
"'%s' is missing to-port AND to-addr " % fwd_port)
|
|
Packit |
a8ec6b |
if fwd_port[2]:
|
|
Packit |
a8ec6b |
check_port(fwd_port[2])
|
|
Packit |
a8ec6b |
if fwd_port[3]:
|
|
Packit |
a8ec6b |
if not checkIP(fwd_port[3]) and not checkIP6(fwd_port[3]):
|
|
Packit |
a8ec6b |
raise FirewallError(
|
|
Packit |
a8ec6b |
errors.INVALID_ADDR,
|
|
Packit |
a8ec6b |
"to-addr '%s' is not a valid address" % fwd_port[3])
|
|
Packit |
a8ec6b |
elif item == "source_ports":
|
|
Packit |
a8ec6b |
for port in config:
|
|
Packit |
a8ec6b |
check_port(port[0])
|
|
Packit |
a8ec6b |
check_tcpudp(port[1])
|
|
Packit |
a8ec6b |
elif item == "target":
|
|
Packit |
a8ec6b |
if config not in ZONE_TARGETS:
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_TARGET, config)
|
|
Packit |
a8ec6b |
elif item == "interfaces":
|
|
Packit |
a8ec6b |
for interface in config:
|
|
Packit |
a8ec6b |
if not checkInterface(interface):
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_INTERFACE, interface)
|
|
Packit |
a8ec6b |
elif item == "sources":
|
|
Packit |
a8ec6b |
for source in config:
|
|
Packit |
a8ec6b |
if not checkIPnMask(source) and not checkIP6nMask(source) and \
|
|
Packit |
a8ec6b |
not check_mac(source) and not source.startswith("ipset:"):
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_ADDR, source)
|
|
Packit |
a8ec6b |
elif item == "rules_str":
|
|
Packit |
a8ec6b |
for rule in config:
|
|
Packit Service |
9bd718 |
rich.Rich_Rule(rule_str=rule)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def check_name(self, name):
|
|
Packit |
a8ec6b |
super(Zone, self).check_name(name)
|
|
Packit |
a8ec6b |
if name.startswith('/'):
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_NAME,
|
|
Packit |
a8ec6b |
"'%s' can't start with '/'" % name)
|
|
Packit |
a8ec6b |
elif name.endswith('/'):
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_NAME,
|
|
Packit |
a8ec6b |
"'%s' can't end with '/'" % name)
|
|
Packit |
a8ec6b |
elif name.count('/') > 1:
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_NAME,
|
|
Packit |
a8ec6b |
"more than one '/' in '%s'" % name)
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
if "/" in name:
|
|
Packit |
a8ec6b |
checked_name = name[:name.find('/')]
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
checked_name = name
|
|
Packit |
a8ec6b |
if len(checked_name) > max_zone_name_len():
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_NAME,
|
|
Packit |
a8ec6b |
"Zone of '%s' has %d chars, max is %d %s" % (
|
|
Packit |
a8ec6b |
name, len(checked_name),
|
|
Packit |
a8ec6b |
max_zone_name_len(),
|
|
Packit |
a8ec6b |
self.combined))
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def combine(self, zone):
|
|
Packit |
a8ec6b |
self.combined = True
|
|
Packit |
a8ec6b |
self.filename = None
|
|
Packit |
a8ec6b |
self.version = ""
|
|
Packit |
a8ec6b |
self.short = ""
|
|
Packit |
a8ec6b |
self.description = ""
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
for interface in zone.interfaces:
|
|
Packit |
a8ec6b |
if interface not in self.interfaces:
|
|
Packit |
a8ec6b |
self.interfaces.append(interface)
|
|
Packit |
a8ec6b |
for source in zone.sources:
|
|
Packit |
a8ec6b |
if source not in self.sources:
|
|
Packit |
a8ec6b |
self.sources.append(source)
|
|
Packit |
a8ec6b |
for service in zone.services:
|
|
Packit |
a8ec6b |
if service not in self.services:
|
|
Packit |
a8ec6b |
self.services.append(service)
|
|
Packit |
a8ec6b |
for port in zone.ports:
|
|
Packit |
a8ec6b |
if port not in self.ports:
|
|
Packit |
a8ec6b |
self.ports.append(port)
|
|
Packit |
a8ec6b |
for proto in zone.protocols:
|
|
Packit |
a8ec6b |
if proto not in self.protocols:
|
|
Packit |
a8ec6b |
self.protocols.append(proto)
|
|
Packit |
a8ec6b |
for icmp in zone.icmp_blocks:
|
|
Packit |
a8ec6b |
if icmp not in self.icmp_blocks:
|
|
Packit |
a8ec6b |
self.icmp_blocks.append(icmp)
|
|
Packit |
a8ec6b |
if zone.masquerade:
|
|
Packit |
a8ec6b |
self.masquerade = True
|
|
Packit |
a8ec6b |
for forward in zone.forward_ports:
|
|
Packit |
a8ec6b |
if forward not in self.forward_ports:
|
|
Packit |
a8ec6b |
self.forward_ports.append(forward)
|
|
Packit |
a8ec6b |
for port in zone.source_ports:
|
|
Packit |
a8ec6b |
if port not in self.source_ports:
|
|
Packit |
a8ec6b |
self.source_ports.append(port)
|
|
Packit |
a8ec6b |
for rule in zone.rules:
|
|
Packit |
a8ec6b |
self.rules.append(rule)
|
|
Packit |
a8ec6b |
if zone.icmp_block_inversion:
|
|
Packit |
a8ec6b |
self.icmp_block_inversion = True
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# PARSER
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
class zone_ContentHandler(IO_Object_ContentHandler):
|
|
Packit |
a8ec6b |
def __init__(self, item):
|
|
Packit |
a8ec6b |
IO_Object_ContentHandler.__init__(self, item)
|
|
Packit |
a8ec6b |
self._rule = None
|
|
Packit |
a8ec6b |
self._rule_error = False
|
|
Packit |
a8ec6b |
self._limit_ok = None
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def startElement(self, name, attrs):
|
|
Packit |
a8ec6b |
IO_Object_ContentHandler.startElement(self, name, attrs)
|
|
Packit |
a8ec6b |
if self._rule_error:
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
self.item.parser_check_element_attrs(name, attrs)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
if name == "zone":
|
|
Packit |
a8ec6b |
if "name" in attrs:
|
|
Packit |
a8ec6b |
log.warning("Ignoring deprecated attribute name='%s'",
|
|
Packit |
a8ec6b |
attrs["name"])
|
|
Packit |
a8ec6b |
if "version" in attrs:
|
|
Packit |
a8ec6b |
self.item.version = attrs["version"]
|
|
Packit |
a8ec6b |
if "immutable" in attrs:
|
|
Packit |
a8ec6b |
log.warning("Ignoring deprecated attribute immutable='%s'",
|
|
Packit |
a8ec6b |
attrs["immutable"])
|
|
Packit |
a8ec6b |
if "target" in attrs:
|
|
Packit |
a8ec6b |
target = attrs["target"]
|
|
Packit |
a8ec6b |
if target not in ZONE_TARGETS:
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_TARGET, target)
|
|
Packit |
a8ec6b |
if target != "" and target != DEFAULT_ZONE_TARGET:
|
|
Packit |
a8ec6b |
self.item.target = target
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "short":
|
|
Packit |
a8ec6b |
pass
|
|
Packit |
a8ec6b |
elif name == "description":
|
|
Packit |
a8ec6b |
pass
|
|
Packit |
a8ec6b |
elif name == "service":
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
if self._rule.element:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
self._rule.element = rich.Rich_Service(attrs["name"])
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if attrs["name"] not in self.item.services:
|
|
Packit |
a8ec6b |
self.item.services.append(attrs["name"])
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Service '%s' already set, ignoring.",
|
|
Packit |
a8ec6b |
attrs["name"])
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "port":
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
if self._rule.element:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
self._rule.element = rich.Rich_Port(attrs["port"],
|
|
Packit |
a8ec6b |
attrs["protocol"])
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
check_port(attrs["port"])
|
|
Packit |
a8ec6b |
check_tcpudp(attrs["protocol"])
|
|
Packit |
a8ec6b |
entry = (portStr(attrs["port"], "-"), attrs["protocol"])
|
|
Packit |
a8ec6b |
if entry not in self.item.ports:
|
|
Packit |
a8ec6b |
self.item.ports.append(entry)
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Port '%s/%s' already set, ignoring.",
|
|
Packit |
a8ec6b |
attrs["port"], attrs["protocol"])
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "protocol":
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
if self._rule.element:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
self._rule.element = rich.Rich_Protocol(attrs["value"])
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
check_protocol(attrs["value"])
|
|
Packit |
a8ec6b |
if attrs["value"] not in self.item.protocols:
|
|
Packit |
a8ec6b |
self.item.protocols.append(attrs["value"])
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Protocol '%s' already set, ignoring.",
|
|
Packit |
a8ec6b |
attrs["value"])
|
|
Packit |
a8ec6b |
elif name == "icmp-block":
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
if self._rule.element:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
self._rule.element = rich.Rich_IcmpBlock(attrs["name"])
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if attrs["name"] not in self.item.icmp_blocks:
|
|
Packit |
a8ec6b |
self.item.icmp_blocks.append(attrs["name"])
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("icmp-block '%s' already set, ignoring.",
|
|
Packit |
a8ec6b |
attrs["name"])
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "icmp-type":
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
if self._rule.element:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
self._rule.element = rich.Rich_IcmpType(attrs["name"])
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: icmp-block '%s' outside of rule",
|
|
Packit |
a8ec6b |
attrs["name"])
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "masquerade":
|
|
Packit |
a8ec6b |
if "enabled" in attrs and \
|
|
Packit |
a8ec6b |
attrs["enabled"].lower() in [ "no", "false" ] :
|
|
Packit |
a8ec6b |
log.warning("Ignoring deprecated attribute enabled='%s'",
|
|
Packit |
a8ec6b |
attrs["enabled"])
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
if self._rule.element:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
self._rule.element = rich.Rich_Masquerade()
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
if self.item.masquerade:
|
|
Packit |
a8ec6b |
log.warning("Masquerade already set, ignoring.")
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
self.item.masquerade = True
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "forward-port":
|
|
Packit |
a8ec6b |
to_port = ""
|
|
Packit |
a8ec6b |
if "to-port" in attrs:
|
|
Packit |
a8ec6b |
to_port = attrs["to-port"]
|
|
Packit |
a8ec6b |
to_addr = ""
|
|
Packit |
a8ec6b |
if "to-addr" in attrs:
|
|
Packit |
a8ec6b |
to_addr = attrs["to-addr"]
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
if self._rule.element:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
self._rule.element = rich.Rich_ForwardPort(attrs["port"],
|
|
Packit |
a8ec6b |
attrs["protocol"],
|
|
Packit |
a8ec6b |
to_port, to_addr)
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
check_port(attrs["port"])
|
|
Packit |
a8ec6b |
check_tcpudp(attrs["protocol"])
|
|
Packit |
a8ec6b |
if to_port:
|
|
Packit |
a8ec6b |
check_port(to_port)
|
|
Packit |
a8ec6b |
if to_addr:
|
|
Packit |
a8ec6b |
if not checkIP(to_addr) and not checkIP6(to_addr):
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_ADDR,
|
|
Packit |
a8ec6b |
"to-addr '%s' is not a valid address" \
|
|
Packit |
a8ec6b |
% to_addr)
|
|
Packit |
a8ec6b |
entry = (portStr(attrs["port"], "-"), attrs["protocol"],
|
|
Packit |
a8ec6b |
portStr(to_port, "-"), str(to_addr))
|
|
Packit |
a8ec6b |
if entry not in self.item.forward_ports:
|
|
Packit |
a8ec6b |
self.item.forward_ports.append(entry)
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Forward port %s/%s%s%s already set, ignoring.",
|
|
Packit |
a8ec6b |
attrs["port"], attrs["protocol"],
|
|
Packit |
a8ec6b |
" >%s" % to_port if to_port else "",
|
|
Packit |
a8ec6b |
" @%s" % to_addr if to_addr else "")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "source-port":
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
if self._rule.element:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one element in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
self._rule.element = rich.Rich_SourcePort(attrs["port"],
|
|
Packit |
a8ec6b |
attrs["protocol"])
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
check_port(attrs["port"])
|
|
Packit |
a8ec6b |
check_tcpudp(attrs["protocol"])
|
|
Packit |
a8ec6b |
entry = (portStr(attrs["port"], "-"), attrs["protocol"])
|
|
Packit |
a8ec6b |
if entry not in self.item.source_ports:
|
|
Packit |
a8ec6b |
self.item.source_ports.append(entry)
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Source port '%s/%s' already set, ignoring.",
|
|
Packit |
a8ec6b |
attrs["port"], attrs["protocol"])
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "interface":
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: interface use in rule.')
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
# zone bound to interface
|
|
Packit |
a8ec6b |
if "name" not in attrs:
|
|
Packit |
a8ec6b |
log.warning('Invalid interface: Name missing.')
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if attrs["name"] not in self.item.interfaces:
|
|
Packit |
a8ec6b |
self.item.interfaces.append(attrs["name"])
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Interface '%s' already set, ignoring.",
|
|
Packit |
a8ec6b |
attrs["name"])
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "source":
|
|
Packit |
a8ec6b |
if self._rule:
|
|
Packit |
a8ec6b |
if self._rule.source:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one source in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
invert = False
|
|
Packit |
a8ec6b |
if "invert" in attrs and \
|
|
Packit |
a8ec6b |
attrs["invert"].lower() in [ "yes", "true" ]:
|
|
Packit |
a8ec6b |
invert = True
|
|
Packit |
a8ec6b |
addr = mac = ipset = None
|
|
Packit |
a8ec6b |
if "address" in attrs:
|
|
Packit |
a8ec6b |
addr = attrs["address"]
|
|
Packit |
a8ec6b |
if "mac" in attrs:
|
|
Packit |
a8ec6b |
mac = attrs["mac"]
|
|
Packit |
a8ec6b |
if "ipset" in attrs:
|
|
Packit |
a8ec6b |
ipset = attrs["ipset"]
|
|
Packit |
a8ec6b |
self._rule.source = rich.Rich_Source(addr, mac, ipset,
|
|
Packit |
a8ec6b |
invert=invert)
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
# zone bound to source
|
|
Packit |
a8ec6b |
if "address" not in attrs and "ipset" not in attrs:
|
|
Packit |
a8ec6b |
log.warning('Invalid source: No address no ipset.')
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if "address" in attrs and "ipset" in attrs:
|
|
Packit |
a8ec6b |
log.warning('Invalid source: Address and ipset.')
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if "family" in attrs:
|
|
Packit |
a8ec6b |
log.warning("Ignoring deprecated attribute family='%s'",
|
|
Packit |
a8ec6b |
attrs["family"])
|
|
Packit |
a8ec6b |
if "invert" in attrs:
|
|
Packit |
a8ec6b |
log.warning('Invalid source: Invertion not allowed here.')
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if "address" in attrs:
|
|
Packit |
a8ec6b |
if not checkIPnMask(attrs["address"]) and \
|
|
Packit |
a8ec6b |
not checkIP6nMask(attrs["address"]) and \
|
|
Packit |
a8ec6b |
not check_mac(attrs["address"]):
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_ADDR, attrs["address"])
|
|
Packit |
a8ec6b |
if "ipset" in attrs:
|
|
Packit |
a8ec6b |
entry = "ipset:%s" % attrs["ipset"]
|
|
Packit |
a8ec6b |
if entry not in self.item.sources:
|
|
Packit |
a8ec6b |
self.item.sources.append(entry)
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Source '%s' already set, ignoring.",
|
|
Packit |
a8ec6b |
attrs["address"])
|
|
Packit |
a8ec6b |
if "address" in attrs:
|
|
Packit |
a8ec6b |
entry = attrs["address"]
|
|
Packit |
a8ec6b |
if entry not in self.item.sources:
|
|
Packit |
a8ec6b |
self.item.sources.append(entry)
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Source '%s' already set, ignoring.",
|
|
Packit |
a8ec6b |
attrs["address"])
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "destination":
|
|
Packit |
a8ec6b |
if not self._rule:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: Destination outside of rule')
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if self._rule.destination:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one destination in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
invert = False
|
|
Packit |
a8ec6b |
if "invert" in attrs and \
|
|
Packit |
a8ec6b |
attrs["invert"].lower() in [ "yes", "true" ]:
|
|
Packit |
a8ec6b |
invert = True
|
|
Packit |
a8ec6b |
self._rule.destination = rich.Rich_Destination(attrs["address"],
|
|
Packit |
a8ec6b |
invert)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name in [ "accept", "reject", "drop", "mark" ]:
|
|
Packit |
a8ec6b |
if not self._rule:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: Action outside of rule')
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if self._rule.action:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: More than one action')
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if name == "accept":
|
|
Packit |
a8ec6b |
self._rule.action = rich.Rich_Accept()
|
|
Packit |
a8ec6b |
elif name == "reject":
|
|
Packit |
a8ec6b |
_type = None
|
|
Packit |
a8ec6b |
if "type" in attrs:
|
|
Packit |
a8ec6b |
_type = attrs["type"]
|
|
Packit |
a8ec6b |
self._rule.action = rich.Rich_Reject(_type)
|
|
Packit |
a8ec6b |
elif name == "drop":
|
|
Packit |
a8ec6b |
self._rule.action = rich.Rich_Drop()
|
|
Packit |
a8ec6b |
elif name == "mark":
|
|
Packit |
a8ec6b |
_set = attrs["set"]
|
|
Packit |
a8ec6b |
self._rule.action = rich.Rich_Mark(_set)
|
|
Packit |
a8ec6b |
self._limit_ok = self._rule.action
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "log":
|
|
Packit |
a8ec6b |
if not self._rule:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: Log outside of rule')
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if self._rule.log:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: More than one log')
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
level = None
|
|
Packit |
a8ec6b |
if "level" in attrs:
|
|
Packit |
a8ec6b |
level = attrs["level"]
|
|
Packit |
a8ec6b |
if level not in [ "emerg", "alert", "crit", "error",
|
|
Packit |
a8ec6b |
"warning", "notice", "info", "debug" ]:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: Invalid log level')
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
prefix = attrs["prefix"] if "prefix" in attrs else None
|
|
Packit |
a8ec6b |
self._rule.log = rich.Rich_Log(prefix, level)
|
|
Packit |
a8ec6b |
self._limit_ok = self._rule.log
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "audit":
|
|
Packit |
a8ec6b |
if not self._rule:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: Audit outside of rule')
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if self._rule.audit:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one audit in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
self._rule.audit = rich.Rich_Audit()
|
|
Packit |
a8ec6b |
self._limit_ok = self._rule.audit
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "rule":
|
|
Packit |
a8ec6b |
family = None
|
|
Packit |
a8ec6b |
priority = 0
|
|
Packit |
a8ec6b |
if "family" in attrs:
|
|
Packit |
a8ec6b |
family = attrs["family"]
|
|
Packit |
a8ec6b |
if family not in [ "ipv4", "ipv6" ]:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: Rule family "%s" invalid',
|
|
Packit |
a8ec6b |
attrs["family"])
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if "priority" in attrs:
|
|
Packit |
a8ec6b |
priority = int(attrs["priority"])
|
|
Packit |
a8ec6b |
self._rule = rich.Rich_Rule(family=family, priority=priority)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "limit":
|
|
Packit |
a8ec6b |
if not self._limit_ok:
|
|
Packit |
a8ec6b |
log.warning('Invalid rule: Limit outside of action, log and audit')
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
if self._limit_ok.limit:
|
|
Packit |
a8ec6b |
log.warning("Invalid rule: More than one limit in rule '%s', ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule_error = True
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
value = attrs["value"]
|
|
Packit |
a8ec6b |
self._limit_ok.limit = rich.Rich_Limit(value)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
elif name == "icmp-block-inversion":
|
|
Packit |
a8ec6b |
if self.item.icmp_block_inversion:
|
|
Packit |
a8ec6b |
log.warning("Icmp-Block-Inversion already set, ignoring.")
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
self.item.icmp_block_inversion = True
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Unknown XML element '%s'", name)
|
|
Packit |
a8ec6b |
return
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def endElement(self, name):
|
|
Packit |
a8ec6b |
IO_Object_ContentHandler.endElement(self, name)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
if name == "rule":
|
|
Packit |
a8ec6b |
if not self._rule_error:
|
|
Packit |
a8ec6b |
try:
|
|
Packit |
a8ec6b |
self._rule.check()
|
|
Packit |
a8ec6b |
except Exception as e:
|
|
Packit |
a8ec6b |
log.warning("%s: %s", e, str(self._rule))
|
|
Packit |
a8ec6b |
else:
|
|
Packit Service |
9bd718 |
if str(self._rule) not in \
|
|
Packit Service |
9bd718 |
[ str(x) for x in self.item.rules ]:
|
|
Packit |
a8ec6b |
self.item.rules.append(self._rule)
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Rule '%s' already set, ignoring.",
|
|
Packit |
a8ec6b |
str(self._rule))
|
|
Packit |
a8ec6b |
self._rule = None
|
|
Packit |
a8ec6b |
self._rule_error = False
|
|
Packit |
a8ec6b |
elif name in [ "accept", "reject", "drop", "mark", "log", "audit" ]:
|
|
Packit |
a8ec6b |
self._limit_ok = None
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def zone_reader(filename, path, no_check_name=False):
|
|
Packit |
a8ec6b |
zone = Zone()
|
|
Packit |
a8ec6b |
if not filename.endswith(".xml"):
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_NAME,
|
|
Packit |
a8ec6b |
"'%s' is missing .xml suffix" % filename)
|
|
Packit |
a8ec6b |
zone.name = filename[:-4]
|
|
Packit |
a8ec6b |
if not no_check_name:
|
|
Packit |
a8ec6b |
zone.check_name(zone.name)
|
|
Packit |
a8ec6b |
zone.filename = filename
|
|
Packit |
a8ec6b |
zone.path = path
|
|
Packit |
a8ec6b |
zone.builtin = False if path.startswith(config.ETC_FIREWALLD) else True
|
|
Packit |
a8ec6b |
zone.default = zone.builtin
|
|
Packit |
a8ec6b |
handler = zone_ContentHandler(zone)
|
|
Packit |
a8ec6b |
parser = sax.make_parser()
|
|
Packit |
a8ec6b |
parser.setContentHandler(handler)
|
|
Packit |
a8ec6b |
name = "%s/%s" % (path, filename)
|
|
Packit |
a8ec6b |
with open(name, "rb") as f:
|
|
Packit |
a8ec6b |
source = sax.InputSource(None)
|
|
Packit |
a8ec6b |
source.setByteStream(f)
|
|
Packit |
a8ec6b |
try:
|
|
Packit |
a8ec6b |
parser.parse(source)
|
|
Packit |
a8ec6b |
except sax.SAXParseException as msg:
|
|
Packit |
a8ec6b |
raise FirewallError(errors.INVALID_ZONE,
|
|
Packit |
a8ec6b |
"not a valid zone file: %s" % \
|
|
Packit |
a8ec6b |
msg.getException())
|
|
Packit |
a8ec6b |
del handler
|
|
Packit |
a8ec6b |
del parser
|
|
Packit |
a8ec6b |
if PY2:
|
|
Packit |
a8ec6b |
zone.encode_strings()
|
|
Packit |
a8ec6b |
return zone
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
def zone_writer(zone, path=None):
|
|
Packit |
a8ec6b |
_path = path if path else zone.path
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
if zone.filename:
|
|
Packit |
a8ec6b |
name = "%s/%s" % (_path, zone.filename)
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
name = "%s/%s.xml" % (_path, zone.name)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
if os.path.exists(name):
|
|
Packit |
a8ec6b |
try:
|
|
Packit |
a8ec6b |
shutil.copy2(name, "%s.old" % name)
|
|
Packit |
a8ec6b |
except Exception as msg:
|
|
Packit |
a8ec6b |
log.error("Backup of file '%s' failed: %s", name, msg)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
dirpath = os.path.dirname(name)
|
|
Packit |
a8ec6b |
if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath):
|
|
Packit |
a8ec6b |
if not os.path.exists(config.ETC_FIREWALLD):
|
|
Packit |
a8ec6b |
os.mkdir(config.ETC_FIREWALLD, 0o750)
|
|
Packit |
a8ec6b |
os.mkdir(dirpath, 0o750)
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
f = io.open(name, mode='wt', encoding='UTF-8')
|
|
Packit |
a8ec6b |
handler = IO_Object_XMLGenerator(f)
|
|
Packit |
a8ec6b |
handler.startDocument()
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# start zone element
|
|
Packit |
a8ec6b |
attrs = {}
|
|
Packit |
a8ec6b |
if zone.version and zone.version != "":
|
|
Packit |
a8ec6b |
attrs["version"] = zone.version
|
|
Packit |
a8ec6b |
if zone.target != DEFAULT_ZONE_TARGET:
|
|
Packit |
a8ec6b |
attrs["target"] = zone.target
|
|
Packit |
a8ec6b |
handler.startElement("zone", attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# short
|
|
Packit |
a8ec6b |
if zone.short and zone.short != "":
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.startElement("short", { })
|
|
Packit |
a8ec6b |
handler.characters(zone.short)
|
|
Packit |
a8ec6b |
handler.endElement("short")
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# description
|
|
Packit |
a8ec6b |
if zone.description and zone.description != "":
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.startElement("description", { })
|
|
Packit |
a8ec6b |
handler.characters(zone.description)
|
|
Packit |
a8ec6b |
handler.endElement("description")
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# interfaces
|
|
Packit |
a8ec6b |
for interface in uniqify(zone.interfaces):
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("interface", { "name": interface })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# source
|
|
Packit |
a8ec6b |
for source in uniqify(zone.sources):
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
if "ipset:" in source:
|
|
Packit |
a8ec6b |
handler.simpleElement("source", { "ipset": source[6:] })
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
handler.simpleElement("source", { "address": source })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# services
|
|
Packit |
a8ec6b |
for service in uniqify(zone.services):
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("service", { "name": service })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# ports
|
|
Packit |
a8ec6b |
for port in uniqify(zone.ports):
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("port", { "port": port[0], "protocol": port[1] })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# protocols
|
|
Packit |
a8ec6b |
for protocol in uniqify(zone.protocols):
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("protocol", { "value": protocol })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# icmp-block-inversion
|
|
Packit |
a8ec6b |
if zone.icmp_block_inversion:
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("icmp-block-inversion", { })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# icmp-blocks
|
|
Packit |
a8ec6b |
for icmp in uniqify(zone.icmp_blocks):
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("icmp-block", { "name": icmp })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# masquerade
|
|
Packit |
a8ec6b |
if zone.masquerade:
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("masquerade", { })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# forward-ports
|
|
Packit |
a8ec6b |
for forward in uniqify(zone.forward_ports):
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
attrs = { "port": forward[0], "protocol": forward[1] }
|
|
Packit |
a8ec6b |
if forward[2] and forward[2] != "" :
|
|
Packit |
a8ec6b |
attrs["to-port"] = forward[2]
|
|
Packit |
a8ec6b |
if forward[3] and forward[3] != "" :
|
|
Packit |
a8ec6b |
attrs["to-addr"] = forward[3]
|
|
Packit |
a8ec6b |
handler.simpleElement("forward-port", attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# source-ports
|
|
Packit |
a8ec6b |
for port in uniqify(zone.source_ports):
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("source-port", { "port": port[0],
|
|
Packit |
a8ec6b |
"protocol": port[1] })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# rules
|
|
Packit |
a8ec6b |
for rule in zone.rules:
|
|
Packit |
a8ec6b |
attrs = { }
|
|
Packit |
a8ec6b |
if rule.family:
|
|
Packit |
a8ec6b |
attrs["family"] = rule.family
|
|
Packit |
a8ec6b |
if rule.priority != 0:
|
|
Packit |
a8ec6b |
attrs["priority"] = str(rule.priority)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.startElement("rule", attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# source
|
|
Packit |
a8ec6b |
if rule.source:
|
|
Packit |
a8ec6b |
attrs = { }
|
|
Packit |
a8ec6b |
if rule.source.addr:
|
|
Packit |
a8ec6b |
attrs["address"] = rule.source.addr
|
|
Packit |
a8ec6b |
if rule.source.mac:
|
|
Packit |
a8ec6b |
attrs["mac"] = rule.source.mac
|
|
Packit |
a8ec6b |
if rule.source.ipset:
|
|
Packit |
a8ec6b |
attrs["ipset"] = rule.source.ipset
|
|
Packit |
a8ec6b |
if rule.source.invert:
|
|
Packit |
a8ec6b |
attrs["invert"] = "True"
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("source", attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# destination
|
|
Packit |
a8ec6b |
if rule.destination:
|
|
Packit |
a8ec6b |
attrs = { "address": rule.destination.addr }
|
|
Packit |
a8ec6b |
if rule.destination.invert:
|
|
Packit |
a8ec6b |
attrs["invert"] = "True"
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("destination", attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# element
|
|
Packit |
a8ec6b |
if rule.element:
|
|
Packit |
a8ec6b |
element = ""
|
|
Packit |
a8ec6b |
attrs = { }
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
if type(rule.element) == rich.Rich_Service:
|
|
Packit |
a8ec6b |
element = "service"
|
|
Packit |
a8ec6b |
attrs["name"] = rule.element.name
|
|
Packit |
a8ec6b |
elif type(rule.element) == rich.Rich_Port:
|
|
Packit |
a8ec6b |
element = "port"
|
|
Packit |
a8ec6b |
attrs["port"] = rule.element.port
|
|
Packit |
a8ec6b |
attrs["protocol"] = rule.element.protocol
|
|
Packit |
a8ec6b |
elif type(rule.element) == rich.Rich_Protocol:
|
|
Packit |
a8ec6b |
element = "protocol"
|
|
Packit |
a8ec6b |
attrs["value"] = rule.element.value
|
|
Packit |
a8ec6b |
elif type(rule.element) == rich.Rich_Masquerade:
|
|
Packit |
a8ec6b |
element = "masquerade"
|
|
Packit |
a8ec6b |
elif type(rule.element) == rich.Rich_IcmpBlock:
|
|
Packit |
a8ec6b |
element = "icmp-block"
|
|
Packit |
a8ec6b |
attrs["name"] = rule.element.name
|
|
Packit |
a8ec6b |
elif type(rule.element) == rich.Rich_IcmpType:
|
|
Packit |
a8ec6b |
element = "icmp-type"
|
|
Packit |
a8ec6b |
attrs["name"] = rule.element.name
|
|
Packit |
a8ec6b |
elif type(rule.element) == rich.Rich_ForwardPort:
|
|
Packit |
a8ec6b |
element = "forward-port"
|
|
Packit |
a8ec6b |
attrs["port"] = rule.element.port
|
|
Packit |
a8ec6b |
attrs["protocol"] = rule.element.protocol
|
|
Packit |
a8ec6b |
if rule.element.to_port != "":
|
|
Packit |
a8ec6b |
attrs["to-port"] = rule.element.to_port
|
|
Packit |
a8ec6b |
if rule.element.to_address != "":
|
|
Packit |
a8ec6b |
attrs["to-addr"] = rule.element.to_address
|
|
Packit |
a8ec6b |
elif type(rule.element) == rich.Rich_SourcePort:
|
|
Packit |
a8ec6b |
element = "source-port"
|
|
Packit |
a8ec6b |
attrs["port"] = rule.element.port
|
|
Packit |
a8ec6b |
attrs["protocol"] = rule.element.protocol
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
raise FirewallError(
|
|
Packit |
a8ec6b |
errors.INVALID_OBJECT,
|
|
Packit |
a8ec6b |
"Unknown element '%s' in zone_writer" % type(rule.element))
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement(element, attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# rule.element
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# log
|
|
Packit |
a8ec6b |
if rule.log:
|
|
Packit |
a8ec6b |
attrs = { }
|
|
Packit |
a8ec6b |
if rule.log.prefix:
|
|
Packit |
a8ec6b |
attrs["prefix"] = rule.log.prefix
|
|
Packit |
a8ec6b |
if rule.log.level:
|
|
Packit |
a8ec6b |
attrs["level"] = rule.log.level
|
|
Packit |
a8ec6b |
if rule.log.limit:
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.startElement("log", attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n ")
|
|
Packit |
a8ec6b |
handler.simpleElement("limit",
|
|
Packit |
a8ec6b |
{ "value": rule.log.limit.value })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n ")
|
|
Packit |
a8ec6b |
handler.endElement("log")
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("log", attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# audit
|
|
Packit |
a8ec6b |
if rule.audit:
|
|
Packit |
a8ec6b |
attrs = {}
|
|
Packit |
a8ec6b |
if rule.audit.limit:
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.startElement("audit", { })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n ")
|
|
Packit |
a8ec6b |
handler.simpleElement("limit",
|
|
Packit |
a8ec6b |
{ "value": rule.audit.limit.value })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n ")
|
|
Packit |
a8ec6b |
handler.endElement("audit")
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement("audit", attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# action
|
|
Packit |
a8ec6b |
if rule.action:
|
|
Packit |
a8ec6b |
action = ""
|
|
Packit |
a8ec6b |
attrs = { }
|
|
Packit |
a8ec6b |
if type(rule.action) == rich.Rich_Accept:
|
|
Packit |
a8ec6b |
action = "accept"
|
|
Packit |
a8ec6b |
elif type(rule.action) == rich.Rich_Reject:
|
|
Packit |
a8ec6b |
action = "reject"
|
|
Packit |
a8ec6b |
if rule.action.type:
|
|
Packit |
a8ec6b |
attrs["type"] = rule.action.type
|
|
Packit |
a8ec6b |
elif type(rule.action) == rich.Rich_Drop:
|
|
Packit |
a8ec6b |
action = "drop"
|
|
Packit |
a8ec6b |
elif type(rule.action) == rich.Rich_Mark:
|
|
Packit |
a8ec6b |
action = "mark"
|
|
Packit |
a8ec6b |
attrs["set"] = rule.action.set
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
log.warning("Unknown action '%s'", type(rule.action))
|
|
Packit |
a8ec6b |
if rule.action.limit:
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.startElement(action, attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n ")
|
|
Packit |
a8ec6b |
handler.simpleElement("limit",
|
|
Packit |
a8ec6b |
{ "value": rule.action.limit.value })
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n ")
|
|
Packit |
a8ec6b |
handler.endElement(action)
|
|
Packit |
a8ec6b |
else:
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.simpleElement(action, attrs)
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace(" ")
|
|
Packit |
a8ec6b |
handler.endElement("rule")
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
|
|
Packit |
a8ec6b |
# end zone element
|
|
Packit |
a8ec6b |
handler.endElement("zone")
|
|
Packit |
a8ec6b |
handler.ignorableWhitespace("\n")
|
|
Packit |
a8ec6b |
handler.endDocument()
|
|
Packit |
a8ec6b |
f.close()
|
|
Packit |
a8ec6b |
del handler
|