关于这个模块,我开始有以下几个问题:
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]
这行代码是将原本就未标记的链以及原本就不属于自己的规则提取出来作为新规则的基本部分,后续新的防火墙规则是在这部分上进行扩展的。如果不记录那些未标记的链,那么删除的时候是不知道哪些未标记的链与对应的规则需要删除。