diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | scripts/VyattaIpTablesAddressFilter.pm | 186 |
2 files changed, 187 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index ef5aece..ef92de7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,6 +47,7 @@ share_perl5_DATA += scripts/VyattaConfigOutput.pm share_perl5_DATA += scripts/VyattaConfigLoad.pm share_perl5_DATA += scripts/VyattaMisc.pm share_perl5_DATA += scripts/VyattaTypeChecker.pm +share_perl5_DATA += scripts/VyattaIpTablesAddressFilter.pm default_DATA = etc/default/vyatta-cfg diff --git a/scripts/VyattaIpTablesAddressFilter.pm b/scripts/VyattaIpTablesAddressFilter.pm new file mode 100644 index 0000000..aa6f662 --- /dev/null +++ b/scripts/VyattaIpTablesAddressFilter.pm @@ -0,0 +1,186 @@ +package VyattaIpTablesAddressFilter; + +use VyattaConfig; +use VyattaMisc; +use VyattaTypeChecker; + +my %_protocolswithports = ( + tcp => 1, + udp => 1, + 6 => 1, + 17 => 1, +); + +my %fields = ( + _srcdst => undef, + _range_start => undef, + _range_stop => undef, + _network => undef, + _address => undef, + _port => undef, + _protocol => undef, + _src_mac => undef, +); + +sub new { + my $that = shift; + my $class = ref ($that) || $that; + my $self = { + %fields, + }; + + bless $self, $class; + return $self; +} + +sub setup { + my ($self, $level) = @_; + my $config = new VyattaConfig; + + $config->setLevel("$level"); + + # setup needed parent nodes + $self->{_srcdst} = $config->returnParent(".."); + $self->{_protocol} = $config->returnValue(".. protocol"); + + # setup address filter nodes + $self->{_address} = $config->returnValue("address"); + $self->{_network} = undef; + $self->{_range_start} = undef; + $self->{_range_stop} = undef; + if (defined($self->{_address})) { + if ($self->{_address} =~ /\//) { + $self->{_network} = $self->{_address}; + $self->{_address} = undef; + } elsif ($self->{_address} =~ /^([^-]+)-([^-]+)$/) { + $self->{_range_start} = $1; + $self->{_range_stop} = $2; + $self->{_address} = undef; + } + } + + $self->{_port} = $config->returnValue("port"); + $self->{_src_mac} = $config->returnValue("mac-address"); + + return 0; +} + +sub setupOrig { + my ($self, $level) = @_; + my $config = new VyattaConfig; + + $config->setLevel("$level"); + + # setup needed parent nodes + $self->{_srcdst} = $config->returnParent(".."); + $self->{_protocol} = $config->returnOrigValue(".. protocol"); + + # setup address filter nodes + $self->{_address} = $config->returnOrigValue("address"); + $self->{_network} = undef; + $self->{_range_start} = undef; + $self->{_range_stop} = undef; + if (defined($self->{_address})) { + if ($self->{_address} =~ /\//) { + $self->{_network} = $self->{_address}; + $self->{_address} = undef; + } elsif ($self->{_address} =~ /^([^-]+)-([^-]+)$/) { + $self->{_range_start} = $1; + $self->{_range_stop} = $2; + $self->{_address} = undef; + } + } + + $self->{_port} = $config->returnOrigValue("port"); + $self->{_src_mac} = $config->returnValue("mac-address"); + + return 0; +} + +sub print { + my ($self) = @_; + + print "srcdst: $self->{_srcdst}\n" if defined $self->{_srcdst}; + print "range start: $self->{_range_start}\n" if defined $self->{_range_start}; + print "range stop: $self->{_range_stop}\n" if defined $self->{_range_stop}; + print "network: $self->{_network}\n" if defined $self->{_network}; + print "address: $self->{_address}\n" if defined $self->{_address}; + print "port: $self->{_port}\n" if defined $self->{_port}; + print "protocol: $self->{_protocol}\n" if defined $self->{_protocol}; + print "src-mac: $self->{_src_mac}\n" if defined $self->{_src_mac}; + + return 0; +} + +sub rule { + my ($self) = @_; + my $rule = ""; + my $can_use_port = 1; + + if (!defined($self->{_protocol}) + || !defined($_protocolswithports{$self->{_protocol}})) { + $can_use_port = 0; + } + + if (($self->{_srcdst} eq "source") && (defined($self->{_src_mac}))) { + # handle src mac + my $str = $self->{_src_mac}; + $str =~ s/^\!(.*)$/! $1/; + $rule .= "-m mac --mac-source $str "; + } + + # set the address filter parameters + if (defined($self->{_network})) { + my $str = $self->{_network}; + return (undef, "\"$str\" is not a valid IP subnet") + if (!VyattaTypeChecker::validateType('ipv4net_negate', $str, 1)); + $str =~ s/^\!(.*)$/! $1/; + $rule .= "--$self->{_srcdst} $str "; + } elsif (defined($self->{_address})) { + my $str = $self->{_address}; + return (undef, "\"$str\" is not a valid IP address") + if (!VyattaTypeChecker::validateType('ipv4_negate', $str, 1)); + $str =~ s/^\!(.*)$/! $1/; + $rule .= "--$self->{_srcdst} $str "; + } elsif ((defined $self->{_range_start}) && (defined $self->{_range_stop})) { + my $start = $self->{_range_start}; + my $stop = $self->{_range_stop}; + return (undef, "\"$start-$stop\" is not a valid IP range") + if (!VyattaTypeChecker::validateType('ipv4_negate', $start, 1) + || !VyattaTypeChecker::validateType('ipv4', $stop, 1)); + my $negate = ''; + if ($self->{_range_start} =~ /^!(.*)$/) { + $start = $1; + $negate = '! ' + } + if ("$self->{_srcdst}" eq "source") { + $rule .= ("-m iprange $negate--src-range $start-$self->{_range_stop} "); + } + elsif ("$self->{_srcdst}" eq "destination") { + $rule .= ("-m iprange $negate--dst-range $start-$self->{_range_stop} "); + } + } + + my ($port_str, $port_err) + = VyattaMisc::getPortRuleString($self->{_port}, $can_use_port, + ($self->{_srcdst} eq "source") ? "s" : "d", + $self->{_protocol}); + return (undef, $port_err) if (!defined($port_str)); + $rule .= $port_str; + return ($rule, undef); +} + +sub outputXmlElem { + my ($name, $value, $fh) = @_; + print $fh " <$name>$value</$name>\n"; +} + +sub outputXml { + my ($self, $prefix, $fh) = @_; + outputXmlElem("${prefix}_addr", $self->{_address}, $fh); + outputXmlElem("${prefix}_net", $self->{_network}, $fh); + outputXmlElem("${prefix}_addr_start", $self->{_range_start}, $fh); + outputXmlElem("${prefix}_addr_stop", $self->{_range_stop}, $fh); + outputXmlElem("${prefix}_port", $self->{_port}, $fh); +} + |