+
+ my ($action, $iface, $source, $dest, $proto, $dport, $sport);
+
+ $line =~ s/#.*$//;
+
+ my @data = split(/\s+/, $line);
+ my $expected_elements = $need_iface ? 7 : 6;
+
+ die "wrong number of rule elements\n" if scalar(@data) > $expected_elements;
+
+ if ($need_iface) {
+ ($action, $iface, $source, $dest, $proto, $dport, $sport) = @data
+ } else {
+ ($action, $source, $dest, $proto, $dport, $sport) = @data;
+ }
+
+ die "incomplete rule\n" if !$action;
+
+ my $service;
+ if ($action =~ m/^(ACCEPT|DROP|REJECT)$/) {
+ # OK
+ } elsif ($allow_groups && $action =~ m/^GROUP-(:?\S+)$/) {
+ # OK
+ } elsif ($action =~ m/^(\S+)\((ACCEPT|DROP|REJECT)\)$/) {
+ ($service, $action) = ($1, $2);
+ if (!$macros->{$service}) {
+ die "unknown service '$service'\n";
+ }
+ } else {
+ die "unknown action '$action'\n";
+ }
+
+ if ($need_iface) {
+ $iface = undef if $iface && $iface eq '-';
+ die "unknown interface '$iface'\n"
+ if defined($iface) && !$valid_netdev_names->{$iface};
+ }
+
+ $proto = undef if $proto && $proto eq '-';
+ die "unknown protokol '$proto'\n" if $proto &&
+ !(defined($protocols->{byname}->{$proto}) ||
+ defined($protocols->{byid}->{$proto}));
+
+ $source = undef if $source && $source eq '-';
+ $dest = undef if $dest && $dest eq '-';
+
+ $dport = undef if $dport && $dport eq '-';
+ $sport = undef if $sport && $sport eq '-';
+
+ my $nbdport = undef;
+ my $nbsport = undef;
+ my $nbsource = undef;
+ my $nbdest = undef;
+
+ $nbsource = parse_address_list($source) if $source;
+ $nbdest = parse_address_list($dest) if $dest;
+ $nbdport = parse_port_name_number_or_range($dport) if $dport;
+ $nbsport = parse_port_name_number_or_range($sport) if $sport;
+
+ return {
+ action => $action,
+ service => $service,
+ iface => $iface,
+ source => $source,
+ dest => $dest,
+ nbsource => $nbsource,
+ nbdest => $nbdest,
+ proto => $proto,
+ dport => $dport,
+ sport => $sport,
+ nbdport => $nbdport,
+ nbsport => $nbsport,
+ };
+}
+
+sub parse_vm_fw_rules {
+ my ($filename, $fh) = @_;
+
+ my $res = { in => [], out => [] };
+
+ my $section;
+