4 # Canonicalize ferm output. You can use this script to check whether
5 # the output from two ferm versions are functionally identical. This
6 # is used in the compatibility tests.
8 # Author: Max Kellermann (max@duempel.org)
15 $token =~ s/^(["'])(.*)\1/$2/s;
22 next if /^\s*(?:#.*)?$/s;
24 # workaround: not supported in ipchains
26 if /cannot set the policy for non-built in chains, exiting|Cannot create new chains if using ipfwadm|Ipfwadm allows only accept, masq, deny and reject targets/;
31 if (s/^(ip6?)tables //) {
38 s/-t (\w+)/$table = $1; ''/eg;
40 unless defined $table;
42 # get command and chain
43 my ($command, $chain);
45 if (s/-P (\w+) (\w+)//g) {
47 delete $data->{iptables
}{$table}{$1}{policy
}
48 if exists $data->{iptables
}{$table}
49 and exists $data->{iptables
}{$table}{$1};
51 $data->{iptables
}{$table}{$1}{policy
} = $2;
56 s/-([ALFZNXE])(?: ([-\w]+))?/($command, $chain) = ($1, $2); ''/eg;
58 next if $command eq 'F' or $command eq 'X';
60 if ($command eq 'N') {
62 push @
{$data->{iptables
}{$table}{$chain}{rules
}}, $command;
64 push @
{$data->{iptables
}{$table}{rules
}}, $command;
69 die 'no chain specified'
70 unless defined $chain;
74 s/-m (\w+)/$modules{$1} = 1; ''/eg;
75 $item->{modules
} = [ grep { not /^(?:tcp|udp|icmp)$/ } keys %modules ];
80 s/-i\b/--in-interface/g;
81 s/-o\b/--out-interface/g;
83 s/-d\b/--destination/g;
87 # evaluate options with name collisions
88 s/--set\s+(\w+)\s+([\w,]+)/$item->{ipset_set} = [$1, $2]; ''/eg
89 if exists $modules{set
};
91 # evaluate options with zero, one, two parameters
92 s/(?:(!)\s*)?--(syn|clamp-mss-to-pmtu|set|rcheck|log-tcp-sequence|log-tcp-options|log-ip-options|continue|save-mark|restore-mark|save|restore|fragment|ecn-tcp-cwr|ecn-tcp-ece|physdev-is-(?:in|out|bridged)|strict|next|frag(res|first|more|last)|nodst|random|ssrr|lsrr|no-srr|rr|ts|ra|any-opt|ecn-tcp-remove|ahres|soft|rt-0-res|rt-0-not-strict|ashort|new|rttl|rsource|rdest|utc|localtz)(?:\s|$)/$item->{$2} = $1; ''/eg;
93 s/--(tcp-flags|chunk-types|add-set|del-set)\s+(?:(\!)\s+)?(\S+)\s+(\S+)/$item->{$1} = [ $2, $3, $4 ]; ''/eg;
94 s/(?:(!)\s*)?--(iplimit-above|src-range|dst-range|connlimit-above|connbytes|tos)\s+(\S+)/$item->{$2} = [ $1, $2 ]; ''/eg;
95 s/--(\w[-\w]*)\s+(!)?\s*(".*?"|'.*?'|\S+)/$item->{$1} = (defined $2 ? "$2\t" : "") . shell_unescape($3); ''/eg;
97 # after we parsed everything we know, nothing must be left
98 die "unparsed rest from line $.: $_"
102 push @
{$data->{iptables
}{$table}{$chain}{rules
}}, $item;
103 } elsif (s/^ipchains //) {
106 # get command and chain
107 my ($command, $chain);
109 if (s/-P (\w+) (\w+)//g) {
110 $data->{ipchains
}{$1}{policy
} = $2;
114 s/-([AFZNX])(?: (\w+))?/($command, $chain) = ($1, $2); ''/eg;
116 if ($command eq 'F' or $command eq 'N' or $command eq 'X') {
117 if (defined $chain) {
118 delete $data->{ipchains
}{$chain}{rules
};
120 delete $data->{ipchains
};
125 die 'no chain specified'
126 unless defined $chain;
130 s/-i\b/--interface/g;
131 s/-d\b/--destination/g;
137 # evaluate options with zero, one parameter
138 s/(!\s*)?--(log|syn)\b/$item->{$2} = $1; ''/eg;
139 s
/--(jump
|protocol
|interface
|destination
|source
|protocol
|
140 dport
|destination
-port
|sport
|source
-port
141 )\s
+(".*?"|(?
:!\s
*)?\S
+)/$item->{$1} = $2; ''/egx
;
143 # after we parsed everything we know, nothing must be left
144 die "unparsed rest from line $.: $_"
148 push @
{$data->{ipchains
}{$chain}{rules
}}, $item;
149 } elsif (s/^ipfwadm //) {
154 or die "No chain in line $.";
160 $data->{ipfwadm
}{$chain}{policy
} = $1;
168 s/-([m])/$item->{$1} = 1; ''/eg;
169 s/-([PVW])\s+((?:!\s*)?\S+)/$item->{$1} = $2; ''/egx;
171 # after we parsed everything we know, nothing must be left
172 die "unparsed rest from line $.: $_"
176 push @
{$data->{ipfwadm
}{$chain}{rules
}}, $item;
178 die "syntax error line $.";
183 $Data::Dumper
::Sortkeys
= 1;