├── 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 | ![Example](doc/example.svg) 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 | ![Legend](doc/legend.svg) 27 | -------------------------------------------------------------------------------- /doc/example.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | blockdiag 10 | blockdiag { 11 | orientation=portrait 12 | group { 13 | orientation=portrait 14 | shape=line; style=none 15 | group { 16 | orientation=portrait 17 | shape=line; style=none 18 | Node0 [class=rule, label="in:lo src:localhost dst:localhost"] 19 | INPUT -> Node0 20 | Node1 [class=rule, label="in:tun0"] 21 | Node0 -> Node1 22 | Node2 [class=rule, label="tcp tcp flags:!FIN,SYN,RST,ACK/SYN state NEW"] 23 | Node1 -> Node2 24 | Node3 [class=rule, label="state log_INVALID"] 25 | Node2 -> Node3 26 | Node4 [class=rule, label="icmp state NEW"] 27 | Node3 -> Node4 28 | Node5 [class=rule, label="icmp state ESTABLISHED"] 29 | Node4 -> Node5 30 | Node6 [class=rule, label="tcp tcp flags:FIN,SYN,RST,PSH,ACK,URG/NONE"] 31 | Node5 -> Node6 32 | Node7 [class=rule, label="tcp tcp flags:FIN,SYN/FIN,SYN"] 33 | Node6 -> Node7 34 | Node8 [class=rule, label="tcp tcp flags:SYN,RST/SYN,RST"] 35 | Node7 -> Node8 36 | Node9 [class=rule, label="tcp tcp flags:FIN,RST/FIN,RST"] 37 | Node8 -> Node9 38 | Node10 [class=rule, label="tcp tcp flags:FIN,ACK/FIN"] 39 | Node9 -> Node10 40 | Node11 [class=rule, label="tcp tcp flags:ACK,URG/URG"] 41 | Node10 -> Node11 42 | INPUT [class=chain_head, shape=box] 43 | Node11 -- INPUT_END -> INPUT_DROP 44 | INPUT_END [shape=none] 45 | } 46 | Node0 -- f0 -> INPUT_ACCEPT [class=accept_line] 47 | Node1 -- f1 -> INPUT_ACCEPT [class=accept_line] 48 | Node2 -- f2 -> f3 -> INPUT_DROP [class=reject_line] 49 | Node3 -- f4 -> f5 -> INPUT_DROP [class=reject_line] 50 | Node4 -- f6 -> f7 -> INPUT_DROP [class=reject_line] 51 | Node5 -- f8 -> INPUT_ACCEPT [class=accept_line] 52 | Node6 -- f9 -> INPUT_log_invalid 53 | Node7 -- f10 -> INPUT_log_invalid 54 | Node8 -- f11 -> INPUT_log_invalid 55 | Node9 -- f12 -> INPUT_log_invalid 56 | Node10 -- f13 -> INPUT_log_invalid 57 | Node11 -- f14 -> INPUT_log_invalid 58 | INPUT_ACCEPT [class=accept] 59 | INPUT_log_invalid [class=target, class="log_invalid", label="log_invalid"] 60 | INPUT_DROP [class=drop] 61 | } 62 | group { 63 | orientation=portrait 64 | shape=line; style=none 65 | group { 66 | orientation=portrait 67 | shape=line; style=none 68 | Node12 [class=rule, label="out:lo src:localhost dst:localhost"] 69 | OUTPUT -> Node12 70 | Node13 [class=rule, label="out:tun0"] 71 | Node12 -> Node13 72 | Node14 [class=rule, label="icmp state NEW,ESTABLISHED icmp echo-request"] 73 | Node13 -> Node14 74 | Node15 [class=rule, label="icmp state NEW,ESTABLISHED"] 75 | Node14 -> Node15 76 | Node16 [class=rule, label="*"] 77 | Node15 -> Node16 78 | OUTPUT [class=chain_head, shape=box] 79 | Node16 -- OUTPUT_END -> OUTPUT_ACCEPT 80 | OUTPUT_END [shape=none] 81 | } 82 | Node12 -- f15 -> f16 -> OUTPUT_ACCEPT [class=accept_line] 83 | Node13 -- f17 -> f18 -> OUTPUT_ACCEPT [class=accept_line] 84 | Node14 -- f19 -> f20 -> OUTPUT_ACCEPT [class=accept_line] 85 | Node15 -- f21 -> f22 -> OUTPUT_ACCEPT [class=accept_line] 86 | Node16 -- f23 -> f24 -> OUTPUT_ACCEPT [class=accept_line] 87 | OUTPUT_ACCEPT [class=accept] 88 | } 89 | group { 90 | orientation=portrait 91 | shape=line; style=none 92 | group { 93 | orientation=portrait 94 | shape=line; style=none 95 | Node17 [class=rule, label="*"] 96 | log_invalid -> Node17 97 | Node18 [class=rule, label="*"] 98 | Node17 -> Node18 99 | log_invalid [class=chain_head] 100 | } 101 | Node17 -- f25 -> log_invalid_LOG 102 | Node18 -- f26 -> log_invalid_DROP [class=reject_line] 103 | log_invalid_LOG [class=target, class="LOG", label="LOG"] 104 | log_invalid_DROP [class=drop] 105 | } 106 | class chain_head [shape=ellipse] 107 | class rule [shape=diamond, width=200] 108 | class target [width=150] 109 | class reject [color = "red", label="REJECT"] 110 | class reject_line [color = "red"] 111 | class drop [color = "red", label="DROP"] 112 | class return [color = "#1ab3ff", label="RETURN"] 113 | class return_line [color = "blue"] 114 | class accept [color = "lightgreen", label="ACCEPT"] 115 | class accept_line [color = "green"] 116 | class fake [shape=none, width=1] 117 | f0 [class=fake] 118 | f1 [class=fake] 119 | f2 [class=fake] 120 | f3 [class=fake] 121 | f4 [class=fake] 122 | f5 [class=fake] 123 | f6 [class=fake] 124 | f7 [class=fake] 125 | f8 [class=fake] 126 | f9 [class=fake] 127 | f10 [class=fake] 128 | f11 [class=fake] 129 | f12 [class=fake] 130 | f13 [class=fake] 131 | f14 [class=fake] 132 | f15 [class=fake] 133 | f16 [class=fake] 134 | f17 [class=fake] 135 | f18 [class=fake] 136 | f19 [class=fake] 137 | f20 [class=fake] 138 | f21 [class=fake] 139 | f22 [class=fake] 140 | f23 [class=fake] 141 | f24 [class=fake] 142 | f25 [class=fake] 143 | f26 [class=fake] 144 | f27 [class=fake] 145 | class ACCEPT [shape=box] 146 | class ACCEPT [shape=box] 147 | class LOG [shape=box] 148 | class log_invalid [shape=ellipse, linecolor=black] 149 | class DROP [shape=box] 150 | class log_invalid [shape=ellipse, linecolor=black] 151 | class log_invalid [shape=ellipse, linecolor=black] 152 | class log_invalid [shape=ellipse, linecolor=black] 153 | class log_invalid [shape=ellipse, linecolor=black] 154 | class log_invalid [shape=ellipse, linecolor=black] 155 | class ACCEPT [shape=box] 156 | class ACCEPT [shape=box] 157 | class ACCEPT [shape=box] 158 | class ACCEPT [shape=box] 159 | class DROP [shape=box] 160 | class ACCEPT [shape=box] 161 | class DROP [shape=box] 162 | class ACCEPT [shape=box] 163 | class DROP [shape=box] 164 | } 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | in:lo src:localhos 196 | t dst:localhost 197 | 198 | INPUT 199 | 200 | in:tun0 201 | 202 | tcp tcp flags:!FIN 203 | ,SYN,RST,ACK/S ... 204 | 205 | state log_INVALID 206 | 207 | icmp state NEW 208 | 209 | icmp state ESTABLI 210 | SHED 211 | 212 | tcp tcp flags:FIN, 213 | SYN,RST,PSH,AC ... 214 | 215 | tcp tcp flags:FIN, 216 | SYN/FIN,SYN 217 | 218 | tcp tcp flags:SYN, 219 | RST/SYN,RST 220 | 221 | tcp tcp flags:FIN, 222 | RST/FIN,RST 223 | 224 | tcp tcp flags:FIN, 225 | ACK/FIN 226 | 227 | tcp tcp flags:ACK, 228 | URG/URG 229 | 230 | DROP 231 | 232 | ACCEPT 233 | 234 | log_invalid 235 | 236 | out:lo src:localho 237 | st dst:localhost 238 | 239 | OUTPUT 240 | 241 | out:tun0 242 | 243 | icmp state NEW,EST 244 | ABLISHED icmp ... 245 | 246 | icmp state NEW,EST 247 | ABLISHED 248 | 249 | * 250 | 251 | ACCEPT 252 | 253 | * 254 | 255 | log_invalid 256 | 257 | * 258 | 259 | LOG 260 | 261 | DROP 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 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 | 4 | 5 | 6 | 7 | 8 | 9 | blockdiag 10 | blockdiag { 11 | node_width = 200; 12 | INPUT [class=chain_head, shape=box] 13 | Node0 [class=rule, label="Rule"] 14 | group { 15 | shape=line 16 | style=none 17 | Node0 [class=rule, label="in:eth0 tcp"] 18 | f0 [style=none, label="Rule that matches tcp pakages from eth0", fontsize=14] 19 | Node0 -> f0 [style=none] 20 | } group { 21 | shape=line 22 | style=none 23 | Node1 [class=rule, label="*"] 24 | f1 [style=none, label="Rule that always matches", fontsize=14] 25 | Node1 -> f1 [style=none] 26 | } 27 | ACCEPT [class=accept] 28 | DROP [class=drop] 29 | RETURN [class=return] 30 | AUDIT [class=target] 31 | chain [class=target, class="chain", label="user defined chain"] 32 | empty_chain [class=target, class="empty_chain", label="empty chain"] 33 | class chain_head [shape=ellipse] 34 | class rule [shape=diamond, width=200] 35 | class target [width=150] 36 | class reject [color = "red", label="REJECT"] 37 | class reject_line [color = "red"] 38 | class drop [color = "red", label="DROP"] 39 | class return [color = "#1ab3ff", label="RETURN"] 40 | class return_line [color = "blue"] 41 | class accept [color = "lightgreen", label="ACCEPT"] 42 | class accept_line [color = "green"] 43 | class fake [shape=none, width=1] 44 | class ACCEPT [shape=box] 45 | class LOG [shape=box] 46 | class chain [shape=ellipse] 47 | class empty_chain [shape=ellipse, style=dotted, linecolor="#444", textcolor="#444"] 48 | } 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | INPUT 63 | 64 | in:eth0 tcp 65 | 66 | Rule that matches tcp paka 67 | ges from eth0 68 | 69 | * 70 | 71 | Rule that always matches 72 | 73 | ACCEPT 74 | 75 | DROP 76 | 77 | RETURN 78 | 79 | AUDIT 80 | 81 | user defined chain 82 | 83 | empty chain 84 | 85 | 86 | 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 | --------------------------------------------------------------------------------