Page MenuHomePhabricator

Update IPv6 firewall rules to support matching of hop-limit
Closed, ResolvedPublicFEATURE REQUEST

Description

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.

Details

Difficulty level
Unknown (require assessment)
Version
-
Why the issue appeared?
Will be filled on close
rps created this task.Mar 2 2018, 9:03 PM
rps added a subscriber: dmbaturin.

P.S. @dmbaturin If you can direct me to some instructions on how you would prefer suggested patches be submitted I can re-work to make it easier on you.

rps added a comment.Mar 2 2018, 9:09 PM

For reference this is the standard ruleset I use on our servers for IPv6 (limited to only what is necessary for DHCPv6 and ICMPv6):

ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 1 -j ACCEPT                      # Destination Unreachable [RFC4443]
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 2 -j ACCEPT                      # Packet Too Big [RFC4443]
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 3 -j ACCEPT                      # Time Exceeded [RFC4443]
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 4 -j ACCEPT                      # Parameter Problem [RFC4443]
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 128 -j ACCEPT                    # Echo Request [RFC4443]
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 130 -j ACCEPT                    # Multicast Listener Query [RFC2710]
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 131 -j ACCEPT                    # Multicast Listener Report [RFC2710]
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 132 -j ACCEPT                    # Multicast Listener Done [RFC2710]
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
syncer assigned this task to dmbaturin.Mar 3 2018, 10:56 AM
syncer triaged this task as Normal priority.
rps added a comment.Sep 25 2018, 10:18 PM

Will this make it into 1.2 before the freeze?

dmbaturin closed this task as Resolved.Sun, Nov 18, 6:15 PM

@rps Sorry for late reply. I would prefer a git format patch of course, but I've merged it by hand and it seems to work fine. It will be in tomorrow's release candidate and today's nightly build.