From 3416fcbb3df7d8dc16ab54a59ae7f81be49881a9 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Fri, 3 Nov 2023 09:27:36 +0800 Subject: [PATCH 01/25] Update iptables-graph support k8s rules --- iptables-graph | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iptables-graph b/iptables-graph index 34bb844..f8c9fa8 100755 --- a/iptables-graph +++ b/iptables-graph @@ -33,6 +33,10 @@ for line in line_list: else: rule_body = ' '.join(token_list[2:]) + rule_body = rule_body.replace('&', '&') + rule_body = rule_body.replace('"', '"') + rule_body = rule_body.replace('>', '>') + rule_body = rule_body.replace('<', '<') all_chains[current_table][current_chain].append({'rule_body':rule_body, 'target':target}) continue else: From 942b829099c9e4d649ce77df079ecc9bb6e0a671 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Thu, 21 Dec 2023 09:55:48 +0800 Subject: [PATCH 02/25] Update targets --- iptables-graph | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables-graph b/iptables-graph index f8c9fa8..a45fc26 100755 --- a/iptables-graph +++ b/iptables-graph @@ -25,7 +25,7 @@ for line in line_list: rule_body = '' target = '' - if token_list[-2] == '-j' and token_list[-1] not in ['RETURN', 'ACCEPT', 'DROP']: + if token_list[-2] == '-j' and token_list[-1] not in ['ACCEPT','REJECT','DROP','REDIRECT','MASQUERADE','LOG','DNAT','SNAT','MIRROR','QUEUE','RETURN','MARK']: target = token_list[-1] if target not in all_chains[current_table]: all_chains[current_table][target] = list() From bdeb6cef53197bad510eda4eb73dbd402ca6b06b Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Thu, 21 Dec 2023 11:12:41 +0800 Subject: [PATCH 03/25] add color to final rule --- iptables-graph | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/iptables-graph b/iptables-graph index a45fc26..76d1ab6 100755 --- a/iptables-graph +++ b/iptables-graph @@ -18,30 +18,29 @@ for line in line_list: if token_list[0][1:] in all_chains.keys(): current_table = token_list[0][1:] continue - if token_list[0] == '-A': - current_chain = token_list[1] - if current_chain not in all_chains[current_table]: - all_chains[current_table][current_chain] = list() - - rule_body = '' - target = '' - if token_list[-2] == '-j' and token_list[-1] not in ['ACCEPT','REJECT','DROP','REDIRECT','MASQUERADE','LOG','DNAT','SNAT','MIRROR','QUEUE','RETURN','MARK']: - target = token_list[-1] - if target not in all_chains[current_table]: - all_chains[current_table][target] = list() - rule_body = ' '.join(token_list[2:]) - else: - rule_body = ' '.join(token_list[2:]) - - rule_body = rule_body.replace('&', '&') - rule_body = rule_body.replace('"', '"') - rule_body = rule_body.replace('>', '>') - rule_body = rule_body.replace('<', '<') - all_chains[current_table][current_chain].append({'rule_body':rule_body, 'target':target}) - continue - else: + if token_list[0] != '-A': continue + current_chain = token_list[1] + if current_chain not in all_chains[current_table]: + all_chains[current_table][current_chain] = list() + target = '' + final_rule = False + i = token_list.index('-j') + if i != -1: + target = token_list[i+1] + if target in ['ACCEPT','REJECT','DROP','REDIRECT','MASQUERADE','LOG','DNAT','SNAT','MIRROR','QUEUE','RETURN','MARK']: + final_rule = target not in ['LOG', 'MARK', 'RETURN'] + target = '' + elif target not in all_chains[current_table]: + all_chains[current_table][target] = list() + rule_body = ' '.join(token_list[2:]) + rule_body = rule_body.replace('&', '&') + rule_body = rule_body.replace('"', '"') + rule_body = rule_body.replace('>', '>') + rule_body = rule_body.replace('<', '<') + all_chains[current_table][current_chain].append({'rule_body':rule_body, 'target':target, 'final_rule':final_rule}) + continue def get_node_name(table_name, chain_name): return re.sub('[^a-zA-Z0-9]', '', table_name) + '_' + re.sub('[^a-zA-Z0-9]', '', chain_name) @@ -51,7 +50,7 @@ def get_port_name(rule_index): output="""digraph { graph [pad="0.5", nodesep="0.5", ranksep="2"]; - node [shape=plain] + node [shape=box3d] rankdir=LR; """ @@ -72,8 +71,9 @@ for table in all_chains: tmp_body += """ """ + rule["rule_body"] + """""" - #tmp_body += """>""" tmp_body += """ end >]; From 056464a054b18d07e18f6aa88588b10cbac34087 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Thu, 21 Dec 2023 17:03:12 +0800 Subject: [PATCH 04/25] Update iptables-graph --- iptables-graph | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iptables-graph b/iptables-graph index 76d1ab6..28da4fd 100755 --- a/iptables-graph +++ b/iptables-graph @@ -29,7 +29,9 @@ for line in line_list: i = token_list.index('-j') if i != -1: target = token_list[i+1] - if target in ['ACCEPT','REJECT','DROP','REDIRECT','MASQUERADE','LOG','DNAT','SNAT','MIRROR','QUEUE','RETURN','MARK']: + if target in ['ACCEPT','REJECT','DROP','RETURN',\ + 'REDIRECT','MASQUERADE','DNAT','SNAT','DNPT','SNPT',\ + 'LOG','QUEUE','MARK']: final_rule = target not in ['LOG', 'MARK', 'RETURN'] target = '' elif target not in all_chains[current_table]: From d67035ca79b9c489cfdfb95ece0f70a2fbb6b5ea Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Wed, 10 Jan 2024 10:53:41 +0800 Subject: [PATCH 05/25] Update iptables-graph --- iptables-graph | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/iptables-graph b/iptables-graph index 28da4fd..7d3fcb0 100755 --- a/iptables-graph +++ b/iptables-graph @@ -25,10 +25,13 @@ for line in line_list: all_chains[current_table][current_chain] = list() target = '' + if '-j' in token_list: + target = token_list[token_list.index('-j') + 1] + elif '-g' in token_list: + target = token_list[token_list.index('-g') + 1] + final_rule = False - i = token_list.index('-j') - if i != -1: - target = token_list[i+1] + if target != '': if target in ['ACCEPT','REJECT','DROP','RETURN',\ 'REDIRECT','MASQUERADE','DNAT','SNAT','DNPT','SNPT',\ 'LOG','QUEUE','MARK']: @@ -36,6 +39,7 @@ for line in line_list: target = '' elif target not in all_chains[current_table]: all_chains[current_table][target] = list() + rule_body = ' '.join(token_list[2:]) rule_body = rule_body.replace('&', '&') rule_body = rule_body.replace('"', '"') From a6c53ad718602b003d5ba8e620aa98cea7e2230d Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Wed, 10 Jan 2024 11:03:23 +0800 Subject: [PATCH 06/25] Update iptables-graph --- iptables-graph | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iptables-graph b/iptables-graph index 7d3fcb0..fa5096b 100755 --- a/iptables-graph +++ b/iptables-graph @@ -24,11 +24,14 @@ for line in line_list: if current_chain not in all_chains[current_table]: all_chains[current_table][current_chain] = list() + i = -1 target = '' if '-j' in token_list: - target = token_list[token_list.index('-j') + 1] + i = token_list.index('-j') + 1 elif '-g' in token_list: - target = token_list[token_list.index('-g') + 1] + i = token_list.index('-g') + 1 + if i > 0 and i < len(token_list): + target = token_list[i] final_rule = False if target != '': From 579446fb1f0c6dd1153ba63af815f7f7a2ab92c7 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Wed, 10 Jan 2024 11:16:40 +0800 Subject: [PATCH 07/25] Update iptables-graph --- iptables-graph | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iptables-graph b/iptables-graph index fa5096b..c1de9b3 100755 --- a/iptables-graph +++ b/iptables-graph @@ -40,8 +40,10 @@ for line in line_list: 'LOG','QUEUE','MARK']: final_rule = target not in ['LOG', 'MARK', 'RETURN'] target = '' - elif target not in all_chains[current_table]: - all_chains[current_table][target] = list() + else: + token_list[i] = "[" + current_table + ":" + token_list[i] + "]" + if target not in all_chains[current_table]: + all_chains[current_table][target] = list() rule_body = ' '.join(token_list[2:]) rule_body = rule_body.replace('&', '&') From 8b2def92f97ab6d0578ad4a8e6825cf67906658b Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Wed, 10 Jan 2024 14:39:03 +0800 Subject: [PATCH 08/25] Update iptables-graph --- iptables-graph | 74 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/iptables-graph b/iptables-graph index c1de9b3..a40dc40 100755 --- a/iptables-graph +++ b/iptables-graph @@ -3,19 +3,52 @@ import sys import re import string -all_chains = { 'raw': {'PREROUTING':list(), 'OUTPUT':list()}, - 'filter': {'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list()}, - 'nat': {'PREROUTING':list(), 'OUTPUT':list(), 'POSTROUTING':list()}, - 'mangle': {'PREROUTING':list(), 'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list(), 'POSTROUTING':list()}} +all_chains = { + 'raw':{'PREROUTING':list(), 'OUTPUT':list()}, + 'filter':{'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list()}, + 'nat':{'PREROUTING':list(), 'OUTPUT':list(), 'POSTROUTING':list()}, + 'mangle':{'PREROUTING':list(), 'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list(), 'POSTROUTING':list()} +} defualt_chain_list = ['PREROUTING', 'FORWARD', 'INPUT', 'OUTPUT', 'POSTROUTING'] +tables_comment = {}; + +def get_escape(text): + text = text.replace('&', '&') + text = text.replace('"', '"') + text = text.replace('>', '>') + text = text.replace('<', '<') + return text input_string = sys.stdin.read() line_list = input_string.splitlines() current_table = None for line in line_list: - token_list = line.split() - if token_list[0][1:] in all_chains.keys(): + if line[0] == '#': + continue + buf = [] + token_list = [] + qoute = False + for i, c in enumerate(line): + if qoute: + buf.append(c) + if c == '"' and line[i-1] != '\\': + qoute = False + token_list.append(''.join(buf)) + buf = [] + else: + if c == ' ': + if len(buf) > 0: + token_list.append(''.join(buf)) + buf = [] + continue + if c == '"': + qoute = True + buf.append(c) + if not qoute and len(buf) > 0: + token_list.append(''.join(buf)) + + if token_list[0][0] == '*' and token_list[0][1:] in all_chains.keys(): current_table = token_list[0][1:] continue if token_list[0] != '-A': @@ -41,15 +74,24 @@ for line in line_list: final_rule = target not in ['LOG', 'MARK', 'RETURN'] target = '' else: - token_list[i] = "[" + current_table + ":" + token_list[i] + "]" + # remove JUMP + del token_list[i-1] + del token_list[i-1] + if '--comment' in token_list: + i = token_list.index('--comment') + 1 + if i < len(token_list): + comment = token_list[i].replace("\\", "") + name = current_table + ':' + target + if name not in tables_comment: + tables_comment[name] = [] + if len(comment) > 0: + comment = get_escape(comment[1:len(comment)-1]) + if comment not in tables_comment[name]: + tables_comment[name].append(comment) if target not in all_chains[current_table]: all_chains[current_table][target] = list() - rule_body = ' '.join(token_list[2:]) - rule_body = rule_body.replace('&', '&') - rule_body = rule_body.replace('"', '"') - rule_body = rule_body.replace('>', '>') - rule_body = rule_body.replace('<', '<') + rule_body = get_escape(' '.join(token_list[2:])) all_chains[current_table][current_chain].append({'rule_body':rule_body, 'target':target, 'final_rule':final_rule}) continue @@ -74,9 +116,13 @@ for table in all_chains: """ + chain + """ """ + table + """""" else: + name = table + ":" + chain + if name in tables_comment: + for comment in tables_comment[name]: + tmp_body +=""" +""" + comment + """""" tmp_body +=""" - """ + chain + """ - """ + table + """""" + [""" + name + """]""" for i in range(len(all_chains[table][chain])): rule = all_chains[table][chain][i] tmp_body += """ From 5151e3104b9c3168be22b9c464a176fe90f51643 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Wed, 10 Jan 2024 21:33:07 +0800 Subject: [PATCH 09/25] Update iptables-graph add security table & correct nat table --- iptables-graph | 346 +++++++++++++++++++++++++------------------------ 1 file changed, 178 insertions(+), 168 deletions(-) diff --git a/iptables-graph b/iptables-graph index 45ee9a7..b348e13 100755 --- a/iptables-graph +++ b/iptables-graph @@ -1,172 +1,182 @@ - #!/usr/bin/env python3 - import sys - import re - import string - - all_chains = { - 'raw':{'PREROUTING':list(), 'OUTPUT':list()}, - 'filter':{'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list()}, - 'nat':{'PREROUTING':list(), 'OUTPUT':list(), 'POSTROUTING':list()}, - 'mangle':{'PREROUTING':list(), 'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list(), 'POSTROUTING':list()} - } - - defualt_chain_list = ['PREROUTING', 'FORWARD', 'INPUT', 'OUTPUT', 'POSTROUTING'] - tables_comment = {}; - - def get_escape(text): - text = text.replace('&', '&') - text = text.replace('"', '"') - text = text.replace('>', '>') - text = text.replace('<', '<') - return text - - input_string = sys.stdin.read() - line_list = input_string.splitlines() - current_table = None - for line in line_list: - if line[0] == '#': - continue - buf = [] - token_list = [] - qoute = False - for i, c in enumerate(line): - if qoute: - buf.append(c) - if c == '"' and line[i-1] != '\\': - qoute = False +#!/usr/bin/env python3 +import sys +import re +import string + +all_chains = { + 'raw':{'PREROUTING':list(), 'OUTPUT':list()}, + 'filter':{'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list()}, + 'security':{'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list()}, + 'nat':{'PREROUTING':list(), 'INPUT':list(), 'OUTPUT':list(), 'POSTROUTING':list()}, + 'mangle':{'PREROUTING':list(), 'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list(), 'POSTROUTING':list()} +} + +defualt_chain_list = ['PREROUTING', 'FORWARD', 'INPUT', 'OUTPUT', 'POSTROUTING'] +tables_comment = {}; + +def get_escape(text): + text = text.replace('&', '&') + text = text.replace('"', '"') + text = text.replace('>', '>') + text = text.replace('<', '<') + return text + +input_string = sys.stdin.read() +line_list = input_string.splitlines() +current_table = None +for line in line_list: + if line[0] == '#': + continue + buf = [] + token_list = [] + qoute = False + for i, c in enumerate(line): + if qoute: + buf.append(c) + if c == '"' and line[i-1] != '\\': + qoute = False + token_list.append(''.join(buf)) + buf = [] + else: + if c == ' ': + if len(buf) > 0: token_list.append(''.join(buf)) buf = [] - else: - if c == ' ': - if len(buf) > 0: - token_list.append(''.join(buf)) - buf = [] - continue - if c == '"': - qoute = True - buf.append(c) - if not qoute and len(buf) > 0: - token_list.append(''.join(buf)) - - if token_list[0][0] == '*' and token_list[0][1:] in all_chains.keys(): - current_table = token_list[0][1:] - continue - if token_list[0] != '-A': - continue - current_chain = token_list[1] - if current_chain not in all_chains[current_table]: - all_chains[current_table][current_chain] = list() - - i = -1 - target = '' - if '-j' in token_list: - i = token_list.index('-j') + 1 - elif '-g' in token_list: - i = token_list.index('-g') + 1 - if i > 0 and i < len(token_list): - target = token_list[i] - - final_rule = False - if target != '': - if target in ['ACCEPT','REJECT','DROP','RETURN',\ - 'REDIRECT','MASQUERADE','DNAT','SNAT','DNPT','SNPT',\ - 'LOG','QUEUE','MARK']: - final_rule = target not in ['LOG', 'MARK', 'RETURN'] - target = '' - else: - # remove JUMP - del token_list[i-1] - del token_list[i-1] - if '--comment' in token_list: - i = token_list.index('--comment') + 1 - if i < len(token_list): - comment = token_list[i].replace("\\", "") - name = current_table + ':' + target - if name not in tables_comment: - tables_comment[name] = [] - if len(comment) > 0: - comment = get_escape(comment[1:len(comment)-1]) - if comment not in tables_comment[name]: - tables_comment[name].append(comment) - if target not in all_chains[current_table]: - all_chains[current_table][target] = list() - - rule_body = get_escape(' '.join(token_list[2:])) - all_chains[current_table][current_chain].append({'rule_body':rule_body, 'target':target, 'final_rule':final_rule}) + continue + if c == '"': + qoute = True + buf.append(c) + if not qoute and len(buf) > 0: + token_list.append(''.join(buf)) + + if token_list[0][0] == '*' and token_list[0][1:] in all_chains.keys(): + current_table = token_list[0][1:] continue - - def get_node_name(table_name, chain_name): - return re.sub('[^a-zA-Z0-9]', '', table_name) + '_' + re.sub('[^a-zA-Z0-9]', '', chain_name) - - def get_port_name(rule_index): - return "rule_" + str(rule_index) - - output="""digraph { - graph [pad="0.5", nodesep="0.5", ranksep="2"]; - node [shape=box3d] - rankdir=LR; - - """ - for table in all_chains: - for chain in all_chains[table]: - node_name = get_node_name(table, chain) - tmp_body = node_name + """ [label=<""" - if chain in defualt_chain_list: - tmp_body +=""" - - """ - else: - name = table + ":" + chain - if name in tables_comment: - for comment in tables_comment[name]: - tmp_body +=""" - """ - tmp_body +=""" - """ - for i in range(len(all_chains[table][chain])): - rule = all_chains[table][chain][i] - tmp_body += """ - """ + if token_list[0] != '-A': + continue + current_chain = token_list[1] + if current_chain not in all_chains[current_table]: + all_chains[current_table][current_chain] = list() + + i = -1 + target = '' + if '-j' in token_list: + i = token_list.index('-j') + 1 + elif '-g' in token_list: + i = token_list.index('-g') + 1 + if i > 0 and i < len(token_list): + target = token_list[i] + + final_rule = False + if target != '': + if target in ['ACCEPT','REJECT','DROP','RETURN',\ + 'REDIRECT','MASQUERADE','DNAT','SNAT','DNPT','SNPT',\ + 'LOG','QUEUE','MARK', \ + 'SECMARK', 'CONNSECMARK']: + final_rule = target not in ['LOG', 'MARK', 'RETURN'] + target = '' + else: + # remove JUMP + del token_list[i-1] + del token_list[i-1] + if '--comment' in token_list: + i = token_list.index('--comment') + 1 + if i < len(token_list): + comment = token_list[i].replace("\\", "") + name = current_table + ':' + target + if name not in tables_comment: + tables_comment[name] = [] + if len(comment) > 0: + comment = get_escape(comment[1:len(comment)-1]) + if comment not in tables_comment[name]: + tables_comment[name].append(comment) + if target not in all_chains[current_table]: + all_chains[current_table][target] = list() + + rule_body = get_escape(' '.join(token_list[2:])) + all_chains[current_table][current_chain].append({'rule_body':rule_body, 'target':target, 'final_rule':final_rule}) + continue + +def get_node_name(table_name, chain_name): + return re.sub('[^a-zA-Z0-9]', '', table_name) + '_' + re.sub('[^a-zA-Z0-9]', '', chain_name) + +def get_port_name(rule_index): + return "rule_" + str(rule_index) + +output="""digraph { + graph [pad="0.5", nodesep="0.5", ranksep="2"]; + node [shape=box3d] + rankdir=LR; + +""" +for table in all_chains: + for chain in all_chains[table]: + node_name = get_node_name(table, chain) + tmp_body = node_name + """ [label=<
""" + chain + """
""" + table + """
""" + comment + """
[""" + name + """]
""" + rule["rule_body"] + """
""" + if chain in defualt_chain_list: + tmp_body +=""" + + """ + else: + name = table + ":" + chain + if name in tables_comment: + for comment in tables_comment[name]: + tmp_body +=""" +""" + tmp_body +=""" + """ + for i in range(len(all_chains[table][chain])): + rule = all_chains[table][chain][i] tmp_body += """ - -
""" + chain + """
""" + table + """
""" + comment + """
[""" + name + """]
end
>]; - """ - output += tmp_body - - for table in all_chains: - for chain in all_chains[table]: - for i in range(len(all_chains[table][chain])): - rule = all_chains[table][chain][i] - if rule['target']: - source_node = get_node_name(table, chain) + ':' + get_port_name(i) - target_node = get_node_name(table, rule['target']) + ':begin' - output += source_node + """ -> """ + target_node + """; - """ - - def default_chain_link(src_table_name, src_chain_name, dst_table_name, dst_chain_name): - source_node = get_node_name(src_table_name, src_chain_name) + ':end' - target_node = get_node_name(dst_table_name, dst_chain_name) + ':begin' - return source_node + """ -> """ + target_node + """ [color=red]; - """ - - output += default_chain_link('raw', 'PREROUTING', 'mangle', 'PREROUTING') - output += default_chain_link('mangle', 'PREROUTING', 'nat', 'PREROUTING') - output += default_chain_link('nat', 'PREROUTING', 'mangle', 'INPUT') - output += default_chain_link('mangle', 'INPUT', 'filter', 'INPUT') - output += default_chain_link('filter', 'INPUT', 'raw', 'OUTPUT') - output += default_chain_link('raw', 'OUTPUT', 'mangle', 'OUTPUT') - output += default_chain_link('mangle', 'OUTPUT', 'nat', 'OUTPUT') - output += default_chain_link('nat', 'OUTPUT', 'filter', 'OUTPUT') - output += default_chain_link('filter', 'OUTPUT', 'mangle', 'POSTROUTING') - output += default_chain_link('mangle', 'POSTROUTING', 'nat', 'POSTROUTING') - output += default_chain_link('nat', 'PREROUTING', 'mangle', 'FORWARD') - output += default_chain_link('mangle', 'FORWARD', 'filter', 'FORWARD') - output += default_chain_link('filter', 'FORWARD', 'mangle', 'POSTROUTING') - - output += """ - }""" - print(output) + """ + rule["rule_body"] + """""" + tmp_body += """ + end +>]; +""" + output += tmp_body + +for table in all_chains: + for chain in all_chains[table]: + for i in range(len(all_chains[table][chain])): + rule = all_chains[table][chain][i] + if rule['target']: + source_node = get_node_name(table, chain) + ':' + get_port_name(i) + target_node = get_node_name(table, rule['target']) + ':begin' + output += source_node + """ -> """ + target_node + """; +""" + +def default_chain_link(src_table_name, src_chain_name, dst_table_name, dst_chain_name): + source_node = get_node_name(src_table_name, src_chain_name) + ':end' + target_node = get_node_name(dst_table_name, dst_chain_name) + ':begin' + return source_node + """ -> """ + target_node + """ [color=red]; +""" + +output += default_chain_link('raw', 'PREROUTING', 'mangle', 'PREROUTING') +output += default_chain_link('mangle', 'PREROUTING', 'nat', 'PREROUTING') + +output += default_chain_link('nat', 'PREROUTING', 'mangle', 'INPUT') +output += default_chain_link('mangle', 'INPUT', 'filter', 'INPUT') +output += default_chain_link('filter', 'INPUT', 'security', 'INPUT') +output += default_chain_link('security', 'INPUT', 'nat', 'INPUT') + +output += default_chain_link('nat', 'PREROUTING', 'mangle', 'FORWARD') +output += default_chain_link('mangle', 'FORWARD', 'filter', 'FORWARD') +output += default_chain_link('filter', 'FORWARD', 'security', 'FORWARD') + +output += default_chain_link('nat', 'INPUT', 'raw', 'OUTPUT') +output += default_chain_link('raw', 'OUTPUT', 'mangle', 'OUTPUT') +output += default_chain_link('mangle', 'OUTPUT', 'nat', 'OUTPUT') +output += default_chain_link('nat', 'OUTPUT', 'filter', 'OUTPUT') +output += default_chain_link('filter', 'OUTPUT', 'security', 'OUTPUT') + +output += default_chain_link('security', 'OUTPUT', 'mangle', 'POSTROUTING') +output += default_chain_link('security', 'FORWARD', 'mangle', 'POSTROUTING') +output += default_chain_link('mangle', 'POSTROUTING', 'nat', 'POSTROUTING') + +output += """ +}""" +print(output) From e2708d84efc9b2fa0d1bcbadabcfa66272f3a1db Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Wed, 10 Jan 2024 22:15:12 +0800 Subject: [PATCH 10/25] Update iptables-graph --- iptables-graph | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/iptables-graph b/iptables-graph index b348e13..1f84033 100755 --- a/iptables-graph +++ b/iptables-graph @@ -11,8 +11,17 @@ all_chains = { 'mangle':{'PREROUTING':list(), 'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list(), 'POSTROUTING':list()} } +def get_node_name(table_name, chain_name): + return re.sub('[^a-zA-Z0-9]', '', table_name) + '_' + re.sub('[^a-zA-Z0-9]', '', chain_name) + defualt_chain_list = ['PREROUTING', 'FORWARD', 'INPUT', 'OUTPUT', 'POSTROUTING'] -tables_comment = {}; +endness_chain = [ + get_node_name('raw', 'PREROUTING'), + get_node_name('nat', ':POSTROUTING'), + get_node_name('nat', 'INPUT'), + get_node_name('raw', 'OUTPUT') +] +tables_comment = {} def get_escape(text): text = text.replace('&', '&') @@ -83,13 +92,13 @@ for line in line_list: i = token_list.index('--comment') + 1 if i < len(token_list): comment = token_list[i].replace("\\", "") - name = current_table + ':' + target - if name not in tables_comment: - tables_comment[name] = [] + node_name = get_node_name(current_table, target) + if node_name not in tables_comment: + tables_comment[node_name] = [] if len(comment) > 0: comment = get_escape(comment[1:len(comment)-1]) - if comment not in tables_comment[name]: - tables_comment[name].append(comment) + if comment not in tables_comment[node_name]: + tables_comment[node_name].append(comment) if target not in all_chains[current_table]: all_chains[current_table][target] = list() @@ -97,8 +106,6 @@ for line in line_list: all_chains[current_table][current_chain].append({'rule_body':rule_body, 'target':target, 'final_rule':final_rule}) continue -def get_node_name(table_name, chain_name): - return re.sub('[^a-zA-Z0-9]', '', table_name) + '_' + re.sub('[^a-zA-Z0-9]', '', chain_name) def get_port_name(rule_index): return "rule_" + str(rule_index) @@ -114,17 +121,19 @@ for table in all_chains: node_name = get_node_name(table, chain) tmp_body = node_name + """ [label=<""" if chain in defualt_chain_list: + bgcolor ="red" + if node_name in endness_chain: + bgcolor = "lightblue" tmp_body +=""" - + """ else: - name = table + ":" + chain - if name in tables_comment: - for comment in tables_comment[name]: + if node_name in tables_comment: + for comment in tables_comment[node_name]: tmp_body +=""" """ tmp_body +=""" - """ + """ for i in range(len(all_chains[table][chain])): rule = all_chains[table][chain][i] tmp_body += """ From 0662565e04cb0de901189f3b586923357cb7e691 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Wed, 10 Jan 2024 23:19:43 +0800 Subject: [PATCH 11/25] Update iptables-graph --- iptables-graph | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/iptables-graph b/iptables-graph index 1f84033..91df4eb 100755 --- a/iptables-graph +++ b/iptables-graph @@ -15,12 +15,19 @@ def get_node_name(table_name, chain_name): return re.sub('[^a-zA-Z0-9]', '', table_name) + '_' + re.sub('[^a-zA-Z0-9]', '', chain_name) defualt_chain_list = ['PREROUTING', 'FORWARD', 'INPUT', 'OUTPUT', 'POSTROUTING'] + +default_chain_policy={} +for table in all_chains: + for chain in defualt_chain_list: + default_chain_policy[get_node_name(table, chain)] = 'ACCEPT' + endness_chain = [ get_node_name('raw', 'PREROUTING'), get_node_name('nat', ':POSTROUTING'), get_node_name('nat', 'INPUT'), get_node_name('raw', 'OUTPUT') ] + tables_comment = {} def get_escape(text): @@ -58,8 +65,14 @@ for line in line_list: if not qoute and len(buf) > 0: token_list.append(''.join(buf)) - if token_list[0][0] == '*' and token_list[0][1:] in all_chains.keys(): - current_table = token_list[0][1:] + if token_list[0][0] == '*': + if token_list[0][1:] in all_chains.keys(): + current_table = token_list[0][1:] + continue + if token_list[0][0] == ':': + node_name = get_node_name(current_table, token_list[0][1:]) + if node_name in default_chain_policy: + default_chain_policy[node_name] = token_list[1] continue if token_list[0] != '-A': continue @@ -124,9 +137,12 @@ for table in all_chains: bgcolor ="red" if node_name in endness_chain: bgcolor = "lightblue" + policy = "" + if node_name in default_chain_policy: + policy = ":" + default_chain_policy[node_name] tmp_body +=""" - """ + """ else: if node_name in tables_comment: for comment in tables_comment[node_name]: @@ -167,6 +183,7 @@ def default_chain_link(src_table_name, src_chain_name, dst_table_name, dst_chain output += default_chain_link('raw', 'PREROUTING', 'mangle', 'PREROUTING') output += default_chain_link('mangle', 'PREROUTING', 'nat', 'PREROUTING') +output += default_chain_link('mangle', 'PREROUTING', 'mangle', 'INPUT') output += default_chain_link('nat', 'PREROUTING', 'mangle', 'INPUT') output += default_chain_link('mangle', 'INPUT', 'filter', 'INPUT') output += default_chain_link('filter', 'INPUT', 'security', 'INPUT') From e5652e9dffc1dad876f5b8331cebbf0f3af58359 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Thu, 11 Jan 2024 11:03:51 +0800 Subject: [PATCH 12/25] Update iptables-graph --- iptables-graph | 273 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 178 insertions(+), 95 deletions(-) diff --git a/iptables-graph b/iptables-graph index 91df4eb..212fb94 100755 --- a/iptables-graph +++ b/iptables-graph @@ -3,45 +3,64 @@ import sys import re import string -all_chains = { - 'raw':{'PREROUTING':list(), 'OUTPUT':list()}, - 'filter':{'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list()}, - 'security':{'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list()}, - 'nat':{'PREROUTING':list(), 'INPUT':list(), 'OUTPUT':list(), 'POSTROUTING':list()}, - 'mangle':{'PREROUTING':list(), 'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list(), 'POSTROUTING':list()} +all_chains = { + "raw": {"PREROUTING": list(), "OUTPUT": list()}, + "filter": {"INPUT": list(), "OUTPUT": list(), "FORWARD": list()}, + "security": {"INPUT": list(), "OUTPUT": list(), "FORWARD": list()}, + "nat": { + "PREROUTING": list(), + "INPUT": list(), + "OUTPUT": list(), + "POSTROUTING": list(), + }, + "mangle": { + "PREROUTING": list(), + "INPUT": list(), + "OUTPUT": list(), + "FORWARD": list(), + "POSTROUTING": list(), + }, } + def get_node_name(table_name, chain_name): - return re.sub('[^a-zA-Z0-9]', '', table_name) + '_' + re.sub('[^a-zA-Z0-9]', '', chain_name) + return ( + re.sub("[^a-zA-Z0-9]", "", table_name) + + "_" + + re.sub("[^a-zA-Z0-9]", "", chain_name) + ) + -defualt_chain_list = ['PREROUTING', 'FORWARD', 'INPUT', 'OUTPUT', 'POSTROUTING'] +defualt_chain_list = ["PREROUTING", "FORWARD", "INPUT", "OUTPUT", "POSTROUTING"] -default_chain_policy={} +default_chain_policy = {} for table in all_chains: for chain in defualt_chain_list: - default_chain_policy[get_node_name(table, chain)] = 'ACCEPT' + default_chain_policy[get_node_name(table, chain)] = "ACCEPT" endness_chain = [ - get_node_name('raw', 'PREROUTING'), - get_node_name('nat', ':POSTROUTING'), - get_node_name('nat', 'INPUT'), - get_node_name('raw', 'OUTPUT') + get_node_name("raw", "PREROUTING"), + get_node_name("nat", ":POSTROUTING"), + get_node_name("nat", "INPUT"), + get_node_name("raw", "OUTPUT"), ] tables_comment = {} + def get_escape(text): - text = text.replace('&', '&') - text = text.replace('"', '"') - text = text.replace('>', '>') - text = text.replace('<', '<') + text = text.replace("&", "&") + text = text.replace('"', """) + text = text.replace(">", ">") + text = text.replace("<", "<") return text + input_string = sys.stdin.read() line_list = input_string.splitlines() current_table = None for line in line_list: - if line[0] == '#': + if line[0] == "#": continue buf = [] token_list = [] @@ -49,159 +68,223 @@ for line in line_list: for i, c in enumerate(line): if qoute: buf.append(c) - if c == '"' and line[i-1] != '\\': + if c == '"' and line[i - 1] != "\\": qoute = False - token_list.append(''.join(buf)) + token_list.append("".join(buf)) buf = [] else: - if c == ' ': + if c == " ": if len(buf) > 0: - token_list.append(''.join(buf)) + token_list.append("".join(buf)) buf = [] continue if c == '"': qoute = True buf.append(c) if not qoute and len(buf) > 0: - token_list.append(''.join(buf)) + token_list.append("".join(buf)) - if token_list[0][0] == '*': + if token_list[0][0] == "*": if token_list[0][1:] in all_chains.keys(): current_table = token_list[0][1:] continue - if token_list[0][0] == ':': + if token_list[0][0] == ":": node_name = get_node_name(current_table, token_list[0][1:]) if node_name in default_chain_policy: default_chain_policy[node_name] = token_list[1] continue - if token_list[0] != '-A': + if token_list[0] != "-A": continue current_chain = token_list[1] if current_chain not in all_chains[current_table]: all_chains[current_table][current_chain] = list() i = -1 - target = '' - if '-j' in token_list: - i = token_list.index('-j') + 1 - elif '-g' in token_list: - i = token_list.index('-g') + 1 + target = "" + if "-j" in token_list: + i = token_list.index("-j") + 1 + elif "-g" in token_list: + i = token_list.index("-g") + 1 if i > 0 and i < len(token_list): target = token_list[i] final_rule = False - if target != '': - if target in ['ACCEPT','REJECT','DROP','RETURN',\ - 'REDIRECT','MASQUERADE','DNAT','SNAT','DNPT','SNPT',\ - 'LOG','QUEUE','MARK', \ - 'SECMARK', 'CONNSECMARK']: - final_rule = target not in ['LOG', 'MARK', 'RETURN'] - target = '' + if target != "": + if target in [ + "ACCEPT", + "REJECT", + "DROP", + "RETURN", + "REDIRECT", + "MASQUERADE", + "DNAT", + "SNAT", + "DNPT", + "SNPT", + "LOG", + "QUEUE", + "MARK", + "SECMARK", + "CONNSECMARK", + ]: + final_rule = target not in ["LOG", "MARK", "RETURN"] + target = "" else: # remove JUMP - del token_list[i-1] - del token_list[i-1] - if '--comment' in token_list: - i = token_list.index('--comment') + 1 + del token_list[i - 1] + del token_list[i - 1] + if "--comment" in token_list: + i = token_list.index("--comment") + 1 if i < len(token_list): comment = token_list[i].replace("\\", "") node_name = get_node_name(current_table, target) if node_name not in tables_comment: tables_comment[node_name] = [] if len(comment) > 0: - comment = get_escape(comment[1:len(comment)-1]) + comment = get_escape(comment[1 : len(comment) - 1]) if comment not in tables_comment[node_name]: tables_comment[node_name].append(comment) if target not in all_chains[current_table]: all_chains[current_table][target] = list() - rule_body = get_escape(' '.join(token_list[2:])) - all_chains[current_table][current_chain].append({'rule_body':rule_body, 'target':target, 'final_rule':final_rule}) + rule_body = get_escape(" ".join(token_list[2:])) + all_chains[current_table][current_chain].append( + {"rule_body": rule_body, "target": target, "final_rule": final_rule} + ) continue def get_port_name(rule_index): return "rule_" + str(rule_index) -output="""digraph { + +output = """digraph { graph [pad="0.5", nodesep="0.5", ranksep="2"]; node [shape=box3d] rankdir=LR; - """ for table in all_chains: for chain in all_chains[table]: node_name = get_node_name(table, chain) - tmp_body = node_name + """ [label=<
""" + chain + """
""" + chain + """
""" + table + """
""" + comment + """
[""" + name + """]
[""" + node_name.replace("_", ":") + """]
""" + chain + """
""" + table + """
""" + table + policy + """
""" + tmp_body = ( + """ + """ + + node_name + + """ [label=<
""" + ) if chain in defualt_chain_list: - bgcolor ="red" + bgcolor = "tomato" if node_name in endness_chain: bgcolor = "lightblue" - policy = "" - if node_name in default_chain_policy: - policy = ":" + default_chain_policy[node_name] - tmp_body +=""" - - """ + tmp_body += ( + """ + + """ + ) else: - if node_name in tables_comment: - for comment in tables_comment[node_name]: - tmp_body +=""" -""" - tmp_body +=""" - """ + if not node_name in tables_comment: + tables_comment[node_name] = [node_name.replace("_", ":")] + for comment in sorted(tables_comment[node_name]): + tmp_body += ( + """ + """ + ) + tmp_body += """ + """ for i in range(len(all_chains[table][chain])): rule = all_chains[table][chain][i] tmp_body += """ - """ - tmp_body += """ - -
""" + chain + """
""" + table + policy + """
""" + + node_name.replace("_", ":") + + """
""" + comment + """
[""" + node_name.replace("_", ":") + """]
""" + + comment + + """
""" + rule["rule_body"] + """
end
>]; + policy = "-j RETURN" + if node_name in default_chain_policy: + policy = "-j " + default_chain_policy[node_name] + tmp_body += ( + """ + """ + + policy + + """ + >]; """ + ) output += tmp_body for table in all_chains: for chain in all_chains[table]: for i in range(len(all_chains[table][chain])): rule = all_chains[table][chain][i] - if rule['target']: - source_node = get_node_name(table, chain) + ':' + get_port_name(i) - target_node = get_node_name(table, rule['target']) + ':begin' - output += source_node + """ -> """ + target_node + """; -""" + if rule["target"]: + source_node = get_node_name(table, chain) + ":" + get_port_name(i) + target_node = get_node_name(table, rule["target"]) + ":begin" + output += ( + """ + """ + + source_node + + """ -> """ + + target_node + + """;""" + ) + def default_chain_link(src_table_name, src_chain_name, dst_table_name, dst_chain_name): - source_node = get_node_name(src_table_name, src_chain_name) + ':end' - target_node = get_node_name(dst_table_name, dst_chain_name) + ':begin' - return source_node + """ -> """ + target_node + """ [color=red]; -""" + source_node = get_node_name(src_table_name, src_chain_name) + color = "red" + if ( + source_node in default_chain_policy + and default_chain_policy[source_node] != "ACCEPT" + ): + color = "grey" + target_node = get_node_name(dst_table_name, dst_chain_name) + return ( + """ + """ + + source_node + + """:end -> """ + + target_node + + """:begin [color=""" + + color + + """];""" + ) + +output += "INGRESS[shape=circle fillcolor=lightblue style=filled];" +output += "EGRESS[shape=circle fillcolor=lightblue style=filled];" +output += "APPLICATION[shape=circle style=filled];" + +output += "INGRESS->" + get_node_name("raw", "PREROUTING") + ":begin[color=blue];" +output += get_node_name("nat", "INPUT") + ":end-> APPLICATION[color=blue];" +output += "APPLICATION->" + get_node_name("raw", "OUTPUT") + ":begin[color=blue];" +output += get_node_name("nat", "POSTROUTING") + ":end-> EGRESS[color=blue];" -output += default_chain_link('raw', 'PREROUTING', 'mangle', 'PREROUTING') -output += default_chain_link('mangle', 'PREROUTING', 'nat', 'PREROUTING') +output += default_chain_link("raw", "PREROUTING", "mangle", "PREROUTING") +output += default_chain_link("mangle", "PREROUTING", "nat", "PREROUTING") -output += default_chain_link('mangle', 'PREROUTING', 'mangle', 'INPUT') -output += default_chain_link('nat', 'PREROUTING', 'mangle', 'INPUT') -output += default_chain_link('mangle', 'INPUT', 'filter', 'INPUT') -output += default_chain_link('filter', 'INPUT', 'security', 'INPUT') -output += default_chain_link('security', 'INPUT', 'nat', 'INPUT') +output += default_chain_link("nat", "PREROUTING", "mangle", "INPUT") +output += default_chain_link("mangle", "INPUT", "filter", "INPUT") +output += default_chain_link("filter", "INPUT", "security", "INPUT") +output += default_chain_link("security", "INPUT", "nat", "INPUT") -output += default_chain_link('nat', 'PREROUTING', 'mangle', 'FORWARD') -output += default_chain_link('mangle', 'FORWARD', 'filter', 'FORWARD') -output += default_chain_link('filter', 'FORWARD', 'security', 'FORWARD') +output += default_chain_link("nat", "PREROUTING", "mangle", "FORWARD") +output += default_chain_link("mangle", "FORWARD", "filter", "FORWARD") +output += default_chain_link("filter", "FORWARD", "security", "FORWARD") -output += default_chain_link('nat', 'INPUT', 'raw', 'OUTPUT') -output += default_chain_link('raw', 'OUTPUT', 'mangle', 'OUTPUT') -output += default_chain_link('mangle', 'OUTPUT', 'nat', 'OUTPUT') -output += default_chain_link('nat', 'OUTPUT', 'filter', 'OUTPUT') -output += default_chain_link('filter', 'OUTPUT', 'security', 'OUTPUT') +# output += default_chain_link("nat", "INPUT", "raw", "OUTPUT") +output += default_chain_link("raw", "OUTPUT", "mangle", "OUTPUT") +output += default_chain_link("mangle", "OUTPUT", "nat", "OUTPUT") +output += default_chain_link("nat", "OUTPUT", "filter", "OUTPUT") +output += default_chain_link("filter", "OUTPUT", "security", "OUTPUT") -output += default_chain_link('security', 'OUTPUT', 'mangle', 'POSTROUTING') -output += default_chain_link('security', 'FORWARD', 'mangle', 'POSTROUTING') -output += default_chain_link('mangle', 'POSTROUTING', 'nat', 'POSTROUTING') +output += default_chain_link("security", "OUTPUT", "mangle", "POSTROUTING") +output += default_chain_link("security", "FORWARD", "mangle", "POSTROUTING") +output += default_chain_link("mangle", "POSTROUTING", "nat", "POSTROUTING") output += """ }""" From 4e915535fbbbc5a920d7961dbcf82c809ab1fc39 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Fri, 12 Jan 2024 15:11:41 +0800 Subject: [PATCH 13/25] remove empty chain --- iptables-graph | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/iptables-graph b/iptables-graph index 212fb94..d3e032e 100755 --- a/iptables-graph +++ b/iptables-graph @@ -2,6 +2,11 @@ import sys import re import string +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument("--eliminate", help="eliminate empty/unused chain", action=argparse.BooleanOptionalAction) +argv = parser.parse_args() all_chains = { "raw": {"PREROUTING": list(), "OUTPUT": list()}, @@ -46,7 +51,7 @@ endness_chain = [ ] tables_comment = {} - +tables_target = [] def get_escape(text): text = text.replace("&", "&") @@ -130,6 +135,8 @@ for line in line_list: final_rule = target not in ["LOG", "MARK", "RETURN"] target = "" else: + if tables_target not in tables_target: + tables_target.append(target) # remove JUMP del token_list[i - 1] del token_list[i - 1] @@ -153,7 +160,6 @@ for line in line_list: ) continue - def get_port_name(rule_index): return "rule_" + str(rule_index) @@ -165,6 +171,10 @@ output = """digraph { """ for table in all_chains: for chain in all_chains[table]: + if argv.eliminate and not chain in defualt_chain_list: + if chain not in tables_target or len(all_chains[table][chain]) == 0: + continue + node_name = get_node_name(table, chain) tmp_body = ( """ @@ -202,7 +212,10 @@ for table in all_chains: tmp_body += """ """ + rule["rule_body"] + """""" policy = "-j RETURN" @@ -221,10 +234,14 @@ for table in all_chains: for table in all_chains: for chain in all_chains[table]: for i in range(len(all_chains[table][chain])): - rule = all_chains[table][chain][i] - if rule["target"]: + target = all_chains[table][chain][i]["target"] + if target: + if argv.eliminate and target not in defualt_chain_list: + if target not in tables_target or len(all_chains[table][target]) == 0: + continue + source_node = get_node_name(table, chain) + ":" + get_port_name(i) - target_node = get_node_name(table, rule["target"]) + ":begin" + target_node = get_node_name(table, target) + ":begin" output += ( """ """ @@ -255,14 +272,17 @@ def default_chain_link(src_table_name, src_chain_name, dst_table_name, dst_chain + """];""" ) -output += "INGRESS[shape=circle fillcolor=lightblue style=filled];" -output += "EGRESS[shape=circle fillcolor=lightblue style=filled];" -output += "APPLICATION[shape=circle style=filled];" - -output += "INGRESS->" + get_node_name("raw", "PREROUTING") + ":begin[color=blue];" -output += get_node_name("nat", "INPUT") + ":end-> APPLICATION[color=blue];" -output += "APPLICATION->" + get_node_name("raw", "OUTPUT") + ":begin[color=blue];" -output += get_node_name("nat", "POSTROUTING") + ":end-> EGRESS[color=blue];" +def default_link(): + return """ + INGRESS[shape=circle fillcolor=lightblue style=filled]; + EGRESS[shape=circle fillcolor=lightblue style=filled]; + APPLICATION[shape=circle fillcolor=lightblue style=filled]; + INGRESS->""" + get_node_name("raw", "PREROUTING") + """:begin[color=blue]; + """ + get_node_name("nat", "INPUT") + """:end-> APPLICATION[color=blue]; + APPLICATION->""" + get_node_name("raw", "OUTPUT") + """:begin[color=blue]; + """ + get_node_name("nat", "POSTROUTING") + """:end-> EGRESS[color=blue];""" + +output += default_link() output += default_chain_link("raw", "PREROUTING", "mangle", "PREROUTING") output += default_chain_link("mangle", "PREROUTING", "nat", "PREROUTING") @@ -276,7 +296,6 @@ output += default_chain_link("nat", "PREROUTING", "mangle", "FORWARD") output += default_chain_link("mangle", "FORWARD", "filter", "FORWARD") output += default_chain_link("filter", "FORWARD", "security", "FORWARD") -# output += default_chain_link("nat", "INPUT", "raw", "OUTPUT") output += default_chain_link("raw", "OUTPUT", "mangle", "OUTPUT") output += default_chain_link("mangle", "OUTPUT", "nat", "OUTPUT") output += default_chain_link("nat", "OUTPUT", "filter", "OUTPUT") From f45d36bf6879223b8080c849b9acd9f90ca195d3 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Fri, 12 Jan 2024 15:57:50 +0800 Subject: [PATCH 14/25] remove rules after absolute RETURN --- iptables-graph | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/iptables-graph b/iptables-graph index d3e032e..888f47d 100755 --- a/iptables-graph +++ b/iptables-graph @@ -51,7 +51,7 @@ endness_chain = [ ] tables_comment = {} -tables_target = [] +tables_target = {} def get_escape(text): text = text.replace("&", "&") @@ -135,8 +135,10 @@ for line in line_list: final_rule = target not in ["LOG", "MARK", "RETURN"] target = "" else: - if tables_target not in tables_target: - tables_target.append(target) + node_name = get_node_name(current_table, target) + if node_name not in tables_target: + tables_target[node_name] = 0 + tables_target[node_name] += 1 # remove JUMP del token_list[i - 1] del token_list[i - 1] @@ -144,7 +146,6 @@ for line in line_list: i = token_list.index("--comment") + 1 if i < len(token_list): comment = token_list[i].replace("\\", "") - node_name = get_node_name(current_table, target) if node_name not in tables_comment: tables_comment[node_name] = [] if len(comment) > 0: @@ -160,10 +161,27 @@ for line in line_list: ) continue +if argv.eliminate: + for table in all_chains: + for chain in all_chains[table]: + rules = all_chains[table][chain] + for i in range(len(rules)): + if rules[i]["rule_body"] == "-j RETURN": + while i != len(rules)-1: + del rules[i] + break + target = rules[i]["target"] + if target and target not in defualt_chain_list and len(all_chains[table][target]) == 1: + rule = all_chains[table][target][0] + if rule["rule_body"] == "" and rule["target"]: + node_name = get_node_name(table, rule["target"]) + tables_target[node_name] -= 1 + rules[i]["target"] = rule["target"] + del all_chains[table][target][0] + def get_port_name(rule_index): return "rule_" + str(rule_index) - output = """digraph { graph [pad="0.5", nodesep="0.5", ranksep="2"]; node [shape=box3d] @@ -172,7 +190,8 @@ output = """digraph { for table in all_chains: for chain in all_chains[table]: if argv.eliminate and not chain in defualt_chain_list: - if chain not in tables_target or len(all_chains[table][chain]) == 0: + node_name = get_node_name(table, chain) + if node_name not in tables_target or tables_target[node_name] < 1 or len(all_chains[table][chain]) == 0: continue node_name = get_node_name(table, chain) @@ -209,13 +228,13 @@ for table in all_chains: """ for i in range(len(all_chains[table][chain])): rule = all_chains[table][chain][i] + if argv.eliminate and rule["target"] and rule["target"] \ + not in defualt_chain_list and len(all_chains[table][rule["target"]]) == 0: + continue tmp_body += """ """ + rule["rule_body"] + """""" policy = "-j RETURN" @@ -237,7 +256,8 @@ for table in all_chains: target = all_chains[table][chain][i]["target"] if target: if argv.eliminate and target not in defualt_chain_list: - if target not in tables_target or len(all_chains[table][target]) == 0: + node_name = get_node_name(table, target) + if node_name not in tables_target or tables_target[node_name] < 1 or len(all_chains[table][target]) == 0: continue source_node = get_node_name(table, chain) + ":" + get_port_name(i) @@ -281,7 +301,7 @@ def default_link(): """ + get_node_name("nat", "INPUT") + """:end-> APPLICATION[color=blue]; APPLICATION->""" + get_node_name("raw", "OUTPUT") + """:begin[color=blue]; """ + get_node_name("nat", "POSTROUTING") + """:end-> EGRESS[color=blue];""" - + output += default_link() output += default_chain_link("raw", "PREROUTING", "mangle", "PREROUTING") From d5ef6ece16a45cead6ff7164b0526d7c84d22072 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Fri, 12 Jan 2024 16:02:22 +0800 Subject: [PATCH 15/25] Update iptables-graph --- iptables-graph | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iptables-graph b/iptables-graph index 888f47d..bcfa674 100755 --- a/iptables-graph +++ b/iptables-graph @@ -167,7 +167,9 @@ if argv.eliminate: rules = all_chains[table][chain] for i in range(len(rules)): if rules[i]["rule_body"] == "-j RETURN": - while i != len(rules)-1: + if chain in defualt_chain_list: + i += 1 + while i < len(rules): del rules[i] break target = rules[i]["target"] From c0af981dda64eb7f629a2e9a07df1df95997fed2 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Fri, 12 Jan 2024 17:30:45 +0800 Subject: [PATCH 16/25] Update iptables-graph --- iptables-graph | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/iptables-graph b/iptables-graph index bcfa674..27e647b 100755 --- a/iptables-graph +++ b/iptables-graph @@ -105,7 +105,7 @@ for line in line_list: all_chains[current_table][current_chain] = list() i = -1 - target = "" + target = None if "-j" in token_list: i = token_list.index("-j") + 1 elif "-g" in token_list: @@ -114,7 +114,7 @@ for line in line_list: target = token_list[i] final_rule = False - if target != "": + if target: if target in [ "ACCEPT", "REJECT", @@ -133,7 +133,7 @@ for line in line_list: "CONNSECMARK", ]: final_rule = target not in ["LOG", "MARK", "RETURN"] - target = "" + target = None else: node_name = get_node_name(current_table, target) if node_name not in tables_target: @@ -161,6 +161,17 @@ for line in line_list: ) continue +def get_next_chain(table_name, chain_name): + rules=all_chains[table_name][chain_name] + if len(rules) == 1: + target = rules[0]["target"] + rule = rules[0]["rule_body"] + if target and rule == "": + del rules[0] + tables_target[get_node_name(table_name, chain_name)] -= 1 + return get_next_chain(table_name, target) + return chain_name + if argv.eliminate: for table in all_chains: for chain in all_chains[table]: @@ -173,13 +184,8 @@ if argv.eliminate: del rules[i] break target = rules[i]["target"] - if target and target not in defualt_chain_list and len(all_chains[table][target]) == 1: - rule = all_chains[table][target][0] - if rule["rule_body"] == "" and rule["target"]: - node_name = get_node_name(table, rule["target"]) - tables_target[node_name] -= 1 - rules[i]["target"] = rule["target"] - del all_chains[table][target][0] + if target and target not in defualt_chain_list: + rules[i]["target"] = get_next_chain(table, target) def get_port_name(rule_index): return "rule_" + str(rule_index) @@ -230,13 +236,18 @@ for table in all_chains: """ for i in range(len(all_chains[table][chain])): rule = all_chains[table][chain][i] + empty_target = False if argv.eliminate and rule["target"] and rule["target"] \ not in defualt_chain_list and len(all_chains[table][rule["target"]]) == 0: - continue + if rule["rule_body"] == "": + continue + empty_target = True tmp_body += """ """ + rule["rule_body"] + """""" policy = "-j RETURN" From 6f538cbecbf781e70453360d3c2f0966668743e9 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Sat, 13 Jan 2024 13:51:48 +0800 Subject: [PATCH 17/25] Update iptables-graph --- iptables-graph | 117 ++++++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 49 deletions(-) diff --git a/iptables-graph b/iptables-graph index 27e647b..8bbefda 100755 --- a/iptables-graph +++ b/iptables-graph @@ -60,15 +60,13 @@ def get_escape(text): text = text.replace("<", "<") return text - -input_string = sys.stdin.read() -line_list = input_string.splitlines() -current_table = None -for line in line_list: - if line[0] == "#": - continue - buf = [] +def parse_line(line): token_list = [] + if line[0] == '#': + token_list.append('#') + token_list.append(line[1:]) + return token_list + buf = [] qoute = False for i, c in enumerate(line): if qoute: @@ -88,30 +86,44 @@ for line in line_list: buf.append(c) if not qoute and len(buf) > 0: token_list.append("".join(buf)) + if len(token_list ) > 0: + first = token_list[0][0] + if first == "*" or first == ':': + token_list.insert(0, first) + token_list[1] = token_list[1][1:] + return token_list - if token_list[0][0] == "*": - if token_list[0][1:] in all_chains.keys(): - current_table = token_list[0][1:] +input_string = sys.stdin.read() +line_list = input_string.splitlines() +current_table = None +for line in line_list: + args = parse_line(line) + if len(args) < 1 or args[0] == "#": + continue + if args[0] == "*": + if args[1] in all_chains.keys(): + current_table = args[1] continue - if token_list[0][0] == ":": - node_name = get_node_name(current_table, token_list[0][1:]) - if node_name in default_chain_policy: - default_chain_policy[node_name] = token_list[1] + if args[0] == ":": + node_name = get_node_name(current_table, args[1]) + if args[2] == '-': + args[2] = "RETURN" + default_chain_policy[node_name] = args[2] continue - if token_list[0] != "-A": + if args[0] != "-A": continue - current_chain = token_list[1] + current_chain = args[1] if current_chain not in all_chains[current_table]: all_chains[current_table][current_chain] = list() i = -1 target = None - if "-j" in token_list: - i = token_list.index("-j") + 1 - elif "-g" in token_list: - i = token_list.index("-g") + 1 - if i > 0 and i < len(token_list): - target = token_list[i] + if "-j" in args: + i = args.index("-j") + 1 + elif "-g" in args: + i = args.index("-g") + 1 + if i > 0 and i < len(args): + target = args[i] final_rule = False if target: @@ -130,9 +142,9 @@ for line in line_list: "QUEUE", "MARK", "SECMARK", - "CONNSECMARK", + "CONNSECMARK" ]: - final_rule = target not in ["LOG", "MARK", "RETURN"] + final_rule = target not in ["LOG", "MARK", "SECMARK", "CONNSECMARK"] target = None else: node_name = get_node_name(current_table, target) @@ -140,12 +152,12 @@ for line in line_list: tables_target[node_name] = 0 tables_target[node_name] += 1 # remove JUMP - del token_list[i - 1] - del token_list[i - 1] - if "--comment" in token_list: - i = token_list.index("--comment") + 1 - if i < len(token_list): - comment = token_list[i].replace("\\", "") + del args[i - 1] + del args[i - 1] + if "--comment" in args: + i = args.index("--comment") + 1 + if i < len(args): + comment = args[i].replace("\\", "") if node_name not in tables_comment: tables_comment[node_name] = [] if len(comment) > 0: @@ -155,9 +167,8 @@ for line in line_list: if target not in all_chains[current_table]: all_chains[current_table][target] = list() - rule_body = get_escape(" ".join(token_list[2:])) all_chains[current_table][current_chain].append( - {"rule_body": rule_body, "target": target, "final_rule": final_rule} + {"rule": args[2:], "target": target, "final": final_rule} ) continue @@ -165,8 +176,8 @@ def get_next_chain(table_name, chain_name): rules=all_chains[table_name][chain_name] if len(rules) == 1: target = rules[0]["target"] - rule = rules[0]["rule_body"] - if target and rule == "": + rule = rules[0]["rule"] + if target and len(rule) == 0: del rules[0] tables_target[get_node_name(table_name, chain_name)] -= 1 return get_next_chain(table_name, target) @@ -177,7 +188,8 @@ if argv.eliminate: for chain in all_chains[table]: rules = all_chains[table][chain] for i in range(len(rules)): - if rules[i]["rule_body"] == "-j RETURN": + rule = rules[i]["rule"] + if len(rule) == 2 and rule[0] == "-j": if chain in defualt_chain_list: i += 1 while i < len(rules): @@ -239,7 +251,7 @@ for table in all_chains: empty_target = False if argv.eliminate and rule["target"] and rule["target"] \ not in defualt_chain_list and len(all_chains[table][rule["target"]]) == 0: - if rule["rule_body"] == "": + if len(rule["rule"]) == 0: continue empty_target = True tmp_body += """ @@ -247,15 +259,22 @@ for table in all_chains: tmp_body += '"' + get_port_name(i) + '"' if empty_target: tmp_body += ' bgcolor="yellow"' - elif rule["final_rule"]: - tmp_body += ' bgcolor="lightgrey"' - tmp_body += """>""" + rule["rule_body"] + """""" - policy = "-j RETURN" - if node_name in default_chain_policy: - policy = "-j " + default_chain_policy[node_name] + elif rule["final"]: + target = rule['rule'][rule['rule'].index('-j') + 1] + if target == 'DROP' or target == 'REJECT': + tmp_body += ' bgcolor="coral"' + elif target == 'RETURN': + tmp_body += ' bgcolor="moccasin"' + else: + tmp_body += ' bgcolor="lightgreen"' + tmp_body += """>""" + get_escape(" ".join(rule["rule"])) + """""" + policy = "-j " + default_chain_policy[node_name] + bgcolor = "white" + if default_chain_policy[node_name] != 'RETURN': + bgcolor = "lightgreen" tmp_body += ( """ - """ + """ + policy + """ >]; @@ -307,13 +326,13 @@ def default_chain_link(src_table_name, src_chain_name, dst_table_name, dst_chain def default_link(): return """ - INGRESS[shape=circle fillcolor=lightblue style=filled]; - EGRESS[shape=circle fillcolor=lightblue style=filled]; - APPLICATION[shape=circle fillcolor=lightblue style=filled]; - INGRESS->""" + get_node_name("raw", "PREROUTING") + """:begin[color=blue]; + START[shape=circle fillcolor=black fontcolor=white style=filled]; + END[shape=circle fillcolor=black fontcolor=white style=filled]; + APPLICATION[shape=circle fillcolor=black fontcolor=white style=filled]; + START->""" + get_node_name("raw", "PREROUTING") + """:begin[color=blue]; """ + get_node_name("nat", "INPUT") + """:end-> APPLICATION[color=blue]; APPLICATION->""" + get_node_name("raw", "OUTPUT") + """:begin[color=blue]; - """ + get_node_name("nat", "POSTROUTING") + """:end-> EGRESS[color=blue];""" + """ + get_node_name("nat", "POSTROUTING") + """:end-> END[color=blue];""" output += default_link() From 59bef5898719f4b645578df07ce03b446e3f3806 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Mon, 15 Jan 2024 08:56:08 +0800 Subject: [PATCH 18/25] Update iptables-graph --- iptables-graph | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/iptables-graph b/iptables-graph index 8bbefda..0b0a4c4 100755 --- a/iptables-graph +++ b/iptables-graph @@ -268,18 +268,19 @@ for table in all_chains: else: tmp_body += ' bgcolor="lightgreen"' tmp_body += """>""" + get_escape(" ".join(rule["rule"])) + """""" - policy = "-j " + default_chain_policy[node_name] - bgcolor = "white" - if default_chain_policy[node_name] != 'RETURN': - bgcolor = "lightgreen" + tmp_body += """ + """ + """>-j """ + policy + """ >]; -""" - ) +""") output += tmp_body for table in all_chains: From ae7c8f0c5805a65245552ecc6269dc39fcb4e134 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Mon, 15 Jan 2024 09:13:43 +0800 Subject: [PATCH 19/25] support libvirt --- iptables-graph | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iptables-graph b/iptables-graph index 0b0a4c4..7eb42b6 100755 --- a/iptables-graph +++ b/iptables-graph @@ -142,9 +142,10 @@ for line in line_list: "QUEUE", "MARK", "SECMARK", - "CONNSECMARK" + "CONNSECMARK", + "CHECKSUM" ]: - final_rule = target not in ["LOG", "MARK", "SECMARK", "CONNSECMARK"] + final_rule = target not in ["LOG", "MARK", "SECMARK", "CONNSECMARK", "CHECKSUM"] target = None else: node_name = get_node_name(current_table, target) From ffa081390b25f1b14bcbc7c5b58eccf7ad2def83 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Mon, 15 Jan 2024 10:12:55 +0800 Subject: [PATCH 20/25] support user final target --- iptables-graph | 147 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 47 deletions(-) diff --git a/iptables-graph b/iptables-graph index 7eb42b6..e67747e 100755 --- a/iptables-graph +++ b/iptables-graph @@ -5,7 +5,14 @@ import string import argparse parser = argparse.ArgumentParser() -parser.add_argument("--eliminate", help="eliminate empty/unused chain", action=argparse.BooleanOptionalAction) +parser.add_argument( + "-e", + "--eliminate", + help="eliminate empty/unused chain", + action=argparse.BooleanOptionalAction, +) +parser.add_argument("-f", "--final-targets", help="final targets") +parser.add_argument("-m", "--middle-targets", help="middle targets") argv = parser.parse_args() all_chains = { @@ -50,9 +57,25 @@ endness_chain = [ get_node_name("raw", "OUTPUT"), ] +default_middle_targets = ["LOG", "MARK", "SECMARK", "CONNSECMARK", "CHECKSUM"] +default_final_targets = [ + "ACCEPT", + "REJECT", + "DROP", + "RETURN", + "REDIRECT", + "MASQUERADE", + "DNAT", + "SNAT", + "DNPT", + "SNPT", + "QUEUE", +] + tables_comment = {} tables_target = {} + def get_escape(text): text = text.replace("&", "&") text = text.replace('"', """) @@ -60,10 +83,13 @@ def get_escape(text): text = text.replace("<", "<") return text -def parse_line(line): + +def parse_line(line, separators): token_list = [] - if line[0] == '#': - token_list.append('#') + if not line: + return token_list + if line[0] == "#": + token_list.append("#") token_list.append(line[1:]) return token_list buf = [] @@ -76,7 +102,7 @@ def parse_line(line): token_list.append("".join(buf)) buf = [] else: - if c == " ": + if c in separators: if len(buf) > 0: token_list.append("".join(buf)) buf = [] @@ -86,19 +112,32 @@ def parse_line(line): buf.append(c) if not qoute and len(buf) > 0: token_list.append("".join(buf)) - if len(token_list ) > 0: + if len(token_list) > 0: first = token_list[0][0] - if first == "*" or first == ':': + if first == "*" or first == ":": token_list.insert(0, first) - token_list[1] = token_list[1][1:] + token_list[1] = token_list[1][1:] return token_list + +def set_targets(args, targets): + if not args: + return + for target in parse_line(args, ","): + target = target.strip() + if len(target) > 0: + targets.append(target) + + +set_targets(argv.final_targets, default_final_targets) +set_targets(argv.middle_targets, default_middle_targets) + input_string = sys.stdin.read() line_list = input_string.splitlines() current_table = None for line in line_list: - args = parse_line(line) - if len(args) < 1 or args[0] == "#": + args = parse_line(line, [" "]) + if len(args) < 1 or args[0] == "#": continue if args[0] == "*": if args[1] in all_chains.keys(): @@ -106,7 +145,7 @@ for line in line_list: continue if args[0] == ":": node_name = get_node_name(current_table, args[1]) - if args[2] == '-': + if args[2] == "-": args[2] = "RETURN" default_chain_policy[node_name] = args[2] continue @@ -127,25 +166,10 @@ for line in line_list: final_rule = False if target: - if target in [ - "ACCEPT", - "REJECT", - "DROP", - "RETURN", - "REDIRECT", - "MASQUERADE", - "DNAT", - "SNAT", - "DNPT", - "SNPT", - "LOG", - "QUEUE", - "MARK", - "SECMARK", - "CONNSECMARK", - "CHECKSUM" - ]: - final_rule = target not in ["LOG", "MARK", "SECMARK", "CONNSECMARK", "CHECKSUM"] + if target in default_middle_targets: + target = None + elif target in default_final_targets: + final_rule = True target = None else: node_name = get_node_name(current_table, target) @@ -173,8 +197,9 @@ for line in line_list: ) continue + def get_next_chain(table_name, chain_name): - rules=all_chains[table_name][chain_name] + rules = all_chains[table_name][chain_name] if len(rules) == 1: target = rules[0]["target"] rule = rules[0]["rule"] @@ -184,13 +209,14 @@ def get_next_chain(table_name, chain_name): return get_next_chain(table_name, target) return chain_name + if argv.eliminate: for table in all_chains: for chain in all_chains[table]: rules = all_chains[table][chain] for i in range(len(rules)): rule = rules[i]["rule"] - if len(rule) == 2 and rule[0] == "-j": + if len(rule) == 2 and rule[0] == "-j": if chain in defualt_chain_list: i += 1 while i < len(rules): @@ -200,9 +226,11 @@ if argv.eliminate: if target and target not in defualt_chain_list: rules[i]["target"] = get_next_chain(table, target) + def get_port_name(rule_index): return "rule_" + str(rule_index) + output = """digraph { graph [pad="0.5", nodesep="0.5", ranksep="2"]; node [shape=box3d] @@ -212,7 +240,11 @@ for table in all_chains: for chain in all_chains[table]: if argv.eliminate and not chain in defualt_chain_list: node_name = get_node_name(table, chain) - if node_name not in tables_target or tables_target[node_name] < 1 or len(all_chains[table][chain]) == 0: + if ( + node_name not in tables_target + or tables_target[node_name] < 1 + or len(all_chains[table][chain]) == 0 + ): continue node_name = get_node_name(table, chain) @@ -250,8 +282,12 @@ for table in all_chains: for i in range(len(all_chains[table][chain])): rule = all_chains[table][chain][i] empty_target = False - if argv.eliminate and rule["target"] and rule["target"] \ - not in defualt_chain_list and len(all_chains[table][rule["target"]]) == 0: + if ( + argv.eliminate + and rule["target"] + and rule["target"] not in defualt_chain_list + and len(all_chains[table][rule["target"]]) == 0 + ): if len(rule["rule"]) == 0: continue empty_target = True @@ -261,10 +297,10 @@ for table in all_chains: if empty_target: tmp_body += ' bgcolor="yellow"' elif rule["final"]: - target = rule['rule'][rule['rule'].index('-j') + 1] - if target == 'DROP' or target == 'REJECT': + target = rule["rule"][rule["rule"].index("-j") + 1] + if target == "DROP" or target == "REJECT": tmp_body += ' bgcolor="coral"' - elif target == 'RETURN': + elif target == "RETURN": tmp_body += ' bgcolor="moccasin"' else: tmp_body += ' bgcolor="lightgreen"' @@ -272,16 +308,17 @@ for table in all_chains: tmp_body += """ -j """ + policy + """ >]; -""") +""" + ) output += tmp_body for table in all_chains: @@ -291,7 +328,11 @@ for table in all_chains: if target: if argv.eliminate and target not in defualt_chain_list: node_name = get_node_name(table, target) - if node_name not in tables_target or tables_target[node_name] < 1 or len(all_chains[table][target]) == 0: + if ( + node_name not in tables_target + or tables_target[node_name] < 1 + or len(all_chains[table][target]) == 0 + ): continue source_node = get_node_name(table, chain) + ":" + get_port_name(i) @@ -326,15 +367,27 @@ def default_chain_link(src_table_name, src_chain_name, dst_table_name, dst_chain + """];""" ) + def default_link(): - return """ + return ( + """ START[shape=circle fillcolor=black fontcolor=white style=filled]; END[shape=circle fillcolor=black fontcolor=white style=filled]; APPLICATION[shape=circle fillcolor=black fontcolor=white style=filled]; - START->""" + get_node_name("raw", "PREROUTING") + """:begin[color=blue]; - """ + get_node_name("nat", "INPUT") + """:end-> APPLICATION[color=blue]; - APPLICATION->""" + get_node_name("raw", "OUTPUT") + """:begin[color=blue]; - """ + get_node_name("nat", "POSTROUTING") + """:end-> END[color=blue];""" + START->""" + + get_node_name("raw", "PREROUTING") + + """:begin[color=blue]; + """ + + get_node_name("nat", "INPUT") + + """:end-> APPLICATION[color=blue]; + APPLICATION->""" + + get_node_name("raw", "OUTPUT") + + """:begin[color=blue]; + """ + + get_node_name("nat", "POSTROUTING") + + """:end-> END[color=blue];""" + ) + output += default_link() From 1c0c691f60980ce348b91e19fa63f2becb5c88ba Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Mon, 15 Jan 2024 10:17:42 +0800 Subject: [PATCH 21/25] Update iptables-graph --- iptables-graph | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iptables-graph b/iptables-graph index e67747e..bac932d 100755 --- a/iptables-graph +++ b/iptables-graph @@ -124,7 +124,7 @@ def set_targets(args, targets): if not args: return for target in parse_line(args, ","): - target = target.strip() + target = target.strip().upper() if len(target) > 0: targets.append(target) From 1b3de200dad1bdac2921008d4bf395851c2a91b2 Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Mon, 15 Jan 2024 11:19:57 +0800 Subject: [PATCH 22/25] Update iptables-graph --- iptables-graph | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/iptables-graph b/iptables-graph index bac932d..671953f 100755 --- a/iptables-graph +++ b/iptables-graph @@ -204,7 +204,6 @@ def get_next_chain(table_name, chain_name): target = rules[0]["target"] rule = rules[0]["rule"] if target and len(rule) == 0: - del rules[0] tables_target[get_node_name(table_name, chain_name)] -= 1 return get_next_chain(table_name, target) return chain_name @@ -326,17 +325,27 @@ for table in all_chains: for i in range(len(all_chains[table][chain])): target = all_chains[table][chain][i]["target"] if target: - if argv.eliminate and target not in defualt_chain_list: - node_name = get_node_name(table, target) + node_name1 = get_node_name(table, chain) + node_name2 = get_node_name(table, target) + if argv.eliminate: if ( - node_name not in tables_target - or tables_target[node_name] < 1 - or len(all_chains[table][target]) == 0 + chain not in defualt_chain_list + and ( + node_name1 not in tables_target + or tables_target[node_name1] < 1 + or len(all_chains[table][chain]) == 0 + ) + or target not in defualt_chain_list + and ( + node_name2 not in tables_target + or tables_target[node_name2] < 1 + or len(all_chains[table][target]) == 0 + ) ): continue - source_node = get_node_name(table, chain) + ":" + get_port_name(i) - target_node = get_node_name(table, target) + ":begin" + source_node = node_name1 + ":" + get_port_name(i) + target_node = node_name2 + ":begin" output += ( """ """ From c7018e99e59101ecdc8f2517eba8f94f157046ed Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Tue, 23 Jan 2024 11:23:56 +0800 Subject: [PATCH 23/25] Update iptables-graph --- iptables-graph | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/iptables-graph b/iptables-graph index 671953f..e8e84de 100755 --- a/iptables-graph +++ b/iptables-graph @@ -100,12 +100,12 @@ def parse_line(line, separators): if c == '"' and line[i - 1] != "\\": qoute = False token_list.append("".join(buf)) - buf = [] + buf.clear() else: if c in separators: if len(buf) > 0: token_list.append("".join(buf)) - buf = [] + buf.clear() continue if c == '"': qoute = True @@ -172,25 +172,34 @@ for line in line_list: final_rule = True target = None else: + if target not in all_chains[current_table]: + all_chains[current_table][target] = list() + # remove JUMP + if argv.eliminate: + del args[i-1] + del args[i-1] node_name = get_node_name(current_table, target) if node_name not in tables_target: tables_target[node_name] = 0 tables_target[node_name] += 1 - # remove JUMP - del args[i - 1] - del args[i - 1] + if node_name not in tables_comment: + tables_comment[node_name] = list() + comment = current_table + ":" + target if "--comment" in args: i = args.index("--comment") + 1 if i < len(args): - comment = args[i].replace("\\", "") - if node_name not in tables_comment: - tables_comment[node_name] = [] - if len(comment) > 0: - comment = get_escape(comment[1 : len(comment) - 1]) - if comment not in tables_comment[node_name]: - tables_comment[node_name].append(comment) - if target not in all_chains[current_table]: - all_chains[current_table][target] = list() + tmp = args[i].replace("\\", "") + i = len(tmp) + if i > 0 and tmp[0] == '"' and tmp[i-1] == '"': + tmp = get_escape(tmp[1 : i-1]) + i = len(tmp) + if i > 0: + if comment in tables_comment[node_name]: + i = tables_comment[node_name].index(comment) + del tables_comment[node_name][i] + comment = tmp + if comment not in tables_comment[node_name]: + tables_comment[node_name].append(comment) all_chains[current_table][current_chain].append( {"rule": args[2:], "target": target, "final": final_rule} From 0b79d0af0ac70a60699464a11f1d35a1969f316b Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Tue, 23 Jan 2024 11:25:19 +0800 Subject: [PATCH 24/25] Update example.txt --- example.txt | 125 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 32 deletions(-) diff --git a/example.txt b/example.txt index 8b6c7b7..238731f 100644 --- a/example.txt +++ b/example.txt @@ -1,35 +1,96 @@ -# Generated by iptables-save v1.6.0 on Thu Apr 8 16:44:20 2021 -*nat -:PREROUTING ACCEPT [1:44] -:INPUT ACCEPT [1:44] -:OUTPUT ACCEPT [108934:8322365] -:POSTROUTING ACCEPT [108934:8322365] -:DOCKER - [0:0] --A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER --A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER --A POSTROUTING -s 172.18.0.0/24 ! -o docker0 -j MASQUERADE --A DOCKER -i docker0 -j RETURN +# Generated by iptables-save v1.8.7 on Tue Jan 23 02:39:22 2024 +*mangle +:PREROUTING ACCEPT [0:0] +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +:KUBE-IPTABLES-HINT - [0:0] +:KUBE-KUBELET-CANARY - [0:0] COMMIT -# Completed on Thu Apr 8 16:44:20 2021 -# Generated by iptables-save v1.6.0 on Thu Apr 8 16:44:20 2021 +# Completed on Tue Jan 23 02:39:22 2024 +# Generated by iptables-save v1.8.7 on Tue Jan 23 02:39:22 2024 *filter -:INPUT ACCEPT [5732373:3510919135] -:FORWARD DROP [0:0] -:OUTPUT ACCEPT [3381411:259078259] -:DOCKER - [0:0] -:DOCKER-ISOLATION-STAGE-1 - [0:0] -:DOCKER-ISOLATION-STAGE-2 - [0:0] -:DOCKER-USER - [0:0] --A FORWARD -j DOCKER-USER --A FORWARD -j DOCKER-ISOLATION-STAGE-1 --A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT --A FORWARD -o docker0 -j DOCKER --A FORWARD -i docker0 ! -o docker0 -j ACCEPT --A FORWARD -i docker0 -o docker0 -j ACCEPT --A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2 --A DOCKER-ISOLATION-STAGE-1 -j RETURN --A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP --A DOCKER-ISOLATION-STAGE-2 -j RETURN --A DOCKER-USER -j RETURN +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:FLANNEL-FWD - [0:0] +:KUBE-FIREWALL - [0:0] +:KUBE-FORWARD - [0:0] +:KUBE-IPVS-FILTER - [0:0] +:KUBE-IPVS-OUT-FILTER - [0:0] +:KUBE-KUBELET-CANARY - [0:0] +:KUBE-NODE-PORT - [0:0] +:KUBE-PROXY-FIREWALL - [0:0] +:KUBE-SOURCE-RANGES-FIREWALL - [0:0] +-A INPUT -m comment --comment "kubernetes ipvs access filter" -j KUBE-IPVS-FILTER +-A INPUT -m comment --comment "kube-proxy firewall rules" -j KUBE-PROXY-FIREWALL +-A INPUT -m comment --comment "kubernetes health check rules" -j KUBE-NODE-PORT +-A INPUT -j KUBE-FIREWALL +-A FORWARD -m comment --comment "kube-proxy firewall rules" -j KUBE-PROXY-FIREWALL +-A FORWARD -m comment --comment "kubernetes forwarding rules" -j KUBE-FORWARD +-A FORWARD -m comment --comment "flanneld forward" -j FLANNEL-FWD +-A OUTPUT -m comment --comment "kubernetes ipvs access filter" -j KUBE-IPVS-OUT-FILTER +-A OUTPUT -j KUBE-FIREWALL +-A FLANNEL-FWD -s 10.244.0.0/16 -m comment --comment "flanneld forward" -j ACCEPT +-A FLANNEL-FWD -d 10.244.0.0/16 -m comment --comment "flanneld forward" -j ACCEPT +-A KUBE-FIREWALL ! -s 127.0.0.0/8 -d 127.0.0.0/8 -m comment --comment "block incoming localnet connections" -m conntrack ! --ctstate RELATED,ESTABLISHED,DNAT -j DROP +-A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -j ACCEPT +-A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT +-A KUBE-IPVS-FILTER -m set --match-set KUBE-LOAD-BALANCER dst,dst -j RETURN +-A KUBE-IPVS-FILTER -m set --match-set KUBE-CLUSTER-IP dst,dst -j RETURN +-A KUBE-IPVS-FILTER -m set --match-set KUBE-EXTERNAL-IP dst,dst -j RETURN +-A KUBE-IPVS-FILTER -m set --match-set KUBE-EXTERNAL-IP-LOCAL dst,dst -j RETURN +-A KUBE-IPVS-FILTER -m set --match-set KUBE-HEALTH-CHECK-NODE-PORT dst -j RETURN +-A KUBE-IPVS-FILTER -m conntrack --ctstate NEW -m set --match-set KUBE-IPVS-IPS dst -j REJECT --reject-with icmp-port-unreachable +-A KUBE-NODE-PORT -m comment --comment "Kubernetes health check node port" -m set --match-set KUBE-HEALTH-CHECK-NODE-PORT dst -j ACCEPT +-A KUBE-SOURCE-RANGES-FIREWALL -j DROP +COMMIT +# Completed on Tue Jan 23 02:39:22 2024 +# Generated by iptables-save v1.8.7 on Tue Jan 23 02:39:22 2024 +*nat +:PREROUTING ACCEPT [15036:904858] +:INPUT ACCEPT [14908:894762] +:OUTPUT ACCEPT [724068:43444067] +:POSTROUTING ACCEPT [244344:14660705] +:DOCKER_OUTPUT - [0:0] +:DOCKER_POSTROUTING - [0:0] +:FLANNEL-POSTRTG - [0:0] +:KUBE-KUBELET-CANARY - [0:0] +:KUBE-LOAD-BALANCER - [0:0] +:KUBE-MARK-MASQ - [0:0] +:KUBE-NODE-PORT - [0:0] +:KUBE-POSTROUTING - [0:0] +:KUBE-SERVICES - [0:0] +-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES +-A PREROUTING -d 172.18.0.1/32 -j DOCKER_OUTPUT +-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES +-A OUTPUT -d 172.18.0.1/32 -j DOCKER_OUTPUT +-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING +-A POSTROUTING -d 172.18.0.1/32 -j DOCKER_POSTROUTING +-A POSTROUTING -m comment --comment "flanneld masq" -j FLANNEL-POSTRTG +-A DOCKER_OUTPUT -d 172.18.0.1/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination 127.0.0.11:33955 +-A DOCKER_OUTPUT -d 172.18.0.1/32 -p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.11:39855 +-A DOCKER_POSTROUTING -s 127.0.0.11/32 -p tcp -j SNAT --to-source 172.18.0.1:53 +-A DOCKER_POSTROUTING -s 127.0.0.11/32 -p udp -j SNAT --to-source 172.18.0.1:53 +-A FLANNEL-POSTRTG -m comment --comment "flanneld masq" -j RETURN +-A FLANNEL-POSTRTG -s 10.244.0.0/24 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j RETURN +-A FLANNEL-POSTRTG -s 10.244.0.0/16 -d 10.244.0.0/24 -m comment --comment "flanneld masq" -j RETURN +-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.0.0/24 -m comment --comment "flanneld masq" -j RETURN +-A FLANNEL-POSTRTG -s 10.244.0.0/16 ! -d 224.0.0.0/4 -m comment --comment "flanneld masq" -j MASQUERADE --random-fully +-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j MASQUERADE --random-fully +-A KUBE-LOAD-BALANCER -j KUBE-MARK-MASQ +-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000 +-A KUBE-NODE-PORT -p tcp -m comment --comment "Kubernetes nodeport TCP port for masquerade purpose" -m set --match-set KUBE-NODE-PORT-TCP dst -j KUBE-MARK-MASQ +-A KUBE-POSTROUTING -m comment --comment "Kubernetes endpoints dst ip:port, source ip for solving hairpin purpose" -m set --match-set KUBE-LOOP-BACK dst,dst,src -j MASQUERADE +-A KUBE-POSTROUTING -j RETURN +-A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0 +-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully +-A KUBE-SERVICES -s 127.0.0.0/8 -j RETURN +-A KUBE-SERVICES -m comment --comment "Kubernetes service lb portal" -m set --match-set KUBE-LOAD-BALANCER dst,dst -j KUBE-LOAD-BALANCER +-A KUBE-SERVICES ! -s 10.244.0.0/16 -m comment --comment "Kubernetes service cluster ip + port for masquerade purpose" -m set --match-set KUBE-CLUSTER-IP dst,dst -j KUBE-MARK-MASQ +-A KUBE-SERVICES -m addrtype --dst-type LOCAL -j KUBE-NODE-PORT +-A KUBE-SERVICES -m set --match-set KUBE-CLUSTER-IP dst,dst -j ACCEPT +-A KUBE-SERVICES -m set --match-set KUBE-LOAD-BALANCER dst,dst -j ACCEPT COMMIT -# Completed on Thu Apr 8 16:44:20 2021 +# Completed on Tue Jan 23 02:39:22 2024 From 8bf035a55d47a28afc14e2ff1d6654305f490b6c Mon Sep 17 00:00:00 2001 From: Jacky WU Date: Tue, 23 Jan 2024 11:26:28 +0800 Subject: [PATCH 25/25] Update example.svg --- example.svg | 1181 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 857 insertions(+), 324 deletions(-) diff --git a/example.svg b/example.svg index 14ca587..783f548 100644 --- a/example.svg +++ b/example.svg @@ -1,359 +1,892 @@ - - - + + %3 - - -filter_DOCKERUSER - - -DOCKER-USER - -filter - --j RETURN - -end - - -filter_DOCKERISOLATIONSTAGE1 - - -DOCKER-ISOLATION-STAGE-1 - -filter - --i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2 - --j RETURN - -end - - -filter_DOCKERISOLATIONSTAGE2 - - -DOCKER-ISOLATION-STAGE-2 - -filter - --o docker0 -j DROP - --j RETURN - -end - - -filter_DOCKERISOLATIONSTAGE1:rule_0->filter_DOCKERISOLATIONSTAGE2:begin - - - - -filter_OUTPUT - - - -OUTPUT - - -filter - -end - - -mangle_POSTROUTING - - - -POSTROUTING - - -mangle - -end - - -filter_OUTPUT:end->mangle_POSTROUTING:begin - - + + + +raw_PREROUTING + + + + + + +raw:PREROUTING + + + +-j ACCEPT - -filter_FORWARD - - - -FORWARD - - -filter - --j DOCKER-USER - --j DOCKER-ISOLATION-STAGE-1 - --o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - --o docker0 -j DOCKER - --i docker0 ! -o docker0 -j ACCEPT - --i docker0 -o docker0 -j ACCEPT - -end - - -filter_FORWARD:rule_0->filter_DOCKERUSER:begin - - - - -filter_FORWARD:rule_1->filter_DOCKERISOLATIONSTAGE1:begin - - - - -filter_DOCKER - - -DOCKER - -filter - -end - - -filter_FORWARD:rule_3->filter_DOCKER:begin - - - - -filter_FORWARD:end->mangle_POSTROUTING:begin - - + + +mangle_PREROUTING + + + + + + +mangle:PREROUTING + + + +-j ACCEPT - -filter_INPUT - - - -INPUT - - -filter - -end + + +raw_PREROUTING:end->mangle_PREROUTING:begin + + -raw_OUTPUT - - - -OUTPUT - - -raw - -end - - -filter_INPUT:end->raw_OUTPUT:begin - - + +raw_OUTPUT + + + + + + +raw:OUTPUT + + + +-j ACCEPT -mangle_OUTPUT - - - -OUTPUT - - -mangle - -end + +mangle_OUTPUT + + + + + + +mangle:OUTPUT + + + +-j ACCEPT -raw_OUTPUT:end->mangle_OUTPUT:begin - - + +raw_OUTPUT:end->mangle_OUTPUT:begin + + - -raw_PREROUTING - - - -PREROUTING - - -raw - -end + + +filter_INPUT + + + + + + +filter:INPUT + + +-m comment --comment "kubernetes ipvs access filter" -j KUBE-IPVS-FILTER + +-m comment --comment "kube-proxy firewall rules" -j KUBE-PROXY-FIREWALL + +-m comment --comment "kubernetes health check rules" -j KUBE-NODE-PORT + +-j KUBE-FIREWALL + + +-j ACCEPT + + + +filter_KUBEIPVSFILTER + + + + + + +kubernetes ipvs access filter + + + +-m set --match-set KUBE-LOAD-BALANCER dst,dst -j RETURN + + +-m set --match-set KUBE-CLUSTER-IP dst,dst -j RETURN + + +-m set --match-set KUBE-EXTERNAL-IP dst,dst -j RETURN + + +-m set --match-set KUBE-EXTERNAL-IP-LOCAL dst,dst -j RETURN + + +-m set --match-set KUBE-HEALTH-CHECK-NODE-PORT dst -j RETURN + + +-m conntrack --ctstate NEW -m set --match-set KUBE-IPVS-IPS dst -j REJECT --reject-with icmp-port-unreachable + +-j RETURN + + + +filter_INPUT:rule_0->filter_KUBEIPVSFILTER:begin + + + + + +filter_KUBEPROXYFIREWALL + + + + + + +kube-proxy firewall rules + + +-j RETURN + + + +filter_INPUT:rule_1->filter_KUBEPROXYFIREWALL:begin + + + + + +filter_KUBENODEPORT + + + + + + +kubernetes health check rules + + + +-m comment --comment "Kubernetes health check node port" -m set --match-set KUBE-HEALTH-CHECK-NODE-PORT dst -j ACCEPT + +-j RETURN + + + +filter_INPUT:rule_2->filter_KUBENODEPORT:begin + + + + + +filter_KUBEFIREWALL + + + + + + +filter:KUBE-FIREWALL + + + +! -s 127.0.0.0/8 -d 127.0.0.0/8 -m comment --comment "block incoming localnet connections" -m conntrack ! --ctstate RELATED,ESTABLISHED,DNAT -j DROP + +-j RETURN + + + +filter_INPUT:rule_3->filter_KUBEFIREWALL:begin + + + + + +security_INPUT + + + + + + +security:INPUT + + + +-j ACCEPT + + + +filter_INPUT:end->security_INPUT:begin + + - -mangle_PREROUTING - - - -PREROUTING - - -mangle - -end + + +filter_OUTPUT + + + + + + +filter:OUTPUT + + +-m comment --comment "kubernetes ipvs access filter" -j KUBE-IPVS-OUT-FILTER + +-j KUBE-FIREWALL + + +-j ACCEPT + + + +filter_OUTPUT:rule_1->filter_KUBEFIREWALL:begin + + + + + +filter_KUBEIPVSOUTFILTER + + + + + + +kubernetes ipvs access filter + + +-j RETURN + + + +filter_OUTPUT:rule_0->filter_KUBEIPVSOUTFILTER:begin + + + + + +security_OUTPUT + + + + + + +security:OUTPUT + + + +-j ACCEPT + + + +filter_OUTPUT:end->security_OUTPUT:begin + + - -raw_PREROUTING:end->mangle_PREROUTING:begin - - + + +filter_FORWARD + + + + + + +filter:FORWARD + + +-m comment --comment "kube-proxy firewall rules" -j KUBE-PROXY-FIREWALL + +-m comment --comment "kubernetes forwarding rules" -j KUBE-FORWARD + +-m comment --comment "flanneld forward" -j FLANNEL-FWD + + +-j ACCEPT + + + +filter_FORWARD:rule_0->filter_KUBEPROXYFIREWALL:begin + + + + + +filter_KUBEFORWARD + + + + + + +kubernetes forwarding rules + + + +-m comment --comment "kubernetes forwarding rules" -j ACCEPT + + +-m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + +-j RETURN + + + +filter_FORWARD:rule_1->filter_KUBEFORWARD:begin + + + + + +filter_FLANNELFWD + + + + + + +flanneld forward + + + +-s 10.244.0.0/16 -m comment --comment "flanneld forward" -j ACCEPT + + +-d 10.244.0.0/16 -m comment --comment "flanneld forward" -j ACCEPT + +-j RETURN + + + +filter_FORWARD:rule_2->filter_FLANNELFWD:begin + + + + + +security_FORWARD + + + + + + +security:FORWARD + + + +-j ACCEPT + + + +filter_FORWARD:end->security_FORWARD:begin + + + + + +filter_KUBESOURCERANGESFIREWALL + + + + + + +filter:KUBESOURCERANGESFIREWALL + + + +-j DROP + +-j RETURN + + + +nat_INPUT + + + + + + +nat:INPUT + + + +-j ACCEPT + + + +security_INPUT:end->nat_INPUT:begin + + - -mangle_FORWARD - - - -FORWARD - - -mangle - -end + + +mangle_POSTROUTING + + + + + + +mangle:POSTROUTING + + + +-j ACCEPT + + + +security_OUTPUT:end->mangle_POSTROUTING:begin + + + + + +security_FORWARD:end->mangle_POSTROUTING:begin + + - -mangle_FORWARD:end->filter_FORWARD:begin - - + + +nat_PREROUTING + + + + + + +nat:PREROUTING + + +-m comment --comment "kubernetes service portals" -j KUBE-SERVICES + +-d 172.18.0.1/32 -j DOCKER_OUTPUT + + +-j ACCEPT + + + +nat_KUBESERVICES + + + + + + +kubernetes service portals + + + +-s 127.0.0.0/8 -j RETURN + +-m comment --comment "Kubernetes service lb portal" -m set --match-set KUBE-LOAD-BALANCER dst,dst -j KUBE-LOAD-BALANCER + +! -s 10.244.0.0/16 -m comment --comment "Kubernetes service cluster ip + port for masquerade purpose" -m set --match-set KUBE-CLUSTER-IP dst,dst -j KUBE-MARK-MASQ + +-m addrtype --dst-type LOCAL -j KUBE-NODE-PORT + + +-m set --match-set KUBE-CLUSTER-IP dst,dst -j ACCEPT + + +-m set --match-set KUBE-LOAD-BALANCER dst,dst -j ACCEPT + +-j RETURN + + + +nat_PREROUTING:rule_0->nat_KUBESERVICES:begin + + + + + +nat_DOCKEROUTPUT + + + + + + +nat:DOCKER_OUTPUT + + + +-d 172.18.0.1/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination 127.0.0.11:33955 + + +-d 172.18.0.1/32 -p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.11:39855 + +-j RETURN + + + +nat_PREROUTING:rule_1->nat_DOCKEROUTPUT:begin + + -mangle_INPUT - - - -INPUT - - -mangle - -end + +mangle_INPUT + + + + + + +mangle:INPUT + + + +-j ACCEPT - -mangle_INPUT:end->filter_INPUT:begin - - + + +nat_PREROUTING:end->mangle_INPUT:begin + + - -nat_POSTROUTING - - - -POSTROUTING - - -nat - --s 172.18.0.0/24 ! -o docker0 -j MASQUERADE - -end + + +mangle_FORWARD + + + + + + +mangle:FORWARD + + + +-j ACCEPT - -mangle_POSTROUTING:end->nat_POSTROUTING:begin - - + + +nat_PREROUTING:end->mangle_FORWARD:begin + + + + + +APPLICATION + +APPLICATION + + + +nat_INPUT:end->APPLICATION + + - -nat_PREROUTING - - - -PREROUTING - - -nat - --m addrtype --dst-type LOCAL -j DOCKER - -end + + +nat_OUTPUT + + + + + + +nat:OUTPUT + + +-m comment --comment "kubernetes service portals" -j KUBE-SERVICES + +-d 172.18.0.1/32 -j DOCKER_OUTPUT + + +-j ACCEPT + + + +nat_OUTPUT:end->filter_OUTPUT:begin + + + + + +nat_OUTPUT:rule_0->nat_KUBESERVICES:begin + + + + + +nat_OUTPUT:rule_1->nat_DOCKEROUTPUT:begin + + + + + +nat_POSTROUTING + + + + + + +nat:POSTROUTING + + +-m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING + +-d 172.18.0.1/32 -j DOCKER_POSTROUTING + +-m comment --comment "flanneld masq" -j FLANNEL-POSTRTG + + +-j ACCEPT + + + +nat_KUBEPOSTROUTING + + + + + + +kubernetes postrouting rules + + + +-m comment --comment "Kubernetes endpoints dst ip:port, source ip for solving hairpin purpose" -m set --match-set KUBE-LOOP-BACK dst,dst,src -j MASQUERADE + + +-j RETURN + +-j MARK --set-xmark 0x4000/0x0 + + +-m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully + +-j RETURN + + + +nat_POSTROUTING:rule_0->nat_KUBEPOSTROUTING:begin + + + + + +nat_DOCKERPOSTROUTING + + + + + + +nat:DOCKER_POSTROUTING + + + +-s 127.0.0.11/32 -p tcp -j SNAT --to-source 172.18.0.1:53 + + +-s 127.0.0.11/32 -p udp -j SNAT --to-source 172.18.0.1:53 + +-j RETURN + + + +nat_POSTROUTING:rule_1->nat_DOCKERPOSTROUTING:begin + + + + + +nat_FLANNELPOSTRTG + + + + + + +flanneld masq + + + +-m comment --comment "flanneld masq" -j RETURN + + +-s 10.244.0.0/24 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j RETURN + + +-s 10.244.0.0/16 -d 10.244.0.0/24 -m comment --comment "flanneld masq" -j RETURN + + +! -s 10.244.0.0/16 -d 10.244.0.0/24 -m comment --comment "flanneld masq" -j RETURN + + +-s 10.244.0.0/16 ! -d 224.0.0.0/4 -m comment --comment "flanneld masq" -j MASQUERADE --random-fully + + +! -s 10.244.0.0/16 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j MASQUERADE --random-fully + +-j RETURN + + + +nat_POSTROUTING:rule_2->nat_FLANNELPOSTRTG:begin + + + + + +END + +END + + + +nat_POSTROUTING:end->END + + + + + +nat_KUBELOADBALANCER + + + + + + +Kubernetes service lb portal + + +-j KUBE-MARK-MASQ + +-j RETURN + + + +nat_KUBESERVICES:rule_1->nat_KUBELOADBALANCER:begin + + + + + +nat_KUBEMARKMASQ + + + + + + +Kubernetes nodeport TCP port for masquerade purpose + + +Kubernetes service cluster ip + port for masquerade purpose + + +-j MARK --set-xmark 0x4000/0x4000 + +-j RETURN + + + +nat_KUBESERVICES:rule_2->nat_KUBEMARKMASQ:begin + + + + + +nat_KUBENODEPORT + + + + + + +nat:KUBE-NODE-PORT + + +-p tcp -m comment --comment "Kubernetes nodeport TCP port for masquerade purpose" -m set --match-set KUBE-NODE-PORT-TCP dst -j KUBE-MARK-MASQ + +-j RETURN + + + +nat_KUBESERVICES:rule_3->nat_KUBENODEPORT:begin + + + + + +nat_KUBELOADBALANCER:rule_0->nat_KUBEMARKMASQ:begin + + + + + +nat_KUBENODEPORT:rule_0->nat_KUBEMARKMASQ:begin + + -mangle_PREROUTING:end->nat_PREROUTING:begin - - + +mangle_PREROUTING:end->nat_PREROUTING:begin + + - -nat_OUTPUT - - - -OUTPUT - - -nat - -! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER - -end + + +mangle_INPUT:end->filter_INPUT:begin + + -mangle_OUTPUT:end->nat_OUTPUT:begin - - - - -nat_MASQUERADE - - -MASQUERADE - -nat - -end - - -nat_OUTPUT:end->filter_OUTPUT:begin - - - - -nat_DOCKER - - -DOCKER - -nat - --i docker0 -j RETURN - -end - - -nat_OUTPUT:rule_0->nat_DOCKER:begin - - + +mangle_OUTPUT:end->nat_OUTPUT:begin + + - -nat_PREROUTING:end->mangle_FORWARD:begin - - + + +mangle_FORWARD:end->filter_FORWARD:begin + + - -nat_PREROUTING:end->mangle_INPUT:begin - - - - -nat_PREROUTING:rule_0->nat_DOCKER:begin - - - - -nat_POSTROUTING:rule_0->nat_MASQUERADE:begin - - + + +mangle_POSTROUTING:end->nat_POSTROUTING:begin + + + + + +START + +START + + + +START->raw_PREROUTING:begin + + + + + +APPLICATION->raw_OUTPUT:begin + +