diff --git a/etc/neutron/rootwrap.d/fwaas-privsep.filters b/etc/neutron/rootwrap.d/fwaas-privsep.filters index 0aa1040aa..6b631417d 100644 --- a/etc/neutron/rootwrap.d/fwaas-privsep.filters +++ b/etc/neutron/rootwrap.d/fwaas-privsep.filters @@ -4,7 +4,4 @@ [Filters] -privsep: PathFilter, privsep-helper, root, - --config-file, /etc, - --privsep_context, neutron_fwaas.privileged.default, - --privsep_sock_path, / +privsep-rootwrap: PathFilter, privsep-helper, root, privsep-helper, --config-file, /etc/(?!\.\.).*, --privsep_context, neutron_fwaas.privileged.default diff --git a/neutron_fwaas/common/netlink_constants.py b/neutron_fwaas/common/netlink_constants.py deleted file mode 100644 index 7e4cd5bde..000000000 --- a/neutron_fwaas/common/netlink_constants.py +++ /dev/null @@ -1,268 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# Some parts are based on python-conntrack: -# Copyright (c) 2009-2011,2015 Andrew Grigorev -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# - -""" -Conntrack - A simple python interface to libnetfilter_conntrack using ctypes. -""" - -NFCT_OF_SHOW_LAYER3_BIT = 0 -NFCT_OF_SHOW_LAYER3 = (1 << NFCT_OF_SHOW_LAYER3_BIT) -NFCT_OF_TIME_BIT = 1 -NFCT_OF_TIME = (1 << NFCT_OF_TIME_BIT) -NFCT_OF_ID_BIT = 2 -NFCT_OF_ID = (1 << NFCT_OF_ID_BIT) - - -CONNTRACK = 0 - -# Callback return codes -NFCT_CB_FAILURE = -1 # failure -NFCT_CB_STOP = 0 # stop the query -NFCT_CB_CONTINUE = 1 # keep iterating through data -NFCT_CB_STOLEN = 2 # like continue, but ct is not freed - - -# Queries -NFCT_Q_CREATE = 0 -NFCT_Q_UPDATE = 1 -NFCT_Q_DESTROY = 2 -NFCT_Q_GET = 3 -NFCT_Q_FLUSH = 4 -NFCT_Q_DUMP = 5 -NFCT_Q_DUMP_RESET = 6 -NFCT_Q_CREATE_UPDATE = 7 -NFCT_Q_DUMP_FILTER = 8 -NFCT_Q_DUMP_FILTER_RESET = 9 - -# Message types -NFCT_T_UNKNOWN = 0 -NFCT_T_NEW_BIT = 0 -NFCT_T_NEW = (1 << NFCT_T_NEW_BIT) -NFCT_T_UPDATE_BIT = 1 -NFCT_T_UPDATE = (1 << NFCT_T_UPDATE_BIT) -NFCT_T_DESTROY_BIT = 2 -NFCT_T_DESTROY = (1 << NFCT_T_DESTROY_BIT) - -NFCT_T_ALL = NFCT_T_NEW | NFCT_T_UPDATE | NFCT_T_DESTROY -NFCT_T_ERROR_BIT = 31 -NFCT_T_ERROR = (1 << NFCT_T_ERROR_BIT) - -# Attributes -ATTR_ORIG_IPV4_SRC = 0 # u32 bits -ATTR_IPV4_SRC = ATTR_ORIG_IPV4_SRC # alias -ATTR_ORIG_IPV4_DST = 1 # u32 bits -ATTR_IPV4_DST = ATTR_ORIG_IPV4_DST # alias -ATTR_REPL_IPV4_SRC = 2 # u32 bits -ATTR_REPL_IPV4_DST = 3 # u32 bits -ATTR_ORIG_IPV6_SRC = 4 # u128 bits -ATTR_IPV6_SRC = ATTR_ORIG_IPV6_SRC # alias -ATTR_ORIG_IPV6_DST = 5 # u128 bits -ATTR_IPV6_DST = ATTR_ORIG_IPV6_DST # alias -ATTR_REPL_IPV6_SRC = 6 # u128 bits -ATTR_REPL_IPV6_DST = 7 # u128 bits -ATTR_ORIG_PORT_SRC = 8 # u16 bits -ATTR_PORT_SRC = ATTR_ORIG_PORT_SRC # alias -ATTR_ORIG_PORT_DST = 9 # u16 bits -ATTR_PORT_DST = ATTR_ORIG_PORT_DST # alias -ATTR_REPL_PORT_SRC = 10 # u16 bits -ATTR_REPL_PORT_DST = 11 # u16 bits -ATTR_ICMP_TYPE = 12 # u8 bits -ATTR_ICMP_CODE = 13 # u8 bits -ATTR_ICMP_ID = 14 # u16 bits -ATTR_ORIG_L3PROTO = 15 # u8 bits -ATTR_L3PROTO = ATTR_ORIG_L3PROTO # alias -ATTR_REPL_L3PROTO = 16 # u8 bits -ATTR_ORIG_L4PROTO = 17 # u8 bits -ATTR_L4PROTO = ATTR_ORIG_L4PROTO # alias -ATTR_REPL_L4PROTO = 18 # u8 bits -ATTR_TCP_STATE = 19 # u8 bits -ATTR_SNAT_IPV4 = 20 # u32 bits -ATTR_DNAT_IPV4 = 21 # u32 bits -ATTR_SNAT_PORT = 22 # u16 bits -ATTR_DNAT_PORT = 23 # u16 bits -ATTR_TIMEOUT = 24 # u32 bits -ATTR_MARK = 25 # u32 bits -ATTR_ORIG_COUNTER_PACKETS = 26 # u32 bits -ATTR_REPL_COUNTER_PACKETS = 27 # u32 bits -ATTR_ORIG_COUNTER_BYTES = 28 # u32 bits -ATTR_REPL_COUNTER_BYTES = 29 # u32 bits -ATTR_USE = 30 # u32 bits -ATTR_ID = 31 # u32 bits -ATTR_STATUS = 32 # u32 bits -ATTR_TCP_FLAGS_ORIG = 33 # u8 bits -ATTR_TCP_FLAGS_REPL = 34 # u8 bits -ATTR_TCP_MASK_ORIG = 35 # u8 bits -ATTR_TCP_MASK_REPL = 36 # u8 bits -ATTR_MASTER_IPV4_SRC = 37 # u32 bits -ATTR_MASTER_IPV4_DST = 38 # u32 bits -ATTR_MASTER_IPV6_SRC = 39 # u128 bits -ATTR_MASTER_IPV6_DST = 40 # u128 bits -ATTR_MASTER_PORT_SRC = 41 # u16 bits -ATTR_MASTER_PORT_DST = 42 # u16 bits -ATTR_MASTER_L3PROTO = 43 # u8 bits -ATTR_MASTER_L4PROTO = 44 # u8 bits -ATTR_SECMARK = 45 # u32 bits -ATTR_ORIG_NAT_SEQ_CORRECTION_POS = 46 # u32 bits -ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE = 47 # u32 bits -ATTR_ORIG_NAT_SEQ_OFFSET_AFTER = 48 # u32 bits -ATTR_REPL_NAT_SEQ_CORRECTION_POS = 49 # u32 bits -ATTR_REPL_NAT_SEQ_OFFSET_BEFORE = 50 # u32 bits -ATTR_REPL_NAT_SEQ_OFFSET_AFTER = 51 # u32 bits -ATTR_SCTP_STATE = 52 # u8 bits -ATTR_SCTP_VTAG_ORIG = 53 # u32 bits -ATTR_SCTP_VTAG_REPL = 54 # u32 bits -ATTR_HELPER_NAME = 55 # string (30 bytes max) -ATTR_DCCP_STATE = 56 # u8 bits -ATTR_DCCP_ROLE = 57 # u8 bits -ATTR_DCCP_HANDSHAKE_SEQ = 58 # u64 bits -ATTR_MAX = 59 -ATTR_GRP_ORIG_IPV4 = 0 # struct nfct_attr_grp_ipv4 -ATTR_GRP_REPL_IPV4 = 1 # struct nfct_attr_grp_ipv4 -ATTR_GRP_ORIG_IPV6 = 2 # struct nfct_attr_grp_ipv6 -ATTR_GRP_REPL_IPV6 = 3 # struct nfct_attr_grp_ipv6 -ATTR_GRP_ORIG_PORT = 4 # struct nfct_attr_grp_port -ATTR_GRP_REPL_PORT = 5 # struct nfct_attr_grp_port -ATTR_GRP_ICMP = 6 # struct nfct_attr_grp_icmp -ATTR_GRP_MASTER_IPV4 = 7 # struct nfct_attr_grp_ipv4 -ATTR_GRP_MASTER_IPV6 = 8 # struct nfct_attr_grp_ipv6 -ATTR_GRP_MASTER_PORT = 9 # struct nfct_attr_grp_port -ATTR_GRP_ORIG_COUNTERS = 10 # struct nfct_attr_grp_ctrs -ATTR_GRP_REPL_COUNTERS = 11 # struct nfct_attr_grp_ctrs -ATTR_GRP_MAX = 12 -ATTR_EXP_MASTER = 0 # pointer to conntrack object -ATTR_EXP_EXPECTED = 1 # pointer to conntrack object -ATTR_EXP_MASK = 2 # pointer to conntrack object -ATTR_EXP_TIMEOUT = 3 # u32 bits -ATTR_EXP_MAX = 4 - -# NFCT_*printf output format -NFCT_O_PLAIN = 0 -NFCT_O_DEFAULT = NFCT_O_PLAIN -NFCT_O_XML = 1 -NFCT_O_MAX = 2 - - -NFCT_CMP_ALL = 0 -NFCT_CMP_ORIG = (1 << 0) -NFCT_CMP_REPL = (1 << 1) -NFCT_CMP_TIMEOUT_EQ = (1 << 2) -NFCT_CMP_TIMEOUT_GT = (1 << 3) -NFCT_CMP_TIMEOUT_GE = (NFCT_CMP_TIMEOUT_EQ | NFCT_CMP_TIMEOUT_GT) -NFCT_CMP_TIMEOUT_LT = (1 << 4) -NFCT_CMP_TIMEOUT_LE = (NFCT_CMP_TIMEOUT_EQ | NFCT_CMP_TIMEOUT_LT) -NFCT_CMP_MASK = (1 << 5) -NFCT_CMP_STRICT = (1 << 6) - -# Conntrack options -CT_OPT_ORIG_SRC_BIT = 0 -CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT) - -CT_OPT_ORIG_DST_BIT = 1 -CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT) - -CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST) - -CT_OPT_REPL_SRC_BIT = 2 -CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT) - -CT_OPT_REPL_DST_BIT = 3 -CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT) - -CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST) - -CT_OPT_PROTO_BIT = 4 -CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT) - -CT_OPT_TUPLE_ORIG = (CT_OPT_ORIG | CT_OPT_PROTO) -CT_OPT_TUPLE_REPL = (CT_OPT_REPL | CT_OPT_PROTO) - -CT_OPT_TIMEOUT_BIT = 5 -CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT) - -CT_OPT_STATUS_BIT = 6 -CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT) - -CT_OPT_ZERO_BIT = 7 -CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT) - -CT_OPT_EVENT_MASK_BIT = 8 -CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT) - -CT_OPT_EXP_SRC_BIT = 9 -CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT) - -CT_OPT_EXP_DST_BIT = 10 -CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT) - -CT_OPT_MASK_SRC_BIT = 11 -CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT) - -CT_OPT_MASK_DST_BIT = 12 -CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT) - -CT_OPT_NATRANGE_BIT = 13 -CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT) - -CT_OPT_MARK_BIT = 14 -CT_OPT_MARK = (1 << CT_OPT_MARK_BIT) - -CT_OPT_ID_BIT = 15 -CT_OPT_ID = (1 << CT_OPT_ID_BIT) - -CT_OPT_FAMILY_BIT = 16 -CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT) - -CT_OPT_SRC_NAT_BIT = 17 -CT_OPT_SRC_NAT = (1 << CT_OPT_SRC_NAT_BIT) - -CT_OPT_DST_NAT_BIT = 18 -CT_OPT_DST_NAT = (1 << CT_OPT_DST_NAT_BIT) - -CT_OPT_OUTPUT_BIT = 19 -CT_OPT_OUTPUT = (1 << CT_OPT_OUTPUT_BIT) - -CT_OPT_SECMARK_BIT = 20 -CT_OPT_SECMARK = (1 << CT_OPT_SECMARK_BIT) - -CT_OPT_BUFFERSIZE_BIT = 21 -CT_OPT_BUFFERSIZE = (1 << CT_OPT_BUFFERSIZE_BIT) - -CT_OPT_ANY_NAT_BIT = 22 -CT_OPT_ANY_NAT = (1 << CT_OPT_ANY_NAT_BIT) - -CT_OPT_ZONE_BIT = 23 -CT_OPT_ZONE = (1 << CT_OPT_ZONE_BIT) - -CT_COMPARISON = (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK | - CT_OPT_SECMARK | CT_OPT_STATUS | CT_OPT_ID | CT_OPT_ZONE) diff --git a/neutron_fwaas/privileged/__init__.py b/neutron_fwaas/privileged/__init__.py deleted file mode 100644 index cc1584ae3..000000000 --- a/neutron_fwaas/privileged/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_privsep import capabilities as c -from oslo_privsep import priv_context - -# It is expected that most (if not all) neutron operations can be -# executed with these privileges. -default = priv_context.PrivContext( - __name__, - cfg_section='privsep', - pypath=__name__ + '.default', - # TODO(gus): CAP_SYS_ADMIN is required (only?) for manipulating - # network namespaces. SYS_ADMIN is a lot of scary powers, so - # consider breaking this out into a separate minimal context. - capabilities=[c.CAP_SYS_ADMIN, c.CAP_NET_ADMIN], -) diff --git a/neutron_fwaas/privileged/netlink_lib.py b/neutron_fwaas/privileged/netlink_lib.py deleted file mode 100644 index 50064cc0d..000000000 --- a/neutron_fwaas/privileged/netlink_lib.py +++ /dev/null @@ -1,272 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# Some parts are based on python-conntrack: -# Copyright (c) 2009-2011,2015 Andrew Grigorev -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# - -""" -Conntrack - A simple python interface to libnetfilter_conntrack using ctypes. -""" - -import ctypes as c -from ctypes.util import find_library -import os -from socket import AF_INET -from socket import AF_INET6 - -from pyroute2 import netns as pynetns - -from oslo_log import log as logging - -from neutron_fwaas._i18n import _LE -from neutron_fwaas.common import netlink_constants as nl_constants - -from neutron_fwaas import privileged - -LOG = logging.getLogger(__name__) - -nfct = c.CDLL(find_library('netfilter_conntrack')) -libc = c.CDLL(find_library('libc.so.6')) - -proto_num = { - 'tcp': 6, - 'udp': 17, - 'icmp': 1, -} - -family_socket = { - 4: AF_INET, - 6: AF_INET6, -} - -NFCT_CALLBACK = c.CFUNCTYPE(c.c_int, c.c_int, c.c_void_p, c.c_void_p) - - -def _list(family=4): - """ - Get list of active conntrack entries. - - :param: family: ipversion of conntrack entries to be listed. - :return: entries: list of conntrack entries. - """ - entries = [] - buf = c.create_string_buffer(1024) - - @NFCT_CALLBACK - def cb(type, ct, data): - nfct.nfct_snprintf(buf, 1024, ct, type, 0, nl_constants.NFCT_OF_TIME) - entries.append(buf.value) - return nl_constants.NFCT_CB_CONTINUE - - h = nfct.nfct_open(nl_constants.CONNTRACK, 0) - - if not h: - LOG.exception(_LE("nfct_open failed!")) - return entries - - nfct.nfct_callback_register(h, nl_constants.NFCT_T_ALL, cb, 0) - ret = nfct.nfct_query(h, nl_constants.NFCT_Q_DUMP, - c.byref(c.c_int(family_socket[family]))) - if ret == -1: - nfct.nfct_close(h) - LOG.exception(_LE("nfct_query failed!")) - return entries - nfct.nfct_close(h) - return entries - - -def _kill(**kwargs): - """ - Delete specified conntrack entries. - - :param: kwargs: entry information - :return: None - """ - family = kwargs.get('family', 4) - protocol = kwargs.get('protocol', 'tcp') - source_address = kwargs.get('src', '0.0.0.0') - destination_address = kwargs.get('dst', '0.0.0.0') - - ct = nfct.nfct_new() - if not ct: - LOG.exception(_LE("nfct_new failed!")) - return - - nfct.nfct_set_attr_u8(ct, nl_constants.ATTR_L3PROTO, family_socket[family]) - - if family == 4: - nfct.nfct_set_attr_u32(ct, nl_constants.ATTR_IPV4_SRC, - libc.inet_addr(source_address)) - nfct.nfct_set_attr_u32(ct, nl_constants.ATTR_IPV4_DST, - libc.inet_addr(destination_address)) - elif family == 6: - nfct.nfct_set_attr_u64(ct, nl_constants.ATTR_IPV6_SRC, - libc.inet_addr(source_address)) - nfct.nfct_set_attr_u64(ct, nl_constants.ATTR_IPV6_DST, - libc.inet_addr(destination_address)) - else: - LOG.exception(_LE("Unsupported protocol family!")) - - nfct.nfct_set_attr_u8(ct, nl_constants.ATTR_L4PROTO, proto_num[protocol]) - - if protocol == 'icmp': - nfct.nfct_set_attr_u8(ct, nl_constants.ATTR_ICMP_TYPE, - kwargs.get('icmp_type', 8)) - nfct.nfct_set_attr_u8(ct, nl_constants.ATTR_ICMP_CODE, - kwargs.get('icmp_code', 0)) - nfct.nfct_set_attr_u16(ct, nl_constants.ATTR_ICMP_ID, - libc.htons(kwargs.get('icmp_id'), 0)) - else: - nfct.nfct_set_attr_u16(ct, nl_constants.ATTR_PORT_SRC, - libc.htons(kwargs.get('sport'))) - nfct.nfct_set_attr_u16(ct, nl_constants.ATTR_PORT_DST, - libc.htons(kwargs.get('dport'))) - h = nfct.nfct_open(nl_constants.CONNTRACK, 0) - if not h: - LOG.exception(_LE("nfct_open failed!")) - else: - ret = nfct.nfct_query(h, nl_constants.NFCT_Q_DESTROY, ct) - if ret == -1: - LOG.exception(_LE("Deleting conntrack failed")) - nfct.nfct_close(h) - nfct.nfct_destroy(ct) - - -def _flush(): - ct = nfct.nfct_new() - if not ct: - libc.perror("nfct_new") - raise LOG.exception(_LE("nfct_new failed!")) - return - h = nfct.nfct_open(nl_constants.CONNTRACK, 0) - if not h: - libc.perror("nfct_open") - raise LOG.exception(_LE("nfct_open failed!")) - else: - ret = nfct.nfct_query(h, nl_constants.NFCT_Q_FLUSH, ct) - if ret == -1: - libc.perror("nfct_query") - raise LOG.exception(_LE("nfct_query failed!")) - nfct.nfct_close(h) - nfct.nfct_destroy(ct) - - -def _parse_entry(entry, ipversion): - """ - Parse entry to a tuple - - :param entry: Array from entry string split - :param ipversion: ipversion used to get this entry - :return: a tuple of parsed entry - example: (4, 'tcp', '1111', '2222', '1.1.1.1', '2.2.2.2') - """ - protocol = entry[1] - if protocol == 'tcp': - src_address = entry[5].split('=')[1] - dst_address = entry[6].split('=')[1] - sport = entry[7].split('=')[1] - dport = entry[8].split('=')[1] - elif protocol == 'udp': - src_address = entry[4].split('=')[1] - dst_address = entry[5].split('=')[1] - sport = entry[6].split('=')[1] - dport = entry[7].split('=')[1] - elif protocol == 'icmp': - src_address = entry[4].split('=')[1] - dst_address = entry[5].split('=')[1] - icmp_type = entry[6].split('=')[1] - icmp_code = entry[7].split('=')[1] - icmp_id = entry[8].split('=')[1] - parsed_entry = (ipversion, protocol, icmp_type, icmp_code, - src_address, dst_address, icmp_id,) - return parsed_entry - parsed_entry = (ipversion, protocol, sport, - dport, src_address, dst_address,) - return parsed_entry - - -@privileged.default.entrypoint -def list_entries(namespace): - """ - List, parse and sort all entries - - :param namespace: - :return: sorted list of entry tuples. - example: [(4, 'icmp', '8', '0', '1.1.1.1', '2.2.2.2'), - (4, 'tcp', '1111', '2222', '1.1.1.1', '2.2.2.2')] - """ - entries = [] - if namespace: - fd = pynetns.setns(namespace) - ipversions = [4, 6] - for ipversion in ipversions: - xentries = _list(ipversion) - for entry in xentries: - sentry = entry.split() - xentry = _parse_entry(sentry, ipversion) - entries.append(xentry) - os.close(fd) - return sorted(entries) - - -def _kill_entry(entry): - """ - Kill the entry - - :param entry: (ipversion, protocol, sport, dport, saddress, daddress) - """ - - if entry[1] == 'icmp': - _kill(family=entry[0], protocol=entry[1], - src=entry[4], dst=entry[5], - icmp_type=int(entry[2]), icmp_code=int(entry[3]), - icmp_id=int(entry[6])) - else: - _kill(family=entry[0], protocol=entry[1], - src=entry[4], dst=entry[5], - sport=int(entry[2]), dport=int(entry[3])) - - -@privileged.default.entrypoint -def kill_entries(namespace, entries): - if namespace: - fd = pynetns.setns(namespace) - for entry in entries: - _kill_entry(entry) - os.close(fd) - - -@privileged.default.entrypoint -def flush_entries(namespace): - if namespace: - fd = pynetns.setns(namespace) - _flush() - os.close(fd) diff --git a/neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent.py b/neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent.py index c4df3c049..63f13651a 100644 --- a/neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent.py +++ b/neutron_fwaas/services/firewall/agents/l3reference/firewall_l3_agent.py @@ -13,7 +13,6 @@ # License for the specific language governing permissions and limitations # under the License. -from neutron.agent.common import config from neutron.common import rpc as n_rpc from neutron import context from oslo_config import cfg @@ -62,7 +61,6 @@ class FWaaSL3AgentExtension(l3_extension.L3AgentExtension): f_resources.FIREWALL_RULE] def initialize(self, connection, driver_type): - config.setup_privsep() self._register_rpc_consumers(connection) def consume_api(self, agent_api): diff --git a/neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas.py b/neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas.py index 49e86ade6..61f1b2879 100644 --- a/neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas.py +++ b/neutron_fwaas/services/firewall/drivers/linux/iptables_fwaas.py @@ -12,13 +12,14 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + from neutron.agent.linux import iptables_manager +from neutron.agent.linux import utils as linux_utils from oslo_log import log as logging from neutron_fwaas._i18n import _LE from neutron_fwaas.common import fwaas_constants as f_const from neutron_fwaas.extensions import firewall as fw_ext -from neutron_fwaas.privileged import netlink_lib from neutron_fwaas.services.firewall.drivers import fwaas_base LOG = logging.getLogger(__name__) @@ -256,6 +257,26 @@ class IptablesFwaasDriver(fwaas_base.FwaasDriverBase): def _find_new_rules(self, pre_firewall, firewall): return self._find_removed_rules(firewall, pre_firewall) + def _get_conntrack_cmd_from_rule(self, ipt_mgr, rule=None): + prefixcmd = ['ip', 'netns', 'exec'] + [ipt_mgr.namespace] + cmd = ['conntrack', '-D'] + if rule: + conntrack_filter = self._get_conntrack_filter_from_rule(rule) + exec_cmd = prefixcmd + cmd + conntrack_filter + else: + exec_cmd = prefixcmd + cmd + return exec_cmd + + def _remove_conntrack_by_cmd(self, cmd): + if cmd: + try: + linux_utils.execute(cmd, run_as_root=True, + check_exit_code=True, + extra_ok_codes=[1]) + except RuntimeError: + LOG.exception( + _LE("Failed execute conntrack command %s"), str(cmd)) + def _remove_conntrack_new_firewall(self, agent_mode, apply_list, firewall): """Remove conntrack when create new firewall""" routers_list = list(set(apply_list)) @@ -264,7 +285,8 @@ class IptablesFwaasDriver(fwaas_base.FwaasDriverBase): agent_mode, router_info) for ipt_if_prefix in ipt_if_prefix_list: ipt_mgr = ipt_if_prefix['ipt'] - self._flush_conntrack_netlink(ipt_mgr.namespace) + cmd = self._get_conntrack_cmd_from_rule(ipt_mgr) + self._remove_conntrack_by_cmd(cmd) def _remove_conntrack_updated_firewall(self, agent_mode, apply_list, pre_firewall, firewall): @@ -280,78 +302,27 @@ class IptablesFwaasDriver(fwaas_base.FwaasDriverBase): i_rules = self._find_new_rules(pre_firewall, firewall) r_rules = self._find_removed_rules(pre_firewall, firewall) removed_conntrack_rules_list = ch_rules + i_rules + r_rules - rules = [] for rule in removed_conntrack_rules_list: - rules.append(self._get_filters_from_rules(rule)) - rules = sorted(list(set(rules))) - self._remove_conntrack_netlink(ipt_mgr.namespace, rules) + cmd = self._get_conntrack_cmd_from_rule(ipt_mgr, rule) + self._remove_conntrack_by_cmd(cmd) - @staticmethod - def _entry2delete(rule, entry): + def _get_conntrack_filter_from_rule(self, rule): + """Get conntrack filter from rule. + The key for get conntrack filter is protocol, destination_port + and source_port. If we want to take more keys, add to the list. """ - Check if an entry will be delete or not - - :param rule: (ipversion, protocol, sport, dport) - :param entry: (ipversion, protocol, sport, dport, saddress, daddress) - :return: True if the entry matches the rule - The entry matches the rule if it has the same ipversion, protocol or - entry source port, destination port sequentially in rule source port, - destination port range. - """ - return ( - (entry[0] == rule[0]) and (not rule[1] or entry[1] == rule[1]) and - (not rule[2] or int(entry[2]) in range(int(rule[2].split(':')[0]), - int(rule[2].split(':')[-1]) + 1)) and - (not rule[2] or int(entry[2]) in range(int(rule[2].split(':')[0]), - int(rule[2].split(':')[-1]) + 1))) - - def _remove_conntrack_netlink(self, namespace, rules): - # Getting a list of all entries - entries = netlink_lib.list_entries(namespace) - - # Compare each entry to each rule to define that this entry - # is to delete or not. - # rule and entry have the same parameters order to be comparable: - # rule: (ipversion, protocol, sport, dport) - # entry: (ipversion, protocol, sport, dport, saddress, daddress) - # rules and entries were sorted lists of tuples to reduce the - # number of comparisons. - dentries = [] - ientry = 0 - entryNumber = len(entries) - for rule in rules: - while ientry < entryNumber and entries[ientry] < rule: - ientry += 1 - while (ientry < entryNumber and - self._entry2delete(rule, entries[ientry])): - dentries.append(entries[ientry]) - ientry += 1 - - # Calling to netlink_lib.kill_entries to delete entries - netlink_lib.kill_entries(namespace, dentries) - - def _flush_conntrack_netlink(self, namespace): - netlink_lib.flush_entries(namespace) - - def _get_filters_from_rules(self, rule): - """Parse parameters from firewall rules - - :param: rule: A firewall rule - :return filter: Tuple of parameters - example: (4, 'tcp', 1111, 2222, '1.1.1.1', '2.2.2.2') - """ - - keys = ['ip_version', 'protocol', 'source_port', 'destination_port'] - addr_keys = ['source_ip_address', 'destination_ip_address'] - rule_filter = [] + conntrack_filter = [] + keys = [['-p', 'protocol'], ['-f', 'ip_version'], + ['--dport', 'destination_port'], ['--sport', 'source_port']] for key in keys: - rule_filter.append(rule.get(key) or '') - for key in addr_keys: - if not rule.get(key): - rule_filter.append('') - else: - rule_filter.append(rule.get(key)) - return tuple(rule_filter) + if rule.get(key[1]): + if key[1] == 'ip_version': + conntrack_filter.append(key[0]) + conntrack_filter.append('ipv' + str(rule.get(key[1]))) + else: + conntrack_filter.append(key[0]) + conntrack_filter.append(rule.get(key[1])) + return conntrack_filter def _remove_default_chains(self, nsid): """Remove fwaas default policy chain.""" diff --git a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas.py b/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas.py index 5fcf172e0..5f0404172 100644 --- a/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas.py +++ b/neutron_fwaas/tests/unit/services/firewall/drivers/linux/test_iptables_fwaas.py @@ -27,8 +27,6 @@ FAKE_DST_PREFIX = '20.0.0.0/24' FAKE_PROTOCOL = 'tcp' FAKE_SRC_PORT = 5000 FAKE_DST_PORT = 22 -FAKE_ENTRY = [(4, 'icmp', '8', '0', '1000', '1.1.1.1', '2.2.2.2'), - (4, 'tcp', '1111', '23', '1.1.1.1', '2.2.2.2'), ] FAKE_FW_ID = 'fake-fw-uuid' FW_LEGACY = 'legacy' @@ -42,12 +40,6 @@ class IptablesFwaasTestCase(base.BaseTestCase): self.iptables_cls_p = mock.patch( 'neutron.agent.linux.iptables_manager.IptablesManager') self.iptables_cls_p.start() - self.netlink_kill_p = mock.patch( - 'neutron_fwaas.privileged.netlink_lib.kill_entries') - self.netlink_kill_p.start() - self.netlink_flush_p = mock.patch( - 'neutron_fwaas.privileged.netlink_lib.flush_entries') - self.netlink_flush = self.netlink_flush_p.start() self.firewall = fwaas.IptablesFwaasDriver() def _fake_rules_v4(self, fwid, apply_list): @@ -293,11 +285,13 @@ class IptablesFwaasTestCase(base.BaseTestCase): self.firewall.create_firewall(FW_LEGACY, apply_list, firewall) for router_info_inst in apply_list: namespace = router_info_inst.iptables_manager.namespace - calls = [mock.call(namespace)] - self.netlink_flush.assert_has_calls(calls) + cmd = ['ip', 'netns', 'exec', namespace, 'conntrack', '-D'] + calls = [ + mock.call(cmd, run_as_root=True, check_exit_code=True, + extra_ok_codes=[1])] + self.utils_exec.assert_has_calls(calls) - @mock.patch('neutron_fwaas.privileged.netlink_lib.kill_entries') - def test_remove_conntrack_inserted_rule(self, mock_kill): + def test_remove_conntrack_inserted_rule(self): apply_list = self._fake_apply_list() rule_list = self._fake_rules_v4(FAKE_FW_ID, apply_list) firewall = self._fake_firewall(rule_list) @@ -310,22 +304,21 @@ class IptablesFwaasTestCase(base.BaseTestCase): 'id': 'fake-fw-rule'} rule_list.insert(2, insert_rule) firewall = self._fake_firewall(rule_list) + self.firewall.update_firewall(FW_LEGACY, apply_list, firewall) for router_info_inst in apply_list: namespace = router_info_inst.iptables_manager.namespace - with mock.patch('neutron_fwaas.privileged.' - 'netlink_lib.list_entries') as list_entries: - list_entries.return_value = FAKE_ENTRY - self.firewall.update_firewall(FW_LEGACY, apply_list, firewall) - calls = [ - mock.call(namespace, [(4, 'icmp', '8', '0', '1000', - '1.1.1.1', '2.2.2.2'), - (4, 'tcp', '1111', '23', - '1.1.1.1', '2.2.2.2')]) - ] - mock_kill.assert_has_calls(calls) + cmd1 = ['ip', 'netns', 'exec', namespace, 'conntrack', + '-D', '-p', 'tcp', '-f', 'ipv4', '--dport', '23'] + cmd2 = ['ip', 'netns', 'exec', namespace, 'conntrack', + '-D', '-p', 'icmp', '-f', 'ipv4'] + calls = [ + mock.call(cmd1, run_as_root=True, check_exit_code=True, + extra_ok_codes=[1]), + mock.call(cmd2, run_as_root=True, check_exit_code=True, + extra_ok_codes=[1])] + self.utils_exec.assert_has_calls(calls) - @mock.patch('neutron_fwaas.privileged.netlink_lib.kill_entries') - def test_remove_conntrack_removed_rule(self, mock_kill): + def test_remove_conntrack_removed_rule(self): apply_list = self._fake_apply_list() rule_list = self._fake_rules_v4(FAKE_FW_ID, apply_list) firewall = self._fake_firewall(rule_list) @@ -334,20 +327,21 @@ class IptablesFwaasTestCase(base.BaseTestCase): remove_rule = rule_list[1] rule_list.remove(remove_rule) firewall = self._fake_firewall(rule_list) + self.firewall.update_firewall(FW_LEGACY, apply_list, firewall) for router_info_inst in apply_list: namespace = router_info_inst.iptables_manager.namespace - with mock.patch('neutron_fwaas.privileged.' - 'netlink_lib.list_entries') as list_entries: - list_entries.return_value = FAKE_ENTRY - self.firewall.update_firewall(FW_LEGACY, apply_list, firewall) - calls = [ - mock.call(namespace, [(4, 'tcp', '1111', '23', - '1.1.1.1', '2.2.2.2')]) - ] - mock_kill.assert_has_calls(calls) + cmd1 = ['ip', 'netns', 'exec', namespace, 'conntrack', + '-D', '-p', 'tcp', '-f', 'ipv4', '--dport', '23'] + cmd2 = ['ip', 'netns', 'exec', namespace, 'conntrack', + '-D', '-p', 'tcp', '-f', 'ipv4', '--dport', '22'] + calls = [ + mock.call(cmd1, run_as_root=True, check_exit_code=True, + extra_ok_codes=[1]), + mock.call(cmd2, run_as_root=True, check_exit_code=True, + extra_ok_codes=[1])] + self.utils_exec.assert_has_calls(calls) - @mock.patch('neutron_fwaas.privileged.netlink_lib.kill_entries') - def test_remove_conntrack_changed_rule(self, mock_kill): + def test_remove_conntrack_changed_rule(self): apply_list = self._fake_apply_list() rule_list = self._fake_rules_v4(FAKE_FW_ID, apply_list) firewall = self._fake_firewall(rule_list) @@ -355,18 +349,20 @@ class IptablesFwaasTestCase(base.BaseTestCase): income_rule = {'enabled': True, 'action': 'deny', 'ip_version': 4, - 'protocol': 'tcp', + 'protocol': 'icmp', 'id': 'fake-fw-rule2'} - rule_list[2] = income_rule + rule_list[1] = income_rule firewall = self._fake_firewall(rule_list) + self.firewall.update_firewall(FW_LEGACY, apply_list, firewall) for router_info_inst in apply_list: namespace = router_info_inst.iptables_manager.namespace - with mock.patch('neutron_fwaas.privileged.' - 'netlink_lib.list_entries') as list_entries: - list_entries.return_value = FAKE_ENTRY - self.firewall.update_firewall(FW_LEGACY, apply_list, firewall) - calls = [ - mock.call(namespace, [(4, 'tcp', '1111', '23', - '1.1.1.1', '2.2.2.2')]) - ] - mock_kill.assert_has_calls(calls) + cmd1 = ['ip', 'netns', 'exec', namespace, 'conntrack', '-D', + '-p', 'tcp', '-f', 'ipv4', '--dport', '22'] + cmd2 = ['ip', 'netns', 'exec', namespace, 'conntrack', '-D', + '-p', 'icmp', '-f', 'ipv4'] + calls = [ + mock.call(cmd1, run_as_root=True, check_exit_code=True, + extra_ok_codes=[1]), + mock.call(cmd2, run_as_root=True, check_exit_code=True, + extra_ok_codes=[1])] + self.utils_exec.assert_has_calls(calls)