├── LICENSE
├── README.md
├── doc
├── example.svg
├── legend.dia
└── legend.svg
└── iptables-vis.awk
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | iptables-vis – visualise iptables chains
2 | ========================================
3 |
4 | This script reads iptables output and generates a nice flow chart. Works with all tables and chains.
5 |
6 | 
7 |
8 | Usage
9 | =====
10 | - Clone repo, make sure awk is installed, install [blockdiag](http://blockdiag.com)
11 | - `iptables -v -L > iptables.txt`
12 | - `awk -f iptables-vis.awk < iptables.txt > iptables.dia`
13 | - `blockdiag iptables.dia -T svg -o iptables.svg`
14 |
15 | To display only selected chains (supports regexp):
16 |
17 | `awk -f iptables-vis.awk -v 'chain_selector=INPUT|OUTPUT|mychain' < iptables.txt > iptables.dia`
18 |
19 | To also render empty chains:
20 |
21 | `awk -f iptables-vis.awk -v 'include_empty_chains=1 < iptables.txt > iptables.dia'`
22 |
23 | Legend
24 | ======
25 |
26 | 
27 |
--------------------------------------------------------------------------------
/doc/example.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
492 |
--------------------------------------------------------------------------------
/doc/legend.dia:
--------------------------------------------------------------------------------
1 | blockdiag {
2 | node_width = 200;
3 | INPUT [class=chain_head, shape=box]
4 | Node0 [class=rule, label="Rule"]
5 | group {
6 | shape=line
7 | style=none
8 | Node0 [class=rule, label="in:eth0 tcp"]
9 | f0 [style=none, label="Rule that matches tcp pakages from eth0", fontsize=14]
10 | Node0 -> f0 [style=none]
11 | } group {
12 | shape=line
13 | style=none
14 | Node1 [class=rule, label="*"]
15 | f1 [style=none, label="Rule that always matches", fontsize=14]
16 | Node1 -> f1 [style=none]
17 | }
18 | ACCEPT [class=accept]
19 | DROP [class=drop]
20 | RETURN [class=return]
21 | AUDIT [class=target]
22 | chain [class=target, class="chain", label="user defined chain"]
23 | empty_chain [class=target, class="empty_chain", label="empty chain"]
24 | class chain_head [shape=ellipse]
25 | class rule [shape=diamond, width=200]
26 | class target [width=150]
27 | class reject [color = "red", label="REJECT"]
28 | class reject_line [color = "red"]
29 | class drop [color = "red", label="DROP"]
30 | class return [color = "#1ab3ff", label="RETURN"]
31 | class return_line [color = "blue"]
32 | class accept [color = "lightgreen", label="ACCEPT"]
33 | class accept_line [color = "green"]
34 | class fake [shape=none, width=1]
35 | class ACCEPT [shape=box]
36 | class LOG [shape=box]
37 | class chain [shape=ellipse]
38 | class empty_chain [shape=ellipse, style=dotted, linecolor="#444", textcolor="#444"]
39 | }
40 |
--------------------------------------------------------------------------------
/doc/legend.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
87 |
--------------------------------------------------------------------------------
/iptables-vis.awk:
--------------------------------------------------------------------------------
1 | #!/usr/bin/awk -f
2 | #
3 | BEGIN {
4 | print indent "blockdiag {" # }
5 | indent=" "
6 | print indent "orientation=portrait"
7 | counter = 0
8 | }
9 |
10 | # Begin of a chain
11 | /^Chain/ {
12 | chainname = $2
13 | in_chain=1
14 | is_a_chain[chainname] = 1
15 | if ( chainname !~ chain_selector && chain_selector != "")
16 | next
17 | in_relevant_chain=1
18 | if ( $3 == "(policy" )
19 | policy=$4
20 | else
21 | policy=0
22 | last=chainname
23 | print indent "group {" # } group the chain
24 | indent=" "
25 | print indent "orientation=portrait"
26 | print indent "shape=line; style=none"
27 | print indent "group {" # } group the filter rules
28 | indent=" "
29 | print indent "orientation=portrait"
30 | print indent "shape=line; style=none"
31 | }
32 |
33 | # Filter in chain
34 | in_chain && /^ *[0-9]/ {
35 | filters_in_chain++
36 | if ( !in_relevant_chain )
37 | next
38 | name="Node" counter++
39 | reject_with=""
40 | label=""
41 | if ( $4 != "all" )
42 | label=label $4 " "
43 | if ( $5 != "--" )
44 | label=label $5 " "
45 | if ( $6 != "any" )
46 | label=label "in:" $6 " "
47 | if ( $7 != "any" )
48 | label=label "out:" $7 " "
49 | if ( $8 != "anywhere" )
50 | label=label "src:" $8 " "
51 | if ( $9 != "anywhere" )
52 | label=label "dst:" $9 " "
53 | comment=0
54 | for (i=10; i<=NF; i++) {
55 | if ( $i == "/*" )
56 | comment=1
57 | else if ( $i == "*/" )
58 | comment=0
59 | else if ( $i == "reject-with" ) {
60 | i++
61 | reject_with = $i
62 | i++
63 | }
64 | else if ( ! comment )
65 | label=label " " $i
66 | }
67 | if ( label == "" )
68 | label = "*"
69 | gsub(/ /, " ", label);
70 | gsub(/^ *| *$/, "", label);
71 | gsub(/'/, "\\'", label);
72 | print indent name " [class=rule, label='" label "']"
73 | print indent last, "->", name
74 | last=name
75 | filter_nodes[num_targets++] = name
76 | target_node_name = chainname "_" $3
77 | if ( reject_with )
78 | target_node_name = target_node_name "_" reject_with
79 | target_label = $3
80 | if ( reject_with )
81 | target_label = target_label "\\n" reject_with
82 |
83 | targets[name] = $3
84 | all_targets[name] = $3
85 | target_node_names[name] = target_node_name
86 | target_labels[target_node_name] = target_label
87 | }
88 |
89 | # End of chain
90 | /^$/ {
91 | in_chain=0
92 | filter_number[chainname] = filters_in_chain
93 | if (in_relevant_chain)
94 | finalize_chain()
95 | filters_in_chain=0
96 | in_relevant_chain=0
97 | }
98 |
99 | function finalize_chain() {
100 | if ( filters_in_chain || include_empty_chains ) {
101 | if ( chainname ~ "^(INPUT|OUTPUT|FORWARD|PREROUTING|POSTROUTING)$" )
102 | print indent chainname " [class=chain_head, shape=box]"
103 | else
104 | print indent chainname " [class=chain_head]"
105 | }
106 | if ( policy ) {
107 | print indent last " -- " chainname "_END -> " chainname "_" policy
108 | print indent chainname "_END" " [shape=none]"
109 | }
110 | # { End filter group
111 | indent=" "
112 | print indent "}"
113 |
114 | # Draw all connections to targets
115 | for ( idx in filter_nodes ) {
116 | name = filter_nodes[idx]
117 | target = targets[name]
118 | target_node_name = target_node_names[name]
119 | target_label = target_labels[target_node_name]
120 | if ( target ~ "^ACCEPT$" )
121 | linestyle=" [class=accept_line]"
122 | else if ( target ~ "^REJECT($|_)|DROP$" )
123 | linestyle=" [class=reject_line]"
124 | else if ( target ~ "^RETURN$" )
125 | linestyle=" [class=return_line]"
126 | else
127 | linestyle=""
128 | # To avoid issues of the dia rendering, a "fakenode" – a node that is
129 | # empty, not visible and of minimal size has to be used.
130 | # For connections to the policy we use an extra node, to make sure the
131 | # line doesn't cross any other.
132 | if ( target != policy )
133 | print indent name, "-- f" fakenode++, "->", target_node_name linestyle;
134 | else
135 | print indent name, "-- f" fakenode++, "-> f" fakenode++, "->", target_node_name linestyle;
136 | }
137 |
138 | # Format all target nodes
139 | if ( policy ) {
140 | targets[++num_targets] = policy # Policies are also targets
141 | target_node_names[num_targets] = chainname "_" policy # Policies are also targets
142 | }
143 | for ( name in target_node_names ) {
144 | target = targets[name]
145 | target_node_name = target_node_names[name]
146 | target_label_esc =target_label = target_labels[target_node_name]
147 | gsub(/\47/, "\\\\&", target_label_esc)
148 | if ( allready_rendered[target_node_name] )
149 | continue
150 | else
151 | allready_rendered[target_node_name] = 1
152 | if ( target ~ "^ACCEPT$" ) {
153 | print indent chainname "_ACCEPT [class=accept]"
154 | }
155 | else if ( target ~ "^DROP$" ) {
156 | print indent chainname "_DROP [class=drop]"
157 | }
158 | else if ( target ~ "^REJECT($|_)" ) {
159 | print indent target_node_name " [class=reject, label='" target_label_esc"']"
160 | }
161 | else if ( target ~ "^RETURN$" ) {
162 | print indent chainname "_RETURN [class=return]"
163 | }
164 | else {
165 | print indent target_node_name " [class=target, class='" target_label_esc"', label='" target_label_esc "']"
166 | }
167 | }
168 | delete filter_nodes
169 | delete targets
170 | delete target_node_names
171 | delete target_labels
172 | delete allready_rendered
173 | # { End group around chain
174 | indent=" "
175 | print indent "}"
176 | }
177 |
178 | END {
179 | filter_number[chainname] = filters_in_chain
180 | if (in_relevant_chain)
181 | finalize_chain()
182 | print indent "class chain_head [shape=ellipse]"
183 | print indent "class rule [shape=diamond, width=200]"
184 | print indent "class target [width=150]"
185 | print indent "class reject [color = \"red\", label=\"REJECT\"]"
186 | print indent "class reject_line [color = \"red\"]"
187 | print indent "class drop [color = \"red\", label=\"DROP\"]"
188 | print indent "class return [color = \"#1ab3ff\", label=\"RETURN\"]"
189 | print indent "class return_line [color = \"blue\"]"
190 | print indent "class accept [color = \"lightgreen\", label=\"ACCEPT\"]"
191 | print indent "class accept_line [color = \"green\"]"
192 | print indent "class fake [shape=none, width=1]"
193 | for (i=0; i<=fakenode; i++)
194 | print indent "f" i " [class=fake]"
195 | # Style the targets depending on their type and content
196 | for ( idx in all_targets ) {
197 | target=all_targets[idx]
198 | if ( ! is_a_chain[target] )
199 | style="shape=box"
200 | else if (filter_number[all_targets[idx]] == 0 )
201 | style="shape=ellipse, style=dotted, linecolor=\"#444\", textcolor=\"#444\""
202 | else
203 | style="shape=ellipse, linecolor=black"
204 | print indent "class", all_targets[idx], "["style"]"
205 | }
206 | # { End blockdiag
207 | indent=""
208 | print indent "}"
209 | }
210 |
--------------------------------------------------------------------------------