summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Vyatta/NatRule.pm168
-rwxr-xr-xscripts/vyatta-update-nat.pl84
-rw-r--r--templates-cfg/service/nat/rule/node.tag/log/node.def3
3 files changed, 168 insertions, 87 deletions
diff --git a/lib/Vyatta/NatRule.pm b/lib/Vyatta/NatRule.pm
index 84b0b2e..79afb26 100644
--- a/lib/Vyatta/NatRule.pm
+++ b/lib/Vyatta/NatRule.pm
@@ -11,12 +11,14 @@ my $src = new Vyatta::IpTables::AddressFilter;
my $dst = new Vyatta::IpTables::AddressFilter;
my %fields = (
+ _rule_number => undef,
_type => undef,
_orig_type => undef,
_inbound_if => undef,
_outbound_if => undef,
_proto => undef,
_exclude => undef,
+ _log => undef,
_inside_addr => {
_addr => undef,
_range => {
@@ -51,13 +53,15 @@ sub setup {
my $config = new Vyatta::Config;
$config->setLevel("$level");
-
+
+ $self->{_rule_number} = $config->returnParent("..");
$self->{_type} = $config->returnValue("type");
$self->{_orig_type} = $config->returnOrigValue("type");
$self->{_inbound_if} = $config->returnValue("inbound-interface");
$self->{_outbound_if} = $config->returnValue("outbound-interface");
$self->{_proto} = $config->returnValue("protocol");
$self->{_exclude} = $config->exists("exclude");
+ $self->{_log} = $config->returnValue("log");
$self->{_inside_addr}->{_addr}
= $config->returnValue("inside-address address");
@@ -97,12 +101,14 @@ sub setupOrig {
$config->setLevel("$level");
+ $self->{_rule_number} = $config->returnParent("..");
$self->{_type} = $config->returnOrigValue("type");
$self->{_orig_type} = $config->returnOrigValue("type");
$self->{_inbound_if} = $config->returnOrigValue("inbound-interface");
$self->{_outbound_if} = $config->returnOrigValue("outbound-interface");
$self->{_proto} = $config->returnOrigValue("protocol");
$self->{_exclude} = $config->existsOrig("exclude");
+ $self->{_log} = $config->returnOrigValue("log");
$self->{_inside_addr}->{_addr}
= $config->returnOrigValue("inside-address address");
@@ -136,11 +142,42 @@ sub setupOrig {
return 0;
}
-# returns (rule, error)
+sub get_num_ipt_rules {
+ my $self = shift;
+ my $ipt_rules = 1;
+ if ("$self->{_log}" eq 'enable') {
+ $ipt_rules++;
+ }
+ return $ipt_rules;
+}
+
+my %nat_type_hash = (
+ 'SNAT' => 'SNAT',
+ 'DNAT' => 'DNAT',
+ 'MASQUERADE' => 'MASQ',
+ 'RETURN' => 'EXCLUDE',
+ 'NETMAP' => 'NETMAP',
+);
+
+sub get_log_prefix {
+ my ($rule_num, $jump_target) = @_;
+
+ # In iptables it allows a 29 character log_prefix, but we ideally
+ # want to include "[nat-type-$rule_num] "
+ # 1 3 1 7 1 4 1 1 = 19
+ # so no truncation is needed.
+ my $nat_type = $nat_type_hash{$jump_target};
+ my $log_prefix = "[NAT-$rule_num-$nat_type] ";
+ return $log_prefix;
+}
+
+# returns (error, @rules)
sub rule_str {
my ($self) = @_;
my $rule_str = "";
my $can_use_port = 1;
+ my $jump_target = '';
+ my $jump_param = '';
if (!defined($self->{_proto}) ||
(($self->{_proto} ne "tcp") && ($self->{_proto} ne "6")
@@ -148,18 +185,18 @@ sub rule_str {
$can_use_port = 0;
}
if (($self->{_type} eq "source") || ($self->{_type} eq "masquerade")) {
- return (undef, 'cannot specify inbound interface with '
- . '"masquerade" or "source" rules')
+ return ('cannot specify inbound interface with '
+ . '"masquerade" or "source" rules', undef)
if (defined($self->{_inbound_if}));
my $use_netmap = 0;
if ($self->{_exclude}) {
- $rule_str .= "-j RETURN";
+ $jump_target = 'RETURN';
} elsif ($self->{_type} eq "masquerade") {
- $rule_str .= "-j MASQUERADE";
+ $jump_target = 'MASQUERADE';
} else {
- $rule_str .= "-j SNAT";
+ $jump_target = 'SNAT';
}
if (defined($self->{_outbound_if})) {
$rule_str .= " -o $self->{_outbound_if}";
@@ -167,7 +204,7 @@ sub rule_str {
# "masquerade" requires outbound_if.
# also make this a requirement for "source" to prevent users from
# inadvertently NATing loopback traffic.
- return (undef, "outbound-interface not specified");
+ return ('outbound-interface not specified', undef);
}
if (defined($self->{_proto})) {
@@ -180,12 +217,12 @@ sub rule_str {
if (defined($self->{_outside_addr}->{_addr})) {
my $addr = $self->{_outside_addr}->{_addr};
if ($addr =~ m/\//) {
- return (undef, "\"$addr\" is not a valid IPv4net address")
+ return ("\"$addr\" is not a valid IPv4net address", undef)
if (!Vyatta::TypeChecker::validateType('ipv4net', $addr, 1));
$to_src .= $addr;
$use_netmap = 1;
} else {
- return (undef, "\"$addr\" is not a valid IP address")
+ return ("\"$addr\" is not a valid IP address", undef)
if (!Vyatta::TypeChecker::validateType('ipv4', $addr, 1));
$to_src .= $addr;
}
@@ -193,24 +230,25 @@ sub rule_str {
&& defined($self->{_outside_addr}->{_range}->{_stop})) {
my $start = $self->{_outside_addr}->{_range}->{_start};
my $stop = $self->{_outside_addr}->{_range}->{_stop};
- return (undef, "\"$start-$stop\" is not a valid IP range")
+ return ("\"$start-$stop\" is not a valid IP range", undef)
if (!Vyatta::TypeChecker::validateType('ipv4', $start, 1)
|| !Vyatta::TypeChecker::validateType('ipv4', $stop, 1));
$to_src .= "$start-$stop";
}
if (($to_src ne "") && ($self->{_type} eq "masquerade")) {
- return (undef, "cannot specify outside IP address with \"masquerade\"");
+ return ("cannot specify outside IP address with \"masquerade\"", undef);
}
if (defined($self->{_outside_addr}->{_port})) {
if (!$can_use_port) {
- return (undef, "ports can only be specified when protocol is \"tcp\" "
- . "or \"udp\" (currently \"$self->{_proto}\")");
+ return ("ports can only be specified when protocol is \"tcp\" "
+ . "or \"udp\" (currently \"$self->{_proto}\")", undef);
}
if ($use_netmap) {
- return (undef, "Cannot use ports with an IPv4net type outside-address as it
-statically maps a whole network of addresses onto another network of addresses");
+ return ("Cannot use ports with an IPv4net type outside-address as it " .
+ "statically maps a whole network of addresses onto another " .
+ "network of addresses", undef);
}
if ($self->{_type} ne "masquerade") {
$to_src .= ":";
@@ -220,15 +258,14 @@ statically maps a whole network of addresses onto another network of addresses")
if ($port =~ /-/) {
($success, $err)
= Vyatta::Misc::isValidPortRange($port, '-');
- return (undef, $err) if (!defined($success));
+ return ($err, undef) if (!defined($success));
} elsif ($port =~ /^\d/) {
($success, $err)
= Vyatta::Misc::isValidPortNumber($port);
- return (undef, $err) if (!defined($success));
+ return ($err, undef) if (!defined($success));
} else {
- ($success, $err)
- = Vyatta::Misc::isValidPortName($port);
- return (undef, $err) if (!defined($success));
+ ($success, $err) = Vyatta::Misc::isValidPortName($port);
+ return ($err, undef) if !defined $success ;
$port = getservbyname($port, $self->{_proto});
}
$to_src .= "$port";
@@ -238,31 +275,30 @@ statically maps a whole network of addresses onto another network of addresses")
# outside-address has no effect for "exclude" rules
} elsif ($to_src ne '') {
if ($self->{_type} eq "masquerade") {
- $rule_str .= " --to-ports $to_src";
+ $jump_param .= " --to-ports $to_src";
} else {
if ($use_netmap) {
# replace "SNAT" with "NETMAP"
- $rule_str =~ s/SNAT/NETMAP/;
- $rule_str .= " --to $to_src";
+ $jump_target = 'NETMAP';
+ $jump_param .= " --to $to_src";
} else {
- $rule_str .= " --to-source $to_src";
+ $jump_param .= " --to-source $to_src";
}
}
} elsif ($self->{_type} ne "masquerade") {
- return (undef, "outside-address not specified");
+ return ('outside-address not specified', undef);
}
} elsif ($self->{_type} eq "destination") {
# type is destination
- return (undef,
- 'cannot specify outbound interface with "destination" rules')
- if (defined($self->{_outbound_if}));
+ return ('cannot specify outbound interface with "destination" rules', undef)
+ if (defined($self->{_outbound_if}));
my $use_netmap = 0;
if ($self->{_exclude}) {
- $rule_str .= "-j RETURN";
+ $jump_target = 'RETURN';
} else {
- $rule_str .= "-j DNAT";
+ $jump_target = 'DNAT';
}
if (defined($self->{_inbound_if})) {
@@ -270,7 +306,7 @@ statically maps a whole network of addresses onto another network of addresses")
} else {
# make this a requirement to prevent users from
# inadvertently NATing loopback traffic.
- return (undef, "inbound-interface not specified");
+ return ('inbound-interface not specified', undef);
}
if (defined($self->{_proto})) {
@@ -281,14 +317,14 @@ statically maps a whole network of addresses onto another network of addresses")
if (defined($self->{_inside_addr}->{_addr})) {
my $addr = $self->{_inside_addr}->{_addr};
if ($addr =~ m/\//) {
- return (undef, "\"$addr\" is not a valid IPv4net address")
+ return ("\"$addr\" is not a valid IPv4net address", undef)
if (!Vyatta::TypeChecker::validateType('ipv4net', $addr, 1));
$to_dst = " --to ";
$to_dst .= $addr;
$use_netmap = 1;
} else {
- return (undef, "\"$addr\" is not a valid IP address")
- if (!Vyatta::TypeChecker::validateType('ipv4', $addr, 1));
+ return ("\"$addr\" is not a valid IP address", undef)
+ if (!Vyatta::TypeChecker::validateType('ipv4', $addr, 1));
$to_dst = " --to-destination ";
$to_dst .= $addr;
}
@@ -296,7 +332,7 @@ statically maps a whole network of addresses onto another network of addresses")
&& defined($self->{_inside_addr}->{_range}->{_stop})) {
my $start = $self->{_inside_addr}->{_range}->{_start};
my $stop = $self->{_inside_addr}->{_range}->{_stop};
- return (undef, "\"$start-$stop\" is not a valid IP range")
+ return ("\"$start-$stop\" is not a valid IP range", undef)
if (!Vyatta::TypeChecker::validateType('ipv4', $start, 1)
|| !Vyatta::TypeChecker::validateType('ipv4', $stop, 1));
$to_dst = " --to-destination ";
@@ -305,27 +341,25 @@ statically maps a whole network of addresses onto another network of addresses")
if (defined($self->{_inside_addr}->{_port})) {
if (!$can_use_port) {
- return (undef, "ports can only be specified when protocol is \"tcp\" "
- . "or \"udp\" (currently \"$self->{_proto}\")");
+ return ("ports can only be specified when protocol is \"tcp\" "
+ . "or \"udp\" (currently \"$self->{_proto}\")", undef);
}
if ($use_netmap) {
- return (undef, "Cannot use ports with an IPv4net type outside-address as it
-statically maps a whole network of addresses onto another network of addresses");
+ return ("Cannot use ports with an IPv4net type outside-address as it "
+ . "statically maps a whole network of addresses onto another "
+ . "network of addresses", undef);
}
my ($success, $err) = (undef, undef);
my $port = $self->{_inside_addr}->{_port};
if ($port =~ /-/) {
- ($success, $err)
- = Vyatta::Misc::isValidPortRange($port, '-');
- return (undef, $err) if (!defined($success));
+ ($success, $err) = Vyatta::Misc::isValidPortRange($port, '-');
+ return ($err, undef) if (!defined($success));
} elsif ($port =~ /^\d/) {
- ($success, $err)
- = Vyatta::Misc::isValidPortNumber($port);
- return (undef, $err) if (!defined($success));
+ ($success, $err) = Vyatta::Misc::isValidPortNumber($port);
+ return ($err, undef) if (!defined($success));
} else {
- ($success, $err)
- = Vyatta::Misc::isValidPortName($port);
- return (undef, $err) if (!defined($success));
+ ($success, $err) = Vyatta::Misc::isValidPortName($port);
+ return ($err, undef) if (!defined($success));
$port = getservbyname($port, $self->{_proto});
}
$to_dst .= ":$port";
@@ -336,35 +370,44 @@ statically maps a whole network of addresses onto another network of addresses")
} elsif ($to_dst ne "") {
if ($use_netmap) {
# replace "DNAT" with "NETMAP"
- $rule_str =~ s/DNAT/NETMAP/;
- $rule_str .= " $to_dst";
+ $jump_target = 'NETMAP';
+ $jump_param .= " $to_dst";
} else {
- $rule_str .= " $to_dst";
+ $jump_param .= " $to_dst";
}
} else {
- return (undef, "inside-address not specified");
+ return ("inside-address not specified", undef);
}
} else {
- return (undef, "rule type not specified/valid");
+ return ("rule type not specified/valid", undef);
}
# source rule string
my ($src_str, $src_err) = $src->rule();
- return (undef, $src_err) if (!defined($src_str));
+ return ($src_err, undef) if (!defined($src_str));
# destination rule string
my ($dst_str, $dst_err) = $dst->rule();
- return (undef, $dst_err) if (!defined($dst_str));
+ return ($dst_err, undef) if (!defined($dst_str));
if ((grep /multiport/, $src_str) || (grep /multiport/, $dst_str)) {
if ((grep /sport/, $src_str) && (grep /dport/, $dst_str)) {
- return (undef, 'cannot specify multiple ports when both '
- . 'source and destination ports are specified');
+ return ('cannot specify multiple ports when both source and destination '
+ . 'ports are specified', undef);
}
}
$rule_str .= " $src_str $dst_str";
-
- return ($rule_str, undef);
+ if ("$self->{_log}" eq "enable") {
+ my $log_rule = $rule_str;
+ my $rule_num = $self->{_rule_number};
+ my $log_prefix = get_log_prefix($rule_num, $jump_target);
+ $log_rule .= " -j LOG --log-prefix \"$log_prefix\" ";
+ $rule_str .= " -j $jump_target $jump_param";
+ return (undef, $log_rule, $rule_str);
+ } else {
+ $rule_str .= " -j $jump_target $jump_param";
+ return (undef, $rule_str);
+ }
}
sub orig_type {
@@ -427,3 +470,8 @@ sub outputXml {
1;
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 2
+# End:
diff --git a/scripts/vyatta-update-nat.pl b/scripts/vyatta-update-nat.pl
index 4e31fa6..6eeb924 100755
--- a/scripts/vyatta-update-nat.pl
+++ b/scripts/vyatta-update-nat.pl
@@ -28,7 +28,12 @@ my $config = new Vyatta::Config;
$config->setLevel("service nat rule");
my %rules = $config->listNodeStatus();
my $rule;
-open(OUT, ">>/dev/null") or exit 1;
+my $debug = 0;
+if ($debug) {
+ open(OUT, ">>/tmp/nat") or exit 1;
+} else {
+ open(OUT, ">>/dev/null") or exit 1;
+}
my %ipt_rulenum = (
source => 2,
destination => 1,
@@ -65,6 +70,8 @@ if ($? >> 8) {
my $all_deleted = 1;
for $rule (@rule_keys) {
print OUT "$rule: $rules{$rule}\n";
+ my $tmp = `iptables -L -nv --line -t nat`;
+ print OUT "iptables before:\n$tmp\n";
my $nrule = new Vyatta::NatRule;
$nrule->setup("service nat rule $rule");
my $otype = $nrule->orig_type();
@@ -84,23 +91,29 @@ for $rule (@rule_keys) {
if (!defined($ntype)) {
exit 3;
}
- $ipt_rulenum{$ntype} += 1;
+ my $ipt_rules = $nrule->get_num_ipt_rules();
+ $ipt_rulenum{$ntype} += $ipt_rules;
next;
} elsif ($rules{$rule} eq "deleted") {
# $ntype should be empty
if (!defined($otype)) {
exit 4;
}
- $cmd = "iptables -t nat -D $chain_name{$otype} $ipt_rulenum{$otype}";
- print OUT "$cmd\n";
- if (system($cmd)) {
- exit 1;
+ my $orule = new Vyatta::NatRule;
+ $orule->setupOrig("service nat rule $rule");
+ my $ipt_rules = $orule->get_num_ipt_rules();
+ for (1 .. $ipt_rules) {
+ $cmd = "iptables -t nat -D $chain_name{$otype} $ipt_rulenum{$otype}";
+ print OUT "$cmd\n";
+ if (system($cmd)) {
+ exit 1;
+ }
}
next;
}
- my ($str, $err) = $nrule->rule_str();
- if (!defined($str)) {
+ my ($err, @rule_strs) = $nrule->rule_str();
+ if (defined $err) {
# rule check failed => return error
print OUT "NAT configuration error: $err\n";
print STDERR "NAT configuration error: $err\n";
@@ -112,34 +125,46 @@ for $rule (@rule_keys) {
if (!defined($ntype)) {
exit 6;
}
- $cmd = "iptables -t nat -I $chain_name{$ntype} $ipt_rulenum{$ntype} " .
- "$str";
- print OUT "$cmd\n";
- if (system($cmd)) {
- exit 1;
+ foreach my $rule_str (@rule_strs) {
+ $cmd = "iptables -t nat -I $chain_name{$ntype} $ipt_rulenum{$ntype} " .
+ "$rule_str";
+ print OUT "$cmd\n";
+ if (system($cmd)) {
+ exit 1;
+ }
+ $ipt_rulenum{$ntype}++;
}
- $ipt_rulenum{$ntype} += 1;
+
} elsif ($rules{$rule} eq "changed") {
# $otype and $ntype may not be the same
if (!defined($otype) || !defined($ntype)) {
exit 7;
}
- $cmd = "iptables -t nat -I $chain_name{$ntype} $ipt_rulenum{$ntype} " .
- "$str";
- print OUT "$cmd\n";
- if (system($cmd)) {
- exit 1;
- }
+
+ # delete the old rule(s)
+ my $orule = new Vyatta::NatRule;
+ $orule->setupOrig("service nat rule $rule");
+ my $ipt_rules = $orule->get_num_ipt_rules();
my $idx = $ipt_rulenum{$otype};
- if ($otype eq $ntype) {
- $idx += 1;
+ for (1 .. $ipt_rules) {
+ $cmd = "iptables -t nat -D $chain_name{$otype} $idx";
+ print OUT "$cmd\n";
+ if (system($cmd)) {
+ exit 1;
+ }
}
- $cmd = "iptables -t nat -D $chain_name{$otype} $idx";
- print OUT "$cmd\n";
- if (system($cmd)) {
- exit 1;
+
+ # add the new rule(s)
+ foreach my $rule_str (@rule_strs) {
+ $cmd = "iptables -t nat -I $chain_name{$ntype} $ipt_rulenum{$ntype} " .
+ "$rule_str";
+ print OUT "$cmd\n";
+ if (system($cmd)) {
+ exit 1;
+ }
+ $ipt_rulenum{$ntype}++;
}
- $ipt_rulenum{$ntype} += 1;
+
}
}
@@ -150,3 +175,8 @@ if ($all_deleted) {
close OUT;
exit 0;
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 2
+# End:
diff --git a/templates-cfg/service/nat/rule/node.tag/log/node.def b/templates-cfg/service/nat/rule/node.tag/log/node.def
new file mode 100644
index 0000000..0d53569
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/log/node.def
@@ -0,0 +1,3 @@
+type: txt
+help: Set NAT rule logging
+syntax:expression: $VAR(@) in "enable", "disable"; "NAT logging must be enable or disable"