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;
75 s/-m (\w+)/$modules{$1} = 1; ''/eg;
76 $item->{modules
} = [ grep { not /^(?:tcp|udp|icmp)$/ } keys %modules ];
81 s/-i\b/--in-interface/g;
82 s/-o\b/--out-interface/g;
84 s/-d\b/--destination/g;
88 # evaluate options with name collisions
89 s/--set\s+(\w+)\s+([\w,]+)/$item->{ipset_set} = [$1, $2]; ''/eg
90 if exists $modules{set
};
92 # evaluate options with zero, one, two parameters
93 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;
94 s/--(tcp-flags|chunk-types|add-set|del-set)\s+(?:(\!)\s+)?(\S+)\s+(\S+)/$item->{$1} = [ $2, $3, $4 ]; ''/eg;
95 s/(?:(!)\s*)?--(iplimit-above|src-range|dst-range|connlimit-above|connbytes|tos)\s+(\S+)/$item->{$2} = [ $1, $2 ]; ''/eg;
96 s/--(\w[-\w]*)\s+(!)?\s*(".*?"|'.*?'|\S+)/$item->{$1} = (defined $2 ? "$2\t" : "") . shell_unescape($3); ''/eg;
98 # after we parsed everything we know, nothing must be left
99 die "unparsed rest from line $.: $_"
103 push @
{$data->{iptables
}{$table}{$chain}{rules
}}, $item;
104 } elsif (s/^ipchains //) {
107 # get command and chain
108 my ($command, $chain);
110 if (s/-P (\w+) (\w+)//g) {
111 $data->{ipchains
}{$1}{policy
} = $2;
115 s/-([AFZNX])(?: (\w+))?/($command, $chain) = ($1, $2); ''/eg;
117 if ($command eq 'F' or $command eq 'N' or $command eq 'X') {
118 if (defined $chain) {
119 delete $data->{ipchains
}{$chain}{rules
};
121 delete $data->{ipchains
};
126 die 'no chain specified'
127 unless defined $chain;
131 s/-i\b/--interface/g;
132 s/-d\b/--destination/g;
138 # evaluate options with zero, one parameter
139 s/(!\s*)?--(log|syn)\b/$item->{$2} = $1; ''/eg;
140 s
/--(jump
|protocol
|interface
|destination
|source
|protocol
|
141 dport
|destination
-port
|sport
|source
-port
142 )\s
+(".*?"|(?
:!\s
*)?\S
+)/$item->{$1} = $2; ''/egx
;
144 # after we parsed everything we know, nothing must be left
145 die "unparsed rest from line $.: $_"
149 push @
{$data->{ipchains
}{$chain}{rules
}}, $item;
150 } elsif (s/^ipfwadm //) {
155 or die "No chain in line $.";
161 $data->{ipfwadm
}{$chain}{policy
} = $1;
169 s/-([m])/$item->{$1} = 1; ''/eg;
170 s/-([PVW])\s+((?:!\s*)?\S+)/$item->{$1} = $2; ''/egx;
172 # after we parsed everything we know, nothing must be left
173 die "unparsed rest from line $.: $_"
177 push @
{$data->{ipfwadm
}{$chain}{rules
}}, $item;
179 die "syntax error line $.";
184 $Data::Dumper
::Sortkeys
= 1;