openstack代码解读之 neutron.agent.linux.iptables_manager模块

关于这个模块,我开始有以下几个问题:

1.研究过他的人一定会对里面的chain的命名方式感到奇怪,为什么会有unwrapped_chain与wrapped_chain同时存在呢,这个按照他注释里面写的意思

# Add a neutron-filter-top chain. It's intended to be shared
# among the various neutron components. It sits at the very top
# of FORWARD and OUTPUT.

这个链可以在neutron模块之间进行共享使用。当然这个链也可以被删除

2.在IptablesTable.remove_chain方法里面,为什么对于wrapped_chain与unwrapped_chain的删除要分别以不同的方式进行?

该方法代码如下:

    def remove_chain(self, name, wrap=True):
        """Remove named chain.

        This removal "cascades". All rule in the chain are removed, as are
        all rules in other chains that jump to it.

        If the chain is not found, this is merely logged.

        """
        name = get_chain_name(name, wrap)
        chain_set = self._select_chain_set(wrap)

        if name not in chain_set:
            LOG.debug('Attempted to remove chain %s which does not exist',
                      name)
            return

        chain_set.remove(name)

        if not wrap:
            # non-wrapped chains and rules need to be dealt with specially,
            # so we keep a list of them to be iterated over in apply()
            self.remove_chains.add(name)

            # Add rules to remove that have a matching chain name or
            # a matching jump chain
            jump_snippet = '-j %s' % name
            self.remove_rules += [str(r) for r in self.rules
                                  if r.chain == name or jump_snippet in r.rule]
        else:
            jump_snippet = '-j %s-%s' % (self.wrap_name, name)

        # Remove rules from list that have a matching chain name or
        # a matching jump chain
        self.rules = [r for r in self.rules
                      if r.chain != name and jump_snippet not in r.rule]

总结来说,删除一个链的时候,先在自己内部的chains与rules数据结构中删除对应的链与规则。对于unwrapped_chain,则需要记录进remove_chains与remove_rules,这个我开始非常不理解,直到我读到刷新防火墙规则的代码:

    def _modify_rules(self, current_lines, table, table_name):
        unwrapped_chains = sorted(table.unwrapped_chains)
        chains = sorted(table.chains)
        rules = set(map(str, table.rules))

        new_filter = [line.strip() for line in current_lines
                      if self.wrap_name not in line and
                      line.strip() not in rules]

        our_chains = [':%s-%s' % (self.wrap_name, name) for name in chains]
        our_chains += [':%s' % name for name in unwrapped_chains
                       if not any(':%s' % name in s for s in new_filter)]

        our_top_rules = []
        our_bottom_rules = []
        for rule in table.rules:
            rule_str = str(rule)

            if rule.top:
                our_top_rules += [rule_str]
            else:
                our_bottom_rules += [rule_str]

        our_chains_and_rules = our_chains + our_top_rules + our_bottom_rules
        rules_index = self._find_rules_index(new_filter)
        new_filter[rules_index:rules_index] = our_chains_and_rules

        def _weed_out_removes(line):

            if line.startswith(':'):
                chain = line[1:]
                if chain in table.remove_chains:
                    table.remove_chains.remove(chain)
                    return False
            else:
                if line in table.remove_rules:
                    table.remove_rules.remove(line)
                    return False
            # Leave it alone
            return True

        seen_lines = set()

        def _weed_out_duplicates(line):
            if line in seen_lines:
                thing = 'chain' if line.startswith(':') else 'rule'
                LOG.warning("Duplicate iptables %(thing)s detected. This "
                            "may indicate a bug in the iptables "
                            "%(thing)s generation code. Line: %(line)s",
                            {'thing': thing, 'line': line})
                return False
            seen_lines.add(line)
            return True

        new_filter.reverse()
        new_filter = [line for line in new_filter
                      if _weed_out_duplicates(line) and
                      _weed_out_removes(line)]
        new_filter.reverse()

        # flush lists, just in case a rule or chain marked for removal
        # was already gone. (chains is a set, rules is a list)
        table.remove_chains.clear()
        table.remove_rules = []
        return new_filter

最难以理解的一句话就是

        new_filter = [line.strip() for line in current_lines
                      if self.wrap_name not in line and
                      line.strip() not in rules]

这行代码是将原本就未标记的链以及原本就不属于自己的规则提取出来作为新规则的基本部分,后续新的防火墙规则是在这部分上进行扩展的。如果不记录那些未标记的链,那么删除的时候是不知道哪些未标记的链与对应的规则需要删除。

发布了48 篇原创文章 · 获赞 4 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/m0_37313888/article/details/90406319