Report abuse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
Puppet::Type.type(:firewallchain).provide :iptables_chain do
  @doc = "Iptables chain provider"

  has_feature :iptables_chain
  has_feature :policy

  commands :iptables => '/sbin/iptables'
  commands :iptables_save => '/sbin/iptables-save'

  commands :ip6tables => '/sbin/ip6tables'
  commands :ip6tables_save => '/sbin/ip6tables-save'

  commands :ebtables => '/sbin/ebtables'
  commands :ebtables_save => '/sbin/ebtables-save'

  defaultfor :kernel => :linux

  Mapping = { 'IPv4' => { 'tables' => method( :iptables ), 'save' => method( :iptables_save) },
               'IPv6' => { 'tables' => method( :ip6tables ), 'save' => method( :ip6tables_save ) },
               'ethernet' => { 'tables' => method( :ebtables ), 'save' => method( :ebtables_save ) }
             }
  InternalChains = 'PREROUTING|POSTROUTING|BROUTING|INPUT|FORWARD|OUTPUT'
  Tables = 'NAT|MANGLE|FILTER|RAW|RAWPOST|BROUTE|'
  Nameformat = /^(#{Tables}):([^:]+):(IP(v[46])?|ethernet)?$/

  def create
    # can't create internal chains
    return if @resource[:name] =~ /^#{InternalChains}$/
    allvalidchains do |t, table, chain|
      debug 'Inserting chain #{chain} on table #{table}'
      t.call ['-t',table,'-N',chain] 
    end
  end

  def destroy
    # can't delete internal chains
    return if @resource[:name] =~ /^#{InternalChains}$/
    allvalidchains do |t, table, chain|
      debug 'Deleting chain #{chain} on table #{table}'
      t.call ['-t',table,'-X',chain] 
    end
  end

  def exists?
    properties[:ensure] != :absent
  end

  def policy=(value)
    allvalidchains do |t, table, chain|
      p =  ['-t',table,'-P',chain,value.to_s.upcase]
      debug "[set policy] #{t} #{p}"
      t.call p
    end
  end

  def policy
    debug "[get policy] #{@resource[:name]}"
    return @property_hash[:policy].to_s.downcase
  end

  def self.prefetch(resources)
    debug("[prefetch(resources)]")
    instances.each do |prov|
      if resource = resources[prov.name]
        resource.provider = prov
      end
    end
  end

  # Look up the current status. This allows us to conventiently look up
  # existing status with properties[:foo].
  def properties
    if @property_hash.empty?
      @property_hash = query || {:ensure => :absent}
      @property_hash[:ensure] = :absent if @property_hash.empty?
    end
    @property_hash.dup
  end

  # Pull the current state of the list from the full list.
  def query
    self.class.instances.each do |instance|
      if instance.name == self.name and instance.table == self.table
        debug "query found " % instance.properties.inspect
        return instance.properties
      end
    end
    nil
  end

  def self.instances
    debug "[instances]"
    table = nil
    chains = []
    hash = {}

    Mapping.each { |protocol, c|
      c['save'].call.split("\n").each do |line|
        # chain name is greedy so we anchor from the end.
        # [\d+:\d+] doesn't exist on ebtables
        if line =~ /^:(.+)\s(\S+)(\s\[\d+:\d+\])?$/ then
          name = (table == 'filter' ? '' : table.upcase) + ':' + $1
          policy = $2 == '-' ? :empty : $2.to_sym
          if protocol=='IPv6' && hash[name + ':']
            # duplicate so create a {table}:{chain}:IP instance
            ippolicy = hash[name + ':'] == policy ? policy : :inconsistent
            ipname = name + ':'
            hash[ipname] = ippolicy
            chains << new({:name => ipname, :policy => ippolicy })
            debug "[dup] #{ipname}, #{ippolicy}"
          end
          name += ':' + protocol
          hash[name] = policy
          chains << new({:name => name, :policy => policy })
          debug "#{name}, #{policy}"
        elsif line =~ /^\*(\S+)/
          table = $1
        end
      end
    }
    chains
  end


  private def allvalidchains
    tables = []
    @resource[:name].match(Nameformat)
    table = ($1=='') ? 'filter' : $1.downcase
    chain = $2
    protocol = $3
    if protocol == 'IP' or protocol == ''
      tables << Mapping['IPv4']['tables']
      tables << Mapping['IPv6']['tables']
    else
      tables << Mapping[protocol]['tables']
    end
    tables.each { |t| 
      yield t,table,chain,protocol
    }
  end
 
end