Update changelog for 0.20.
[tails-test.git] / features / support / helpers / firewall_helper.rb
blob400965a51b6dc0b7eeb1179f3ec2e16e8c305277
1 require 'packetfu'
2 require 'ipaddr'
4 # Extent IPAddr with a private/public address space checks
5 class IPAddr
6   PrivateIPv4Ranges = [
7     IPAddr.new("10.0.0.0/8"),
8     IPAddr.new("172.16.0.0/12"),
9     IPAddr.new("192.168.0.0/16"),
10     IPAddr.new("255.255.255.255/32")
11   ]
13   PrivateIPv6Ranges = [
14     IPAddr.new("fc00::/7"),   # private
15   ]
17   def private?
18     if self.ipv4?
19       PrivateIPv4Ranges.each do |ipr|
20         return true if ipr.include?(self)
21       end
22       return false
23     else
24       PrivateIPv6Ranges.each do |ipr|
25         return true if ipr.include?(self)
26       end
27       return false
28     end
29   end
31   def public?
32     !private?
33   end
34 end
36 class FirewallLeakCheck
37   attr_reader :ipv4_tcp_leaks, :ipv4_nontcp_leaks, :ipv6_leaks, :nonip_leaks
39   def initialize(pcap_file, tor_relays)
40     packets = PacketFu::PcapFile.new.file_to_array(:filename => pcap_file)
41     @tor_relays = tor_relays
42     ipv4_tcp_packets = []
43     ipv4_nontcp_packets = []
44     ipv6_packets = []
45     nonip_packets = []
46     packets.each do |p|
47       if PacketFu::TCPPacket.can_parse?(p)
48         ipv4_tcp_packets << PacketFu::TCPPacket.parse(p)
49       elsif PacketFu::IPPacket.can_parse?(p)
50         ipv4_nontcp_packets << PacketFu::IPPacket.parse(p)
51       elsif PacketFu::IPv6Packet.can_parse?(p)
52         ipv6_packets << PacketFu::IPv6Packet.parse(p)
53       elsif PacketFu::Packet.can_parse?(p)
54         nonip_packets << PacketFu::Packet.parse(p)
55       else
56         save_pcap_file
57         raise "Found something in the pcap file that cannot be parsed"
58       end
59     end
60     ipv4_tcp_hosts = get_public_hosts_from_ippackets ipv4_tcp_packets
61     tor_nodes = Set.new(get_all_tor_contacts)
62     @ipv4_tcp_leaks = ipv4_tcp_hosts.select{|host| !tor_nodes.member?(host)}
63     @ipv4_nontcp_leaks = get_public_hosts_from_ippackets ipv4_nontcp_packets
64     @ipv6_leaks = get_public_hosts_from_ippackets ipv6_packets
65     @nonip_leaks = nonip_packets
66   end
68   # Returns a list of all unique non-LAN destination IP addresses
69   # found in `packets`.
70   def get_public_hosts_from_ippackets(packets)
71     hosts = []
72     packets.each do |p|
73       candidate = nil
74       if p.kind_of?(PacketFu::IPPacket)
75         candidate = p.ip_daddr
76       elsif p.kind_of?(PacketFu::IPv6Packet)
77         candidate = p.ipv6_header.ipv6_daddr
78       else
79         save_pcap_file
80         raise "Expected an IP{v4,v6} packet, but got something else:\n" +
81               p.peek_format
82       end
83       if candidate != nil and IPAddr.new(candidate).public?
84         hosts << candidate
85       end
86     end
87     hosts.uniq
88   end
90   # Returns an array of all Tor relays and authorities, i.e. all
91   # Internet hosts Tails ever should contact.
92   def get_all_tor_contacts
93     @tor_relays + $tor_authorities
94   end
96   def empty?
97     @ipv4_tcp_leaks.empty? and @ipv4_nontcp_leaks.empty? and @ipv6_leaks.empty? and @nonip_leaks.empty?
98   end