Patch for current 1.2 nightly build included. Ip6tables supports the "hl" module for matching hop-limit.
The ability to match IPv6 traffic by TTL greatly simplifies firewall rule creation for appropriately restricting link-local traffic (such as IPv6 neighbor discovery).
Example:
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 134 -m hl --hl-eq 255 -j ACCEPT # Router Advertisement [RFC4861] ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 135 -m hl --hl-eq 255 -j ACCEPT # Neighbor Solicitation [RFC4861] ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 136 -m hl --hl-eq 255 -j ACCEPT # Neighbor Advertisement [RFC4861] ip6tables -A INPUT -p udp -m udp --sport 547 --dport 546 -m hl --hl-eq 255 -j ACCEPT # DHCPv6
The following syntax is proposed:
firewall { ipv6-name EXAMPLE { rule 1000 { action accept hop-limit { eq 255 } icmpv6 { type 134 } protocol ipv6-icmp } } }
Supporting eq, lt, and gt comparison operators for matching TTL 0-255.
The needed vyatta-cfg templates can be generated using the following:
mkdir /opt/vyatta/share/vyatta-cfg/templates/firewall/ipv6-name/node.tag/rule/node.tag/hop-limit echo -en "help: Hop Limit\n" > /opt/vyatta/share/vyatta-cfg/templates/firewall/ipv6-name/node.tag/rule/node.tag/hop-limit/node.def mkdir /opt/vyatta/share/vyatta-cfg/templates/firewall/ipv6-name/node.tag/rule/node.tag/hop-limit/eq mkdir /opt/vyatta/share/vyatta-cfg/templates/firewall/ipv6-name/node.tag/rule/node.tag/hop-limit/lt mkdir /opt/vyatta/share/vyatta-cfg/templates/firewall/ipv6-name/node.tag/rule/node.tag/hop-limit/gt echo -en "type: u32\nhelp: Value to match a hop limit equal to it\nval_help: u32:0-255; Hop limit equal to value\nsyntax:expression: \$VAR(@) >= 0 && \$VAR(@) <= 255; \"eq must be between 0 and 255\"\ncommit:expression: (\$VAR(../lt/) == \"\") && (\$VAR(../gt/) == \"\"); \"you may only define one comparison (eq|lt|gt)\"\n" > /opt/vyatta/share/vyatta-cfg/templates/firewall/ipv6-name/node.tag/rule/node.tag/hop-limit/eq/node.def echo -en "type: u32\nhelp: Value to match a hop limit less than or equal to it\nval_help: u32:0-255; Hop limit less than value\nsyntax:expression: \$VAR(@) >= 0 && \$VAR(@) <= 255; \"lt must be between 0 and 255\"\ncommit:expression: (\$VAR(../eq/) == \"\") && (\$VAR(../gt/) == \"\"); \"you may only define one comparison (eq|lt|gt)\"\n" > /opt/vyatta/share/vyatta-cfg/templates/firewall/ipv6-name/node.tag/rule/node.tag/hop-limit/lt/node.def echo -en "type: u32\nhelp: Value to match a hop limit greater than or equal to it\nval_help: u32:0-255; Hop limit greater than value\nsyntax:expression: \$VAR(@) >= 0 && \$VAR(@) <= 255; \"gt must be between 0 and 255\"\ncommit:expression: (\$VAR(../lt/) == \"\") && (\$VAR(../eq/) == \"\"); \"you may only define one comparison (eq|lt|gt)\"\n" > /opt/vyatta/share/vyatta-cfg/templates/firewall/ipv6-name/node.tag/rule/node.tag/hop-limit/gt/node.def
The implementation requires the following changes to /opt/vyatta/share/perl5/Vyatta/IpTables/Rule.pm from nightly build 999.201803010337 :
--- /opt/vyatta/share/perl5/Vyatta/IpTables/Rule.pm.backup 2018-03-02 16:46:17.442860929 +0000 +++ /opt/vyatta/share/perl5/Vyatta/IpTables/Rule.pm 2018-03-02 20:53:33.761473262 +0000 @@ -59,7 +59,12 @@ }, _disable => undef, _ip_version => undef, - _comment => undef + _comment => undef, + _hop_limit => { # rps_patch + _eq => undef, # rps_patch + _lt => undef, # rps_patch + _gt => undef, # rps_patch + } ); my %dummy_rule = ( @@ -112,7 +117,12 @@ }, _disable => undef, _ip_version => undef, - _comment => undef + _comment => undef, + _hop_limit => { # rps_patch + _eq => undef, # rps_patch + _lt => undef, # rps_patch + _gt => undef, # rps_patch + } ); my $DEBUG = 'false'; @@ -206,6 +216,10 @@ $self->{_disable} = $config->$exists_func("disable"); + $self->{_hop_limit}->{_eq} = $config->$val_func("hop-limit eq"); # rps_patch + $self->{_hop_limit}->{_lt} = $config->$val_func("hop-limit lt"); # rps_patch + $self->{_hop_limit}->{_gt} = $config->$val_func("hop-limit gt"); # rps_patch + # TODO: need $config->exists("$level source") in Vyatta::Config.pm $src->$addr_setup("$level source"); $dst->$addr_setup("$level destination"); @@ -255,6 +269,7 @@ print "mod table: $self->{_mod_table}\n" if defined $self->{_mod_table}; print "mod dscp: $self->{_mod_dscp}\n" if defined $self->{_mod_dscp}; print "mod tcp-mss: $self->{_mod_tcpmss}\n" if defined $self->{_mod_tcpmss}; + print "hop-limit: $self->{_hop_limit}\n" if defined $self->{_hop_limit}; # rps_patch $src->print(); $dst->print(); @@ -423,6 +438,16 @@ } } + # Setup HL rule if configured # rps_patch + # # rps_patch + if ( defined($self->{_hop_limit}->{_eq}) ) { # rps_patch + $rule .= " -m hl --hl-eq $self->{_hop_limit}->{_eq}"; # rps_patch + } elsif ( defined($self->{_hop_limit}->{_lt}) ) { # rps_patch + $rule .= " -m hl --hl-lt $self->{_hop_limit}->{_lt}"; # rps_patch + } elsif ( defined($self->{_hop_limit}->{_gt}) ) { # rps_patch + $rule .= " -m hl --hl-gt $self->{_hop_limit}->{_gt}"; # rps_patch + } # rps_patch + # add the source and destination rules ($srcrule, $err_str) = $src->rule(); return ($err_str,) if (!defined($srcrule));
Note rps_patch comments added for clarity and should be stripped before commit.
This patch appears to be functional and I recommend its review and inclusion in 1.2.