The Puppet Labs Issue Tracker has Moved: https://tickets.puppetlabs.com

This issue tracker is now in read-only archive mode and automatic ticket export has been disabled. Redmine users will need to create a new JIRA account to file tickets using https://tickets.puppetlabs.com. See the following page for information on filing tickets with JIRA:

Feature #11440

ipv4 and ipv6 providers concurrent support unless v4 or v6 only feature/address is specified

Added by Daniel Black over 4 years ago. Updated about 3 years ago.

Status:ClosedStart date:12/16/2011
Priority:NormalDue date:
Assignee:Ken Barber% Done:

0%

Category:firewallSpent time:-
Target version:-
Keywords: Branch:

We've Moved!

Ticket tracking is now hosted in JIRA: https://tickets.puppetlabs.com


Description

I’d like the following to generate an IPv4 and IPv6 rules. Is this possible?

        firewall { '510 ssh':
                dport => '22',
                state => 'NEW',
                action => 'accept',
        }

Its currently missing IPv6 rule for this.

$ ip6tables -nvL INPUT
Chain INPUT (policy ACCEPT 3378 packets, 351K bytes)
 pkts bytes target     prot opt in     out     source               destination

History

#1 Updated by Daniel Black over 4 years ago

My workaround is the current definition that omits the source/destination/tosource/todest which are IP specific. Interesting icmp/ipv6-icmp6 is valid on both stacks. I haven’t tested all options here yet.

Feel free to include.

define dualstackfirewall ( $ensure=undef, $action=undef, $sport=undef, $dport=undef, $port=undef, $proto=undef,
      $chain=undef, $table=undef, $jump=undef, $iniface=undef, $outiface=undef, $toports=undef, $reject=undef,
      $log_level=undef, $log_prefix=undef, $icmp=undef, $state=undef, $limit=undef, $burst=undef,
      $uid=undef, $gid=undef, $match=undef ) {
   firewall { "${name}_ipv4": provider=>iptables }
   firewall { "${name}_ipv6": provider=>ip6tables }

   if $ensure { Firewall["${name}_ipv4"] { ensure=>$ensure } Firewall["${name}_ipv6"] { ensure=>$ensure } }
   if $action { Firewall["${name}_ipv4"] { action=>$action } Firewall["${name}_ipv6"] { action=>$action } }
   if $sport { Firewall["${name}_ipv4"] { sport=>$sport } Firewall["${name}_ipv6"] { sport=>$sport } }
   if $dport { Firewall["${name}_ipv4"] { dport=>$dport } Firewall["${name}_ipv6"] { dport=>$dport } }
   if $port { Firewall["${name}_ipv4"] { port=>$port } Firewall["${name}_ipv6"] { port=>$port } }
   if $proto { Firewall["${name}_ipv4"] { proto=>$proto } Firewall["${name}_ipv6"] { proto=>$proto } }
   if $chain { Firewall["${name}_ipv4"] { chain=>$chain } Firewall["${name}_ipv6"] { chain=>$chain } }
   if $table { Firewall["${name}_ipv4"] { table=>$table } Firewall["${name}_ipv6"] { table=>$table } }
   if $jump { Firewall["${name}_ipv4"] { jump=>$jump } Firewall["${name}_ipv6"] { jump=>$jump } }
   if $iniface { Firewall["${name}_ipv4"] { iniface=>$iniface } Firewall["${name}_ipv6"] { iniface=>$iniface } }
   if $outiface { Firewall["${name}_ipv4"] { outiface=>$outiface } Firewall["${name}_ipv6"] { outiface=>$outiface } }
   if $toports { Firewall["${name}_ipv4"] { toports=>$toports } Firewall["${name}_ipv6"] { toports=>$toports } }
   if $reject { Firewall["${name}_ipv4"] { reject=>$reject } Firewall["${name}_ipv6"] { reject=>$reject } }
   if $log_level { Firewall["${name}_ipv4"] { log_level=>$log_level } Firewall["${name}_ipv6"] { log_level=>$log_level } }
   if $log_prefix { Firewall["${name}_ipv4"] { log_prefix=>$log_prefix } Firewall["${name}_ipv6"] { log_prefix=>$log_prefix } }
   if $icmp { Firewall["${name}_ipv4"] { icmp=>$icmp } Firewall["${name}_ipv6"] { icmp=>$icmp } }
   if $state { Firewall["${name}_ipv4"] { state=>$state } Firewall["${name}_ipv6"] { state=>$state } }
   if $limit { Firewall["${name}_ipv4"] { limit=>$limit } Firewall["${name}_ipv6"] { limit=>$limit } }
   if $burst { Firewall["${name}_ipv4"] { burst=>$burst } Firewall["${name}_ipv6"] { burst=>$burst } }
   if $uid { Firewall["${name}_ipv4"] { uid=>$uid } Firewall["${name}_ipv6"] { uid=>$uid } }
   if $gid { Firewall["${name}_ipv4"] { gid=>$gid } Firewall["${name}_ipv6"] { gid=>$gid } }
   if $match { Firewall["${name}_ipv4"] { match=>$match } Firewall["${name}_ipv6"] { match=>$match } }
}

note: (late edit s/outface/outiface)

#2 Updated by Daniel Black over 4 years ago

As seen with ticket/10162-firewallchain_support_attempt2 multi-provider support can work.

Proposal

As this proposal changes the 1 to 1 resource to rule assumption to a 1 to many, it also solves #10116 (source/destination arrays), #11439 tcp/udp in one rule, and hopefully will fix #11279 source/destination removal to change rule,

provider changes

self.instances

Consolidation in the provider self.instances method will consolidate resources instances where the instance properties (excluding src/dest) match and the comment, table, and chain matches and comment.isnotempty().

  self.instances
    hash = {}
    for ebtables-save,iptables-save,ip6tables-save as |currentaddressfamily|
      line by line
        parse rule
        if comment.empty()
          key = { comment=>comment, table => table, chain => chain, unmanaged_id = uniq() }
          hash[key] = { properties => properties, addressfamily => currentaddressfamily }
        else
          key = { comment=>comment, table => table, chain => chain, unmanaged_id = false }
          x = hash[key]
          if x
            if x.properties_removing_src_dest == properties_removing_src_dest
              x.properties.src += properties.src 
              x.properties.dest += properties.dest
              x.addressfamily += currentfamily
            else
              # collision in comments - assume not puppet managed but preserve uniqueness
              # unmanage old resource
              hash.removebykey(key)
              key[unmanaged_id]=uniq()
              hash[key] = x
              # new rule
              key2=key.dup
              key2[unmanaged_id]=uniq()
              hash[key2][properties] = properties
              hash[key2][addressfamily] => currentaddressfamily
            end
          else
            # new chain
            hash[key] = { properties => properties, addressfamily => currentaddressfamilty }
          end
        end
      next line
    next address familty table

create rule

create rule iterates over address family tables and creates a rule ignoring those where source/destination don’t match table.address_family.

remove rule

type/src/destination/table assignment

evaluate which types nolonger apply and remove them. Add new types if required.

type changes

Add to firewall a :type attribute with values [ :ipv4, :ipv6, :ethernet, :auto ] defaulting to auto.

Validation (:type != :auto)

(type allowed as array)

  • if no source or no destination – all good

  • if source/destination.address_family != :type – error

  • if source/destination.resolve doesn’t include :type address – error

  • if source/destination.resolve includes ! :type address – warning (e.g. ‘google.com return IPv6 address 20…::2 however type was fixed to :ipv4’

Validation (:type == :auto)

types = [ ‘ethernet’, ‘ipv4’, ‘ipv6’]

  • if :table = nat –> types remove ipv6

  • if :table = ‘BROUTING’ –> types remove ipv4, ipv6

  • if source address specified –> types remove [ ‘unspecified addresses’]

  • if destination address specified –> types remove [ ‘unspecified addresses’]

  • if no ethernet source/destination addresses and :table != ‘BROUTING’ –> types remove ethernet

  • if types.empty – error

Examples

google.com , example.com –> ipv4 and ipv6 addresses ipv4.google.com ipv4.example.com –> ipv4 only addresses ipv6.google.com ipv6.example.com –> ipv6 only addresses

Examples: address family | resource

  • ipv4, ipv6 | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, }

  • ipv4 | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, type => ‘ipv4’ }

  • ipv6 | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, type => ‘ipv6’ }

  • ethernet | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, table=>‘BROUTE’ }

  • ethernet | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>‘60:EB:69:E8:CE:7F’ }

  • all | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘60:EB:69:E8:CE:7F’, ‘google.com’] }

  • ipv4, ipv6 (ethernet ignored as no destination ethernet address) | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘60:EB:69:E8:CE:7F’, ‘google.com’], destination => ‘example.com’ ] }

  • ipv4, ipv6 | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘example.com’], destination =>‘google.com’] }

  • error – nothing common | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘ipv4.example.com’], destination =>‘ipv6.google.com’] }

  • IPv6 | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘ipv6.example.com’], destination =>‘ipv6.google.com’] }

  • IPv4 + warning (that ipv6 on google exists) | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘ipv4.example.com’], destination =>‘google.com’] }

  • IPv6 + warning (that ipv4 on google exists) | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘ipv6.example.com’], destination =>‘google.com’] }

  • error – ipv4 specified by no ipv4 | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘ipv6.example.com’], type => ‘ipv4’ }

  • error – ipv6 specified by no ipv6 | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘ipv4.example.com’], type => ‘ipv6’ }

  • error – ethernet specified by no ethernet src/destination | firewall { ‘510 ssh’: dport => ‘22’, action => ‘accept’, source=>[‘example.com’,‘google.com’], type => [ ‘ethernet’, ‘ipv4’, ‘ipv6’ }

#3 Updated by James Turnbull over 4 years ago

  • Status changed from Unreviewed to Needs Decision
  • Assignee set to Ken Barber

#4 Updated by Dan Carley almost 4 years ago

I like the proposal, Daniel.

The current dual-stack functionality we’ve got is pretty much useless. For instance there’s no way to purge rules outside the default v4 provider. Anything that we can do to mask the stupidity of the historical iptables/ip6tables split is a boon.

Do you have the prototype in a branch somewhere that I can help hack upon?

#5 Updated by Ken Barber about 3 years ago

  • Status changed from Needs Decision to Closed

Hiya … I’ve fall behind a bit on all this work, also the bug tracker is moving to here: https://github.com/puppetlabs/puppet-firewall/issues I’ve managed to move what I still think is relevant and merge up items that are related. Consider this a slight declaration of ‘ticket debt’. If you think you’re issue isn’t represented in the new tracker feel free to open a new one.

Apologies for any confusion :–).

Ken.

#6 Updated by Ken Barber about 3 years ago

Sorry – the new URL is actually: http://github.com/puppetlabs/puppetlabs-firewall/issues … thanks @Wolfspyre.

Also available in: Atom PDF