Module: Construqt::Flavour::Ubuntu::Firewall

Defined in:
lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb

Defined Under Namespace

Classes: ToFrom

Class Method Summary collapse

Class Method Details

.create(host, ifname, iface) ⇒ Object



439
440
441
442
443
444
445
446
447
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 439

def self.create(host, ifname, iface)
  throw 'interface must set' unless ifname
  writer = iface.host.result.etc_network_iptables
  create_from_iface(ifname, iface, writer)
  create_from_iface(ifname, iface.delegate.vrrp.delegate, writer) if iface.delegate.vrrp
  writer_local = host.result.etc_network_interfaces.get(iface)
  writer_local.lines.up("iptables-restore < /etc/network/iptables.cfg")
  writer_local.lines.up("ip6tables-restore < /etc/network/ip6tables.cfg")
end

.create_from_iface(ifname, iface, writer) ⇒ Object



430
431
432
433
434
435
436
437
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 430

def self.create_from_iface(ifname, iface, writer)
  iface.firewalls && iface.firewalls.each do |firewall|
    firewall.get_raw && Firewall.write_raw(firewall, firewall.get_raw, ifname, iface, writer.raw)
    firewall.get_nat && Firewall.write_nat(firewall, firewall.get_nat, ifname, iface, writer.nat)
    firewall.get_forward && Firewall.write_forward(firewall, firewall.get_forward, ifname, iface, writer.filter)
    firewall.get_host && Firewall.write_host(firewall, firewall.get_host, ifname, iface, writer.filter)
  end
end


335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 335

def self.create_link_local(fw, ifname, iface, rule, writer)
  return unless fw.ipv6?
  # fe80::/64
  # ff02::/16 dest
  i_to_from = ToFrom.new.bind_interface(ifname, iface, rule).input_only
  i_rule = rule.clone.from_my_net.to_my_net
  i_to_from.push_begin_to("-p icmpv6")
  i_rule.to_net_addr("fe80::/64")
  i_rule.from_net_addr("ff02::/16", "fe80::/64")
  write_table("ip6tables", i_rule, i_to_from.factory(writer.ipv6.input))

  #i_to_from = ToFrom.new.bind_interface(ifname, iface, rule).input_only
  #i_rule = rule.clone.from_my_net.to_my_net
  #i_to_from.push_begin_to("-p icmpv6")
  #i_rule.to_net_addr("fe80::/64")
  #i_rule.from_net_addr("fe80::/64")
  #i_to_from.push_middle_to("--icmpv6-type 136")
  #write_table("ip6tables", i_rule, i_to_from.factory(writer.ipv6.input))

  o_to_from = ToFrom.new.bind_interface(ifname, iface, rule).output_only
  o_to_from.push_begin_from("-p icmpv6")
  o_rule = rule.clone.from_my_net.to_my_net
  #o_rule.from_net_addr("fe80::/64")
  o_rule.from_net_addr("fe80::/64")
  o_rule.to_net_addr("ff02::/16", "fe80::/64")
  #o_to_from.push_middle_from("--icmpv6-type 135")
  write_table("ip6tables", o_rule, o_to_from.factory(writer.ipv6.output))

  #binding.pry
  #o_to_from = ToFrom.new.bind_interface(ifname, iface, rule).output_only
  #o_to_from.push_begin_from("-p icmpv6")
  #o_rule = rule.clone.from_my_net.to_my_net
  #o_rule.from_net_addr("fe80::/64")
  #o_rule.to_net_addr("fe80::/64")
  #o_to_from.push_middle_from("--icmpv6-type 136")
  #write_table("ip6tables", o_rule, o_to_from.factory(writer.ipv6.output))
end

.filter_routes(routes, family) ⇒ Object



129
130
131
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 129

def self.filter_routes(routes, family)
  routes.map{|i| i.dst }.select{|i| family == Construqt::Addresses::IPV6 ? i.ipv6? : i.ipv4? }
end

.icmp_type(family, type) ⇒ Object



283
284
285
286
287
288
289
290
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 283

def self.icmp_type(family, type)
  {
    Construqt::Firewalls::ICMP::PingRequest => {
        :v4 => "-m icmp --icmp-type 8/0",
        :v6 => "--icmpv6-type 128"
    }
  }[type][family]
end

.protocol_loop(rule) ⇒ Object



268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 268

def self.protocol_loop(rule)
  protocol_loop = []
  {
    'tcp' => rule.tcp?,
    'udp' => rule.udp?,
    'esp' => rule.esp?,
    'ah' => rule.ah?,
    'icmp' => rule.icmp?
  }.each do |proto, enabled|
    protocol_loop << "-p #{proto}" if enabled
  end
  protocol_loop = [''] if protocol_loop.empty?
  protocol_loop
end

.write_forward(fw, forward, ifname, iface, writer) ⇒ Object



292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 292

def self.write_forward(fw, forward, ifname, iface, writer)
  forward.rules.each do |rule|
    throw "ACTION must set #{ifname}" unless rule.get_action
    #puts "write_forward #{rule.inspect} #{rule.input_only?} #{rule.output_only?}"
    if rule.get_log
      to_from = ToFrom.new.bind_interface(ifname, iface, rule).assign_in_out(rule)
        .end_to("--nflog-prefix o:#{rule.get_log}:#{ifname}")
        .end_from("--nflog-prefix i:#{rule.get_log}:#{ifname}")
      fw.ipv4? && write_table("iptables", rule.clone.action("NFLOG"), to_from.factory(writer.ipv4.forward))
      fw.ipv6? && write_table("ip6tables", rule.clone.action("NFLOG"), to_from.factory(writer.ipv6.forward))
    end

    protocol_loop(rule).each do |protocol|
      {:v4 => { :enabled => fw.ipv4?, :table => "iptables", :writer => writer.ipv4.forward },
       :v6 => { :enabled => fw.ipv6?, :table => "ip6tables", :writer => writer.ipv6.forward }}.each do |family, cfg|
        next unless cfg[:enabled]
        to_from = ToFrom.new.bind_interface(ifname, iface, rule).assign_in_out(rule)
        if protocol == "-p icmp" && family == :v6
          my_protocol = "-p icmpv6"
        else
          my_protocol = protocol
        end
        to_from.push_begin_to(my_protocol)
        to_from.push_begin_from(my_protocol)

        if rule.get_ports && !rule.get_ports.empty?
          to_from.push_middle_from("-m multiport --dports #{rule.get_ports.join(",")}")
          to_from.push_middle_to("-m multiport --sports #{rule.get_ports.join(",")}")
        end
        if rule.icmp? && rule.get_type
          to_from.push_middle_from(icmp_type(family, rule.get_type))
        end

        if rule.connection?
          to_from.push_middle_from("-m state --state NEW,ESTABLISHED")
          to_from.push_middle_to("-m state --state RELATED,ESTABLISHED")
        end
        write_table(cfg[:table], rule, to_from.factory(cfg[:writer]))
      end
    end
  end
end

.write_host(fw, host, ifname, iface, writer) ⇒ Object



373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 373

def self.write_host(fw, host, ifname, iface, writer)
  host.rules.each do |rule|
    if rule.get_log
      nflog_rule = rule.clone.action("NFLOG")
      l_in_to_from = ToFrom.new.bind_interface(ifname, iface, nflog_rule).input_only
        .end_from("--nflog-prefix o:#{rule.get_log}:#{ifname}")
      l_out_to_from = ToFrom.new.bind_interface(ifname, iface, nflog_rule).output_only
        .end_to("--nflog-prefix i:#{rule.get_log}:#{ifname}")
      fw.ipv4? && write_table("iptables", nflog_rule, l_in_to_from.factory(writer.ipv4.input))
      fw.ipv4? && write_table("iptables", nflog_rule, l_out_to_from.factory(writer.ipv4.output))
      fw.ipv6? && write_table("ip6tables", nflog_rule, l_in_to_from.factory(writer.ipv6.input))
      fw.ipv6? && write_table("ip6tables", nflog_rule, l_out_to_from.factory(writer.ipv6.output))
    end
    next create_link_local(fw, ifname, iface, rule, writer) if rule.link_local?

    protocol_loop(rule).each do |protocol|
      [{
        :doit    => rule.input_only?,
        :from_to => lambda { ToFrom.new.bind_interface(ifname, iface, rule).input_only },
        :writer4 => !rule.from_is_inbound? ? writer.ipv4.input : writer.ipv4.output,
        :writer6 => !rule.from_is_inbound? ? writer.ipv6.input : writer.ipv6.output
      },{
        :doit    => rule.output_only?,
        :from_to => lambda { ToFrom.new.bind_interface(ifname, iface, rule).output_only },
        :writer4 => rule.from_is_inbound? ? writer.ipv4.input : writer.ipv4.output,
        :writer6 => rule.from_is_inbound? ? writer.ipv6.input : writer.ipv6.output
      }].each do |to_from_writer|
        next unless to_from_writer[:doit]
        {:v4 => { :enabled => fw.ipv4?, :table => "iptables", :writer => to_from_writer[:writer4]},
         :v6 => { :enabled => fw.ipv6?, :table => "ip6tables", :writer => to_from_writer[:writer6] }}.each do |family, cfg|
          to_from = to_from_writer[:from_to].call
          next unless cfg[:enabled]
          if protocol == "-p icmp" && family == :v6
            my_protocol = "-p icmpv6"
          else
            my_protocol = protocol
          end
          to_from.push_begin_to(my_protocol)
          to_from.push_begin_from(my_protocol)
          if rule.get_ports && !rule.get_ports.empty?
            to_from.push_middle_from("-m multiport --dports #{rule.get_ports.join(",")}")
            to_from.push_middle_to("-m multiport --sports #{rule.get_ports.join(",")}")
          end
          if rule.icmp? && rule.get_type
            to_from.push_middle_from(icmp_type(family, rule.get_type))
          end
          if rule.connection?
            to_from.push_middle_from("-m state --state NEW,ESTABLISHED")
            to_from.push_middle_to("-m state --state RELATED,ESTABLISHED")
          end
          write_table(cfg[:table], rule, to_from.factory(cfg[:writer]))
        end
      end
    end
  end
end

.write_nat(fw, nat, ifname, iface, writer) ⇒ Object



254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 254

def self.write_nat(fw, nat, ifname, iface, writer)
  nat.rules.each do |rule|
    throw "ACTION must set #{ifname}" unless rule.get_action
    throw "TO_SOURCE must set #{ifname}" unless rule.to_source?
    if rule.to_source? && rule.postrouting?
      src = iface.address.ips.select{|ip| ip.ipv4?}.first
      throw "missing ipv4 address and postrouting and to_source is used #{ifname}" unless src
      to_from = ToFrom.new.bind_interface(ifname, iface, rule).assign_in_out(rule).end_to("--to-source #{src}")
        .ifname(ifname).factory(writer.ipv4.postrouting)
      fw.ipv4? && write_table("iptables", rule, to_from)
    end
  end
end

.write_raw(fw, raw, ifname, iface, writer) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 235

def self.write_raw(fw, raw, ifname, iface, writer)
  #        puts ">>>RAW #{iface.name} #{raw.firewall.name}"
  raw.rules.each do |rule|
    throw "ACTION must set #{ifname}" unless rule.get_action
    if rule.prerouting?
      to_from = ToFrom.new.bind_interface(ifname, iface, rule).assign_in_out(rule)
      #puts "PREROUTING #{to_from.inspect}"
      fw.ipv4? && write_table("iptables", rule, to_from.factory(writer.ipv4.prerouting))
      fw.ipv6? && write_table("ip6tables", rule, to_from.factory(writer.ipv6.prerouting))
    end

    if rule.output?
      to_from = ToFrom.new.bind_interface(ifname, iface, rule).assign_in_out(rule)
      fw.ipv4? && write_table("iptables", rule, to_from.factory(writer.ipv4.output))
      fw.ipv6? && write_table("ip6tables", rule, to_from.factory(writer.ipv6.output))
    end
  end
end

.write_table(iptables, rule, to_from) ⇒ Object

def self.try_tags_as_ipaddress(list, family, *possible_addrs)

  return list unless list.empty?
  ret = possible_addrs.map do |addr|
    next nil unless addr
    begin
      addr = IPAddress.parse(addr)
      next addr if (addr.ipv4? && family == Construqt::Addresses::IPV4) || (addr.ipv6? && family == Construqt::Addresses::IPV6)
      nil
    rescue Exception => e
      nil
    end
  end.compact
  binding.pry unless ret.empty?
  ret
end


149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb', line 149

def self.write_table(iptables, rule, to_from)
  family = iptables=="ip6tables" ? Construqt::Addresses::IPV6 : Construqt::Addresses::IPV4
  if rule.from_my_net?
    networks = iptables=="ip6tables" ? to_from.get_interface.address.v6s : to_from.get_interface.address.v4s
    if rule.from_route?
      networks += self.filter_routes(to_from.get_interface.address.routes, family)
    end
    from_list = IPAddress.summarize(networks)
  else
    from_list = Construqt::Tags.ips_net(rule.get_from_net, family)
#            from_list = try_tags_as_ipaddress(from_list, family, rule.get_from_net)
  end

  if rule.to_my_net?
    networks = iptables=="ip6tables" ? to_from.get_interface.address.v6s : to_from.get_interface.address.v4s
    if rule.from_route?
      networks += self.filter_routes(to_from.get_interface.address.routes, family)
    end
    to_list = IPAddress.summarize(networks)
  else
    if rule.get_to_host
      to_list = Construqt::Tags.ips_hosts(rule.get_to_host, family)
    else
      to_list = Construqt::Tags.ips_net(rule.get_to_net, family)
    end
#           to_list = try_tags_as_ipaddress(to_list, family, rule.get_to_net, rule.get_to_host)
  end
  unless rule.get_to_net_addr.empty?
    #binding.pry
    addrs = rule.get_to_net_addr.map { |i| IPAddress.parse(i) }.select { |i|
      (i.ipv6? && family == Construqt::Addresses::IPV6) || (i.ipv4? && family == Construqt::Addresses::IPV4)
    }
    to_list = IPAddress.summarize(to_list + addrs)
  end
  unless rule.get_from_net_addr.empty?
    addrs = rule.get_from_net_addr.map { |i| IPAddress.parse(i) }.select { |i|
      (i.ipv6? && family == Construqt::Addresses::IPV6) || (i.ipv4? && family == Construqt::Addresses::IPV4)
    }
    from_list = IPAddress.summarize(from_list + addrs)
  end
  #puts ">>>>>#{from_list.inspect}"
  #puts ">>>>>#{state.inspect} end_to:#{state.end_to}:#{state.end_from}:#{state.middle_to}#{state.middle_from}"
  action_i = action_o = rule.get_action
  if to_list.empty? && from_list.empty?
    #puts "write_table=>o:#{to_from.output_only?}:#{to_from.output_ifname} i:#{to_from.input_only?}:#{to_from.input_ifname}"
    if to_from.output_only?
      to_from.factory!.row("#{to_from.output_ifname}#{to_from.get_begin_from}#{to_from.get_middle_to} -j #{rule.get_action}#{to_from.get_end_to}")
    end

    if to_from.input_only?
      to_from.factory!.row("#{to_from.input_ifname}#{to_from.get_begin_to}#{to_from.get_middle_from} -j #{rule.get_action}#{to_from.get_end_from}")
    end
  end

  if to_list.length > 1
    # work on these do a better hashing
    action_o = "I.#{to_from.get_ifname}.#{rule.object_id.to_s(32)}"
    action_i = "O.#{to_from.get_ifname}.#{rule.object_id.to_s(32)}"
    to_list.each do |ip|
      if to_from.output_only?
        to_from.factory!.table(action_o).row("#{to_from.output_ifname} -d #{ip.to_string} -j #{rule.get_action}")
      end

      if to_from.input_only?
        to_from.factory!.table(action_i).row("#{to_from.input_ifname} -s #{ip.to_string} -j #{rule.get_action}")
      end
    end

  elsif to_list.length == 1
    from_dst = " -d #{to_list.first.to_string}"
    to_src = " -s #{to_list.first.to_string}"
  else
    from_dst = to_src =""
  end

  from_list.each do |ip|
    if to_from.output_only?
      to_from.factory!.row("#{to_from.output_ifname}#{to_from.get_begin_from} -s #{ip.to_string}#{from_dst}#{to_from.get_middle_from} -j #{action_o}#{to_from.get_end_to}")
    end

    if to_from.input_only?
      to_from.factory!.row("#{to_from.input_ifname}#{to_from.get_begin_to}#{to_src} -d #{ip.to_string}#{to_from.get_middle_to} -j #{action_i}#{to_from.get_end_from}")
    end
  end
end