summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaurav <gaurav.sinha@vyatta.com>2012-03-20 18:47:33 -0700
committerGaurav <gaurav.sinha@vyatta.com>2012-03-20 18:47:33 -0700
commit7330d01fd5ac752e265cf868b3a7f9ef30af9a93 (patch)
treef60b385fa08b035e2fa6f629c98d3f7064263e67
parent613330a8acca0535df5bc1fc839fb29ce1261272 (diff)
parent0f71f18eaec8643d8f78b95bb1657734b3f5b368 (diff)
downloadvyatta-conntrack-7330d01fd5ac752e265cf868b3a7f9ef30af9a93.tar.gz
vyatta-conntrack-7330d01fd5ac752e265cf868b3a7f9ef30af9a93.zip
Merge branch 'cttimeout_pacifica' into oxnard
Brings in the changes needed for connection tracking timeouts per connection. Conflicts: .frlog debian/changelog
-rw-r--r--Makefile.am2
-rw-r--r--lib/Vyatta/Conntrack/RuleCT.pm246
-rw-r--r--scripts/vyatta-conntrack-timeouts.pl174
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/node.def3
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.def9
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/description/node.def3
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/address/node.def10
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/node.def1
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/port/node.def10
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/icmp/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/node.def2
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/other/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/close-wait/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/close/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/established/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/fin-wait/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/last-ack/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/node.def1
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/syn-recv/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/syn-sent/node.def7
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/time-wait/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/node.def1
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/other/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/stream/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/address/node.def8
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/node.def1
-rw-r--r--templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/port/node.def8
27 files changed, 574 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 46e3603..39a08b2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,11 +16,13 @@ checkparamsonreboot_SCRIPTS += scripts/check-params-on-reboot.d/conntrack-hash-s
share_perl5_DATA = lib/Vyatta/Conntrack/Config.pm
share_perl5_DATA += lib/Vyatta/Conntrack/ConntrackUtil.pm
+share_perl5_DATA += lib/Vyatta/Conntrack/RuleCT.pm
sbin_SCRIPTS = scripts/vyatta-update-conntrack-log.pl
bin_sudo_usersdir = $(bindir)/sudo-users
bin_sudo_users_SCRIPTS = scripts/vyatta-show-conntrack.pl
bin_sudo_users_SCRIPTS += scripts/vyatta-delete-conntrack.pl
+bin_sudo_users_SCRIPTS += scripts/vyatta-conntrack-timeouts.pl
curver_DATA = cfg-version/conntrack@1
diff --git a/lib/Vyatta/Conntrack/RuleCT.pm b/lib/Vyatta/Conntrack/RuleCT.pm
new file mode 100644
index 0000000..319edb4
--- /dev/null
+++ b/lib/Vyatta/Conntrack/RuleCT.pm
@@ -0,0 +1,246 @@
+#
+# The timeouts are implemented using nfct-timeout policies that are
+# later applied to the corresponding iptables rules. The rules and
+# policies are distinguished based on the rule number.
+
+package Vyatta::Conntrack::RuleCT;
+
+use strict;
+use Vyatta::Config;
+require Vyatta::IpTables::AddressFilter;
+
+my $src = new Vyatta::IpTables::AddressFilter;
+my $dst = new Vyatta::IpTables::AddressFilter;
+my %fields = (
+ _rule_number => undef,
+ _protocol => undef,
+ _tcp => {
+ _close => undef,
+ _close_wait => undef,
+ _established => undef,
+ _fin_wait => undef,
+ _last_ack => undef,
+ _syn_sent => undef,
+ _syn_recv => undef,
+ _time_wait => undef,
+ },
+ _udp => {
+ _other => undef,
+ _stream => undef,
+ },
+ _other => undef,
+ _icmp => undef ,
+ _comment => undef,
+);
+
+my %dummy_rule = (
+ _rule_number => 10000,
+ _protocol => undef,
+ _tcp => {
+ _close => undef,
+ _close_wait => undef,
+ _established => undef,
+ _fin_wait => undef,
+ _last_ack => undef,
+ _syn_sent => undef,
+ _syn_recv => undef,
+ _time_wait => undef,
+ },
+ _udp => {
+ _other => undef,
+ _stream => undef,
+ },
+ _other => undef,
+ _icmp => undef ,
+ _comment => undef,
+);
+
+my $DEBUG = 'false';
+
+sub rule {
+ my ( $self ) = @_;
+ my ($rule, $srcrule, $dstrule, $err_str);
+ my $tcp_and_udp = 0;
+ # set CLI rule num as comment
+ my @level_nodes = split (' ', $self->{_comment});
+ $rule .= "-m comment --comment \"$level_nodes[2]-$level_nodes[5]\" ";
+ ($srcrule, $err_str) = $src->rule();
+ if (defined($err_str)) {
+ Vyatta::Config::outputError(["Conntrack"], "Conntrack config error: $err_str");
+ exit 1;
+ }
+ ($dstrule, $err_str) = $dst->rule();
+ if (defined($err_str)) {
+ Vyatta::Config::outputError(["Conntrack"], "Conntrack config error: $err_str");
+ exit 1;
+ }
+ if ($self->{_protocol} eq "tcp") {
+ $rule .= " -p tcp";
+ } elsif ($self->{_protocol} eq "udp") {
+ $rule .= " -p udp";
+ } elsif ($self->{_protocol} eq "icmp") {
+ $rule .= " -p icmp";
+ } elsif ($self->{_protocol} eq "other") {
+ $rule .= " -p all";
+ }
+ $rule .= " $srcrule $dstrule ";
+ return $rule;
+}
+
+sub new {
+ my $that = shift;
+ my $class = ref ($that) || $that;
+ my $self = {
+ %fields,
+ };
+
+ bless $self, $class;
+ return $self;
+}
+
+sub setupDummy {
+ my ($self, $level) = @_;
+
+ %{$self} = %dummy_rule;
+ $src = new Vyatta::IpTables::AddressFilter;
+ $dst = new Vyatta::IpTables::AddressFilter;
+
+ # set the default policy
+ my $config = new Vyatta::Config;
+ $config->setLevel("$level");
+}
+
+sub setup_base {
+ my ($self, $level, $val_func, $exists_func, $addr_setup) = @_;
+ my $config = new Vyatta::Config;
+
+ $config->setLevel("$level");
+ $self->{_comment} = $level;
+ $self->{_rule_number} = $config->returnParent("..");
+ if ($config->$exists_func("protocol tcp")) {
+ $self->{_protocol} = "tcp";
+ $self->{_tcp}->{_close} = $config->$val_func("protocol tcp close");
+ $self->{_tcp}->{_close_wait} = $config->$val_func("protocol tcp close-wait");
+ $self->{_tcp}->{_time_wait} = $config->$val_func("protocol tcp time_wait");
+ $self->{_tcp}->{_syn_recv} = $config->$val_func("protocol tcp syn-recv");
+ $self->{_tcp}->{_syn_sent} = $config->$val_func("protocol tcp syn-sent");
+ $self->{_tcp}->{_last_ack} = $config->$val_func("protocol tcp last-ack");
+ $self->{_tcp}->{_fin_wait} = $config->$val_func("protocol tcp fin-wait");
+ $self->{_tcp}->{_established} = $config->$val_func("protocol tcp established");
+ } elsif ($config->$exists_func("protocol icmp")) {
+ $self->{_protocol} = "icmp";
+ $self->{_icmp} = $config->$val_func("protocol icmp");
+ } elsif ($config->$exists_func("protocol udp")) {
+ $self->{_protocol} = "udp";
+ $self->{_udp}->{_other} = $config->$val_func("protocol udp other");
+ $self->{_udp}->{_stream} = $config->$val_func("protocol udp stream");
+ } elsif ($config->$exists_func("protocol other")) {
+ $self->{_protocol} = "other";
+ $self->{_other} = $config->$val_func("protocol other");
+ }
+
+ $src->$addr_setup("$level source");
+ $src->{_protocol} = $self->{_protocol};#needed to use address filter
+ if ( (($src->{_protocol} eq 'icmp') or ($src->{_protocol} eq 'other')) and (defined($src->{_port})) ) {
+ die "Error: Cannot specify port with protocol $src->{_protocol}\n";
+ }
+ $dst->$addr_setup("$level destination");
+ $dst->{_protocol} = $self->{_protocol};#needed to use address filter
+ if ( (($dst->{_protocol} eq 'icmp') or ($dst->{_protocol} eq 'other')) and (defined($dst->{_port})) ) {
+ die "Error: Cannot specify port with protocol $dst->{_protocol}\n";
+ }
+
+ return 0;
+}
+
+sub setup {
+ my ($self, $level) = @_;
+
+ $self->setup_base($level, 'returnValue', 'exists', 'setup');
+ return 0;
+}
+
+sub setupOrig {
+ my ($self, $level) = @_;
+ $self->setup_base($level, 'returnOrigValue', 'existsOrig', 'setupOrig');
+ return 0;
+}
+
+sub print {
+ my ( $self ) = @_;
+
+ print "rulenum: $self->{_rule_number}\n" if defined $self->{_rule_number};
+ print "protocol: $self->{_protocol}\n" if defined $self->{_protocol};
+ print "state: $self->{_state}\n" if defined $self->{_state};
+ $src->print();
+ $dst->print();
+ print "$self->{_tcp}->{_close}\n";
+ print "$self->{_tcp}->{_close_wait}\n";
+ print "$self->{_tcp}->{_established}\n";
+ print "$self->{_tcp}->{_fin_wait}\n";
+ print "$self->{_tcp}->{_syn_sent}\n";
+ print "$self->{_tcp}->{_syn_recv}\n";
+}
+
+# return a string that has the nfct-timeout command to create
+# a timeout policy.
+sub get_policy_command {
+ my ($self, $is_delete) = @_;
+ my $command;
+ my @level_nodes = split (' ', $self->{_comment});
+ $command .= "policy_$level_nodes[2]_$level_nodes[5] ";
+ if ($is_delete eq "delete") {
+ return $command;
+ }
+ $command .= " inet";
+ if ($self->{_protocol} eq 'tcp') {
+ $command .= " tcp";
+ if ($self->{_tcp}->{_close}) {
+ $command .= " close $self->{_tcp}->{_close}";
+ }
+ if ($self->{_tcp}->{_close_wait}) {
+ $command .= " close_wait $self->{_tcp}->{_close_wait}";
+ }
+ if ($self->{_tcp}->{_time_wait}) {
+ $command .= " time_wait $self->{_tcp}->{_time_wait}";
+ }
+ if ($self->{_tcp}->{_syn_recv}) {
+ $command .= " syn_recv $self->{_tcp}->{_syn_recv}";
+ }
+ if ($self->{_tcp}->{_syn_sent}) {
+ $command .= " syn_sent $self->{_tcp}->{_syn_sent}";
+ }
+ if ($self->{_tcp}->{_last_ack}) {
+ $command .= " last_ack $self->{_tcp}->{_last_ack}";
+ }
+ if ($self->{_tcp}->{_fin_wait}) {
+ $command .= " fin_wait $self->{_tcp}->{_fin_wait}";
+ }
+ if ($self->{_tcp}->{_established}) {
+ $command .= " established $self->{_tcp}->{_established}";
+ }
+ } elsif ($self->{_protocol} eq 'udp') {
+ $command .= " udp";
+ if ($self->{_udp}->{_other}) {
+ $command .= " unreplied $self->{_udp}->{_other}";
+ }
+ if ($self->{_udp}->{_stream}) {
+ $command .= " replied $self->{_udp}->{_stream}";
+ }
+ } elsif ($self->{_protocol} eq 'icmp') {
+ $command .= " icmp timeout $self->{_icmp}";
+ } elsif ($self->{_protocol} eq 'other') {
+ $command .= " generic timeout $self->{_other}";
+ }
+ return $command;
+}
+
+
+
+1;
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 2
+# End:
diff --git a/scripts/vyatta-conntrack-timeouts.pl b/scripts/vyatta-conntrack-timeouts.pl
new file mode 100644
index 0000000..525a438
--- /dev/null
+++ b/scripts/vyatta-conntrack-timeouts.pl
@@ -0,0 +1,174 @@
+#!/usr/bin/perl
+
+use lib "/opt/vyatta/share/perl5";
+use warnings;
+use strict;
+
+use Vyatta::Config;
+use Vyatta::Conntrack::RuleCT;
+use Vyatta::IpTables::AddressFilter;
+use Getopt::Long;
+use Vyatta::Zone;
+use Sys::Syslog qw(:standard :macros);
+
+#for future use when v6 timeouts need to be set
+my %cmd_hash = ( 'ipv4' => 'iptables',
+ 'ipv6' => 'ip6tables');
+# Enable printing debug output to stdout.
+my $debug_flag = 0;
+
+# Enable sending debug output to syslog.
+my $syslog_flag = 0;
+my $nfct = "sudo /opt/vyatta/sbin/nfct";
+my ($create, $delete, $update);
+my $CTERROR = "Conntrack timeout error:";
+GetOptions("create=s" => \$create,
+ "delete=s" => \$delete,
+ "update=s" => \$update,
+);
+
+update_config();
+
+openlog("vyatta-conntrack", "pid", "local0");
+
+sub log_msg {
+ my $message = shift;
+
+ print "DEBUG: $message\n" if $debug_flag;
+ syslog(LOG_DEBUG, "%s", $message) if $syslog_flag;
+}
+# Run command and capture output
+# run_cmd("$iptables_cmd -t $table -F $name", 1);
+# if command fails, then send output to syslog
+sub run_cmd {
+ my ($cmd_to_run, $redirect) = @_;
+
+ log_msg("Running: $cmd_to_run");
+# print "$cmd_to_run\n";
+
+ if ($redirect) {
+ open (my $out, '-|', $cmd_to_run . ' 2>&1')
+ or die "Can't run command \"$cmd_to_run\": $!";
+ my @cmd_out = <$out>;
+
+ # if command suceeds to do nothing.
+ return if (close ($out));
+
+ foreach my $line (@cmd_out) {
+ chomp $line;
+ syslog(LOG_INFO, "%s", $line);
+ }
+ } else {
+ system($cmd_to_run);
+ }
+}
+
+sub remove_timeout_policy {
+ my ($rule_string, $timeout_policy) = @_;
+ my @tokens = split (' ', $timeout_policy);
+ # First remove the iptables rules before removing policy.
+ my $iptables_cmd1 = "iptables -D PREROUTING -t raw $rule_string -j CT --timeout $tokens[0]";
+ my $iptables_cmd2 = "iptables -D OUTPUT -t raw $rule_string -j CT --timeout $tokens[0]";
+ my $nfct_timeout_cmd = "$nfct timeout delete $timeout_policy";
+ run_cmd($iptables_cmd2);
+ if ($? >> 8) {
+ print "$CTERROR failed to run $iptables_cmd2\n";
+ #dont exit, try to clean as much.
+ }
+ run_cmd($iptables_cmd1);
+ if ($? >> 8) {
+ print "$CTERROR failed to run $iptables_cmd1\n";
+ }
+ run_cmd($nfct_timeout_cmd);
+ if ($? >> 8) {
+ print "$CTERROR failed to run $nfct_timeout_cmd\n";
+ }
+}
+
+# nfct-timeout create policy1 tcp established 1200 close-wait 100 fin-wait 10
+# iptables -I PREROUTING -t raw -s 1.1.1.1 -d 2.2.2.2 -j CT --timeout policy1
+sub apply_timeout_policy {
+ my ($rule_string, $timeout_policy, $rule) = @_;
+ my $nfct_timeout_cmd = "$nfct timeout add $timeout_policy";
+ my @tokens = split (' ', $timeout_policy);
+ my $iptables_cmd1 = "iptables -I PREROUTING -t raw $rule_string -j CT --timeout $tokens[0]";
+ my $iptables_cmd2 = "iptables -I OUTPUT -t raw $rule_string -j CT --timeout $tokens[0]";
+ run_cmd($nfct_timeout_cmd);
+ if ($? >> 8) {
+ print "$CTERROR failed to run $nfct_timeout_cmd\n";
+ exit 1;
+ }
+ run_cmd($iptables_cmd1);
+ if ($? >> 8) {
+ #cleanup the policy before exit.
+ run_cmd("nfct timeout delete policy_timeout_$rule");
+ print "$CTERROR failed to run $iptables_cmd1\n";
+ exit 1;
+ }
+ run_cmd($iptables_cmd2);
+ if ($? >> 8) {
+ run_cmd("nfct timeout delete policy_timeout_$rule");
+ run_cmd("iptables -D PREROUTING -t raw $rule_string -j CT --timeout $tokens[0]");
+ print "$CTERROR failed to run $iptables_cmd2\n";
+ exit 1;
+ }
+}
+
+sub handle_rule_creation {
+ my ($rule) = @_;
+ my $node = new Vyatta::Conntrack::RuleCT;
+ my ($rule_string, $timeout_policy);
+ do_protocol_check($rule);
+ $node->setup("system conntrack timeout custom rule $rule");
+ $rule_string = $node->rule();
+ $timeout_policy = $node->get_policy_command("add"); #nfct-timeout command string
+ apply_timeout_policy($rule_string, $timeout_policy, $rule);
+}
+
+# we mandate only one protocol configuration per rule
+sub do_protocol_check {
+ my ($rule) = @_;
+ my $config = new Vyatta::Config;
+ my $protocol_nos = $config->listNodes("system conntrack timeout custom rule $rule protocol");
+ if (($protocol_nos > 1) or ($protocol_nos < 1)) {
+ Vyatta::Config::outputError(["Conntrack"], "Conntrack config error: please configure exactly one protocol in rule $rule");
+ exit 1;
+ }
+}
+
+sub handle_rule_modification {
+ my ($rule) = @_;
+ do_protocol_check($rule);
+ handle_rule_deletion($rule);
+ handle_rule_creation($rule);
+}
+
+sub handle_rule_deletion {
+ my ($rule) = @_;
+ my $node = new Vyatta::Conntrack::RuleCT;
+ my ($rule_string, $timeout_policy);
+ $node->setupOrig("system conntrack timeout custom rule $rule");
+ $rule_string = $node->rule();
+ $timeout_policy = $node->get_policy_command("delete"); #nfct-timeout command string
+ remove_timeout_policy($rule_string, $timeout_policy);
+}
+
+sub update_config {
+ my $config = new Vyatta::Config;
+ my %rules = (); #hash of timeout config rules
+ my $iptables_cmd = $cmd_hash{'ipv4'};
+
+ $config->setLevel("system conntrack timeout custom rule");
+ %rules = $config->listNodeStatus();
+ foreach my $rule (sort keys %rules) {
+ if ("$rules{$rule}" eq 'static') {
+ } elsif ("$rules{$rule}" eq 'added') {
+ handle_rule_creation($rule);
+ } elsif ("$rules{$rule}" eq 'changed') {
+ handle_rule_modification($rule);
+ } elsif ("$rules{$rule}" eq 'deleted') {
+ handle_rule_deletion($rule);
+ }
+ }
+}
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/node.def b/templates-cfg/system/conntrack/timeout/custom/node.def
new file mode 100644
index 0000000..4421b83
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/node.def
@@ -0,0 +1,3 @@
+help: Define custom timeouts per connection
+end:expression: "sudo /opt/vyatta/bin/sudo-users/vyatta-conntrack-timeouts.pl"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.def
new file mode 100644
index 0000000..077603e
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.def
@@ -0,0 +1,9 @@
+tag:
+
+type: u32
+
+help: Rule number (1-9999)
+
+syntax:expression: $VAR(@) > 0 && $VAR(@) <= 9999; "Custom timeout rule number must be between 1 and 9999"
+
+val_help: u32:1-9999; Rule number
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/description/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/description/node.def
new file mode 100644
index 0000000..90bf88b
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/description/node.def
@@ -0,0 +1,3 @@
+type: txt
+
+help: Rule description
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/address/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/address/node.def
new file mode 100644
index 0000000..83d7514
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/address/node.def
@@ -0,0 +1,10 @@
+type: txt
+
+help: Destination IP address, subnet, or range
+
+val_help: ipv4; IP address to match
+val_help: ipv4net; Subnet to match
+val_help: ipv4range; IP range to match
+val_help: !ipv4; Match everything except the specified address
+val_help: !ipv4net; Match everything except the specified subnet
+val_help: !ipv4range; Match everything except the specified range
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/node.def
new file mode 100644
index 0000000..dc227b7
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/node.def
@@ -0,0 +1 @@
+help: Destination parameters
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/port/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/port/node.def
new file mode 100644
index 0000000..2b2d8c7
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/destination/port/node.def
@@ -0,0 +1,10 @@
+type: txt
+
+help: Destination port
+
+val_help: <port name>; Named port (any name in /etc/services, e.g., http)
+val_help: u32:1-65535; Numbered port
+val_help: range; Numbered port range (e.g., 1001-1005)
+comp_help: Multiple destination ports can be specified as a comma-separated list.
+The whole list can also be "negated" using '!'. For example:
+ '!22,telnet,http,123,1001-1005'
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/icmp/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/icmp/node.def
new file mode 100644
index 0000000..16c9224
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/icmp/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: ICMP timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; ICMP timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/node.def
new file mode 100644
index 0000000..7f26da6
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/node.def
@@ -0,0 +1,2 @@
+help: Customize protocol specific timers, one protocol configuration per rule
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/other/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/other/node.def
new file mode 100644
index 0000000..4d50136
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/other/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: Generic connection timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; Generic connection timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/close-wait/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/close-wait/node.def
new file mode 100644
index 0000000..7b9b089
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/close-wait/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: TCP CLOSE-WAIT timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; TCP CLOSE-WAIT timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/close/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/close/node.def
new file mode 100644
index 0000000..c37bb68
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/close/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: TCP CLOSE timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; TCP CLOSE timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/established/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/established/node.def
new file mode 100644
index 0000000..dfc575d
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/established/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: TCP ESTABLISHED timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; TCP ESTABLISHED timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/fin-wait/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/fin-wait/node.def
new file mode 100644
index 0000000..4514d6a
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/fin-wait/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: TCP FIN-WAIT timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; TCP FIN-WAIT timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/last-ack/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/last-ack/node.def
new file mode 100644
index 0000000..5c1cc25
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/last-ack/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: TCP LAST-ACK timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; TCP LAST-ACK timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/node.def
new file mode 100644
index 0000000..2d58f9c
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/node.def
@@ -0,0 +1 @@
+help: TCP per connection timeout options
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/syn-recv/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/syn-recv/node.def
new file mode 100644
index 0000000..a9c5a57
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/syn-recv/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: TCP SYN-RECEIVED timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; TCP SYN-RECEIVED timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/syn-sent/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/syn-sent/node.def
new file mode 100644
index 0000000..af71067
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/syn-sent/node.def
@@ -0,0 +1,7 @@
+type: u32
+
+help: TCP SYN-SENT timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; TCP SYN-SENT timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/time-wait/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/time-wait/node.def
new file mode 100644
index 0000000..1b85ba1
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/tcp/time-wait/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: TCP TIME-WAIT timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; TCP TIME-WAIT timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/node.def
new file mode 100644
index 0000000..321f684
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/node.def
@@ -0,0 +1 @@
+help: UDP per connection timeout configuration options
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/other/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/other/node.def
new file mode 100644
index 0000000..abfdc7e
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/other/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: UDP generic timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; UDP generic timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/stream/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/stream/node.def
new file mode 100644
index 0000000..431c94a
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/protocol/udp/stream/node.def
@@ -0,0 +1,8 @@
+type: u32
+
+help: UDP stream timeout for matching connection(s) in seconds
+
+val_help: u32:1-21474836; UDP stream timeout in seconds
+
+syntax:expression: ($VAR(@) >= 1 && $VAR(@) <= 21474836) ; "Value must be between 1 and 21474836"
+
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/address/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/address/node.def
new file mode 100644
index 0000000..72d6a17
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/address/node.def
@@ -0,0 +1,8 @@
+type: txt
+help: Source IP address, subnet, or range
+val_help: ipv4; IP address to match
+val_help: ipv4net; Subnet to match
+val_help: ipv4range; IP range to match
+val_help: !ipv4; Match everything except the specified address
+val_help: !ipv4net; Match everything except the specified subnet
+val_help: !ipv4range; Match everything except the specified range
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/node.def
new file mode 100644
index 0000000..84cdc1f
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/node.def
@@ -0,0 +1 @@
+help: Source parameters
diff --git a/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/port/node.def b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/port/node.def
new file mode 100644
index 0000000..adfae7a
--- /dev/null
+++ b/templates-cfg/system/conntrack/timeout/custom/rule/node.tag/source/port/node.def
@@ -0,0 +1,8 @@
+type: txt
+help: Source port
+val_help: <port name>; Named port (any name in /etc/services, e.g., http)
+val_help: u32:1-65535; Numbered port
+val_help: range; Numbered port range (e.g., 1001-1005)
+comp_help: Multiple source ports can be specified as a comma-separated list.
+The whole list can also be "negated" using '!'. For example:
+ '!22,telnet,http,123,1001-1005'