firewall_helper.rb 2.7 KB
Newer Older
1
2
require 'packetfu'

3
4
5
6
7
8
9
10
11
12
13
# Returns the unique edges (based on protocol, source/destination
# address/port) in the graph of all network flows.
def pcap_connections_helper(pcap_file, opts = {})
  opts[:ignore_dhcp] ||= true
  connections = Array.new
  packets = PacketFu::PcapFile.new.file_to_array(:filename => pcap_file)
  packets.each do |p|
    if PacketFu::EthPacket.can_parse?(p)
      eth_packet = PacketFu::EthPacket.parse(p)
    else
      raise 'Found something that is not an ethernet packet'
14
    end
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    sport = nil
    dport = nil
    if PacketFu::TCPPacket.can_parse?(p)
      ip_packet = PacketFu::TCPPacket.parse(p)
      protocol = 'tcp'
      sport = ip_packet.tcp_sport
      dport = ip_packet.tcp_dport
    elsif PacketFu::UDPPacket.can_parse?(p)
      ip_packet = PacketFu::UDPPacket.parse(p)
      protocol = 'udp'
      sport = ip_packet.udp_sport
      dport = ip_packet.udp_dport
    elsif PacketFu::ICMPPacket.can_parse?(p)
      ip_packet = PacketFu::ICMPPacket.parse(p)
      protocol = 'icmp'
    elsif PacketFu::IPPacket.can_parse?(p)
      ip_packet = PacketFu::IPPacket.parse(p)
      protocol = 'ip'
    elsif PacketFu::IPv6Packet.can_parse?(p)
      ip_packet = PacketFu::IPv6Packet.parse(p)
      protocol = 'ipv6'
    else
      raise "Found something that cannot be parsed"
38
39
    end

40
41
42
43
44
45
    if protocol == "udp" and
       sport == 68 and
       dport == 67 and
       ip_packet.ip_saddr == '0.0.0.0' and
       ip_packet.ip_daddr == "255.255.255.255"
      next if opts[:ignore_dhcp]
46
    end
47

48
    packet_info = {
49
50
51
52
53
54
      mac_saddr: eth_packet.eth_saddr,
      mac_daddr: eth_packet.eth_daddr,
      protocol: protocol,
      sport: sport,
      dport: dport,
    }
55
56
57
58
59
60
61
62
63
    # It seems *Packet.parse can return nil despite *Packet.can_parse?
    # returning true.
    if ip_packet
      packet_info[:saddr] = ip_packet.ip_saddr
      packet_info[:daddr] = ip_packet.ip_daddr
    else
      puts "We were hit by #11508. PacketFu bug? Packet info: #{packet_info}"
    end
    connections << packet_info
64
  end
65
66
67
  connections.uniq.map { |p| OpenStruct.new(p) }
end

68
69
70
class FirewallAssertionFailedError < Test::Unit::AssertionFailedError
end

anonym's avatar
anonym committed
71
72
# These assertions are made from the perspective of the system under
# testing when it comes to the concepts of "source" and "destination".
73
74
75
76
def assert_all_connections(pcap_file, opts = {}, &block)
  all = pcap_connections_helper(pcap_file, opts)
  good = all.find_all(&block)
  bad = all - good
77
78
79
80
81
  unless bad.empty?
    raise FirewallAssertionFailedError.new(
            "Unexpected connections were made:\n" +
            bad.map { |e| "  #{e}" } .join("\n"))
  end
82
end
83

84
85
def assert_no_connections(pcap_file, opts = {}, &block)
  assert_all_connections(pcap_file, opts) { |*args| not(block.call(*args)) }
86
end