packetfu 1.1.11 → 1.1.12.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.rspec +2 -0
  4. data/.travis.yml +2 -3
  5. data/README.md +127 -0
  6. data/examples/100kpackets.rb +11 -10
  7. data/examples/ackscan.rb +4 -1
  8. data/examples/arp.rb +4 -5
  9. data/examples/arphood.rb +5 -4
  10. data/examples/dissect_thinger.rb +10 -7
  11. data/examples/ethernet.rb +8 -3
  12. data/examples/ids.rb +22 -4
  13. data/examples/idsv2.rb +25 -6
  14. data/examples/ifconfig.rb +6 -3
  15. data/examples/new-simple-stats.rb +5 -6
  16. data/examples/packetfu-shell.rb +11 -48
  17. data/examples/pcap2pcapng.rb +32 -0
  18. data/examples/simple-sniffer.rb +9 -4
  19. data/examples/simple-stats.rb +7 -8
  20. data/examples/slammer.rb +2 -2
  21. data/examples/uniqpcap.rb +17 -7
  22. data/lib/packetfu.rb +10 -175
  23. data/lib/packetfu/capture.rb +2 -2
  24. data/lib/packetfu/common.rb +142 -0
  25. data/lib/packetfu/config.rb +8 -8
  26. data/lib/packetfu/inject.rb +3 -3
  27. data/lib/packetfu/packet.rb +22 -18
  28. data/lib/packetfu/pcap.rb +2 -1
  29. data/lib/packetfu/pcapng.rb +37 -0
  30. data/lib/packetfu/pcapng/block.rb +25 -0
  31. data/lib/packetfu/pcapng/epb.rb +112 -0
  32. data/lib/packetfu/pcapng/file.rb +316 -0
  33. data/lib/packetfu/pcapng/idb.rb +125 -0
  34. data/lib/packetfu/pcapng/shb.rb +146 -0
  35. data/lib/packetfu/pcapng/spb.rb +83 -0
  36. data/lib/packetfu/pcapng/unknown_block.rb +60 -0
  37. data/lib/packetfu/protos.rb +3 -0
  38. data/lib/packetfu/protos/arp.rb +10 -10
  39. data/lib/packetfu/protos/icmpv6.rb +131 -0
  40. data/lib/packetfu/protos/icmpv6/header.rb +69 -0
  41. data/lib/packetfu/protos/icmpv6/mixin.rb +14 -0
  42. data/lib/packetfu/protos/ip.rb +4 -5
  43. data/lib/packetfu/protos/ipv6/header.rb +2 -0
  44. data/lib/packetfu/protos/udp.rb +24 -12
  45. data/lib/packetfu/structfu.rb +27 -0
  46. data/lib/packetfu/utils.rb +55 -9
  47. data/lib/packetfu/version.rb +1 -1
  48. data/packetfu.gemspec +13 -7
  49. data/spec/arp_spec.rb +11 -5
  50. data/spec/eth_spec.rb +20 -11
  51. data/spec/fake_packets.rb +28 -0
  52. data/spec/hsrp_spec.rb +15 -0
  53. data/spec/icmp_spec.rb +12 -5
  54. data/spec/icmpv6_spec.rb +98 -0
  55. data/spec/invalid_spec.rb +28 -0
  56. data/spec/ip_spec.rb +10 -5
  57. data/spec/ipv4_icmp.pcap +0 -0
  58. data/spec/ipv4_udp.pcap +0 -0
  59. data/spec/ipv6_icmp.pcap +0 -0
  60. data/spec/ipv6_spec.rb +4 -0
  61. data/spec/ipv6_udp.pcap +0 -0
  62. data/spec/lldp_spec.rb +36 -0
  63. data/spec/octets_spec.rb +43 -0
  64. data/spec/packet_spec.rb +24 -0
  65. data/spec/packetfu_spec.rb +6 -1
  66. data/spec/pcap_spec.rb +286 -0
  67. data/spec/pcapng/epb_spec.rb +81 -0
  68. data/spec/pcapng/file_spec.rb +295 -0
  69. data/spec/pcapng/file_spec_helper.rb +45 -0
  70. data/spec/pcapng/idb_spec.rb +53 -0
  71. data/spec/pcapng/shb_spec.rb +42 -0
  72. data/spec/pcapng/spb_spec.rb +43 -0
  73. data/spec/pcapng/unknown_block_spec.rb +36 -0
  74. data/spec/spec_helper.rb +3 -31
  75. data/spec/tcp_spec.rb +4 -1
  76. data/spec/udp_spec.rb +149 -1
  77. data/spec/utils_spec.rb +98 -15
  78. data/test/pcapng-test/output_be/advanced/test100.pcapng +0 -0
  79. data/test/pcapng-test/output_be/advanced/test100.txt +11 -0
  80. data/test/pcapng-test/output_be/advanced/test101.pcapng +0 -0
  81. data/test/pcapng-test/output_be/advanced/test101.txt +11 -0
  82. data/test/pcapng-test/output_be/advanced/test102.pcapng +0 -0
  83. data/test/pcapng-test/output_be/advanced/test102.txt +14 -0
  84. data/test/pcapng-test/output_be/basic/test001.pcapng +0 -0
  85. data/test/pcapng-test/output_be/basic/test001.txt +9 -0
  86. data/test/pcapng-test/output_be/basic/test002.pcapng +0 -0
  87. data/test/pcapng-test/output_be/basic/test002.txt +7 -0
  88. data/test/pcapng-test/output_be/basic/test003.pcapng +0 -0
  89. data/test/pcapng-test/output_be/basic/test003.txt +8 -0
  90. data/test/pcapng-test/output_be/basic/test004.pcapng +0 -0
  91. data/test/pcapng-test/output_be/basic/test004.txt +9 -0
  92. data/test/pcapng-test/output_be/basic/test005.pcapng +0 -0
  93. data/test/pcapng-test/output_be/basic/test005.txt +9 -0
  94. data/test/pcapng-test/output_be/basic/test006.pcapng +0 -0
  95. data/test/pcapng-test/output_be/basic/test006.txt +9 -0
  96. data/test/pcapng-test/output_be/basic/test007.pcapng +0 -0
  97. data/test/pcapng-test/output_be/basic/test007.txt +9 -0
  98. data/test/pcapng-test/output_be/basic/test008.pcapng +0 -0
  99. data/test/pcapng-test/output_be/basic/test008.txt +9 -0
  100. data/test/pcapng-test/output_be/basic/test009.pcapng +0 -0
  101. data/test/pcapng-test/output_be/basic/test009.txt +9 -0
  102. data/test/pcapng-test/output_be/basic/test010.pcapng +0 -0
  103. data/test/pcapng-test/output_be/basic/test010.txt +9 -0
  104. data/test/pcapng-test/output_be/basic/test011.pcapng +0 -0
  105. data/test/pcapng-test/output_be/basic/test011.txt +10 -0
  106. data/test/pcapng-test/output_be/basic/test012.pcapng +0 -0
  107. data/test/pcapng-test/output_be/basic/test012.txt +10 -0
  108. data/test/pcapng-test/output_be/basic/test013.pcapng +0 -0
  109. data/test/pcapng-test/output_be/basic/test013.txt +9 -0
  110. data/test/pcapng-test/output_be/basic/test014.pcapng +0 -0
  111. data/test/pcapng-test/output_be/basic/test014.txt +9 -0
  112. data/test/pcapng-test/output_be/basic/test015.pcapng +0 -0
  113. data/test/pcapng-test/output_be/basic/test015.txt +9 -0
  114. data/test/pcapng-test/output_be/basic/test016.pcapng +0 -0
  115. data/test/pcapng-test/output_be/basic/test016.txt +11 -0
  116. data/test/pcapng-test/output_be/basic/test017.pcapng +0 -0
  117. data/test/pcapng-test/output_be/basic/test017.txt +9 -0
  118. data/test/pcapng-test/output_be/basic/test018.pcapng +0 -0
  119. data/test/pcapng-test/output_be/basic/test018.txt +12 -0
  120. data/test/pcapng-test/output_be/difficult/test200.pcapng +0 -0
  121. data/test/pcapng-test/output_be/difficult/test200.txt +8 -0
  122. data/test/pcapng-test/output_be/difficult/test201.pcapng +0 -0
  123. data/test/pcapng-test/output_be/difficult/test201.txt +11 -0
  124. data/test/pcapng-test/output_be/difficult/test202.pcapng +0 -0
  125. data/test/pcapng-test/output_be/difficult/test202.txt +14 -0
  126. data/test/pcapng-test/output_le/advanced/test100.pcapng +0 -0
  127. data/test/pcapng-test/output_le/advanced/test100.txt +11 -0
  128. data/test/pcapng-test/output_le/advanced/test101.pcapng +0 -0
  129. data/test/pcapng-test/output_le/advanced/test101.txt +11 -0
  130. data/test/pcapng-test/output_le/advanced/test102.pcapng +0 -0
  131. data/test/pcapng-test/output_le/advanced/test102.txt +14 -0
  132. data/test/pcapng-test/output_le/basic/test001.pcapng +0 -0
  133. data/test/pcapng-test/output_le/basic/test001.txt +9 -0
  134. data/test/pcapng-test/output_le/basic/test002.pcapng +0 -0
  135. data/test/pcapng-test/output_le/basic/test002.txt +7 -0
  136. data/test/pcapng-test/output_le/basic/test003.pcapng +0 -0
  137. data/test/pcapng-test/output_le/basic/test003.txt +8 -0
  138. data/test/pcapng-test/output_le/basic/test004.pcapng +0 -0
  139. data/test/pcapng-test/output_le/basic/test004.txt +9 -0
  140. data/test/pcapng-test/output_le/basic/test005.pcapng +0 -0
  141. data/test/pcapng-test/output_le/basic/test005.txt +9 -0
  142. data/test/pcapng-test/output_le/basic/test006.pcapng +0 -0
  143. data/test/pcapng-test/output_le/basic/test006.txt +9 -0
  144. data/test/pcapng-test/output_le/basic/test007.pcapng +0 -0
  145. data/test/pcapng-test/output_le/basic/test007.txt +9 -0
  146. data/test/pcapng-test/output_le/basic/test008.pcapng +0 -0
  147. data/test/pcapng-test/output_le/basic/test008.txt +9 -0
  148. data/test/pcapng-test/output_le/basic/test009.pcapng +0 -0
  149. data/test/pcapng-test/output_le/basic/test009.txt +9 -0
  150. data/test/pcapng-test/output_le/basic/test010.pcapng +0 -0
  151. data/test/pcapng-test/output_le/basic/test010.txt +9 -0
  152. data/test/pcapng-test/output_le/basic/test011.pcapng +0 -0
  153. data/test/pcapng-test/output_le/basic/test011.txt +10 -0
  154. data/test/pcapng-test/output_le/basic/test012.pcapng +0 -0
  155. data/test/pcapng-test/output_le/basic/test012.txt +10 -0
  156. data/test/pcapng-test/output_le/basic/test013.pcapng +0 -0
  157. data/test/pcapng-test/output_le/basic/test013.txt +9 -0
  158. data/test/pcapng-test/output_le/basic/test014.pcapng +0 -0
  159. data/test/pcapng-test/output_le/basic/test014.txt +9 -0
  160. data/test/pcapng-test/output_le/basic/test015.pcapng +0 -0
  161. data/test/pcapng-test/output_le/basic/test015.txt +9 -0
  162. data/test/pcapng-test/output_le/basic/test016.pcapng +0 -0
  163. data/test/pcapng-test/output_le/basic/test016.txt +11 -0
  164. data/test/pcapng-test/output_le/basic/test017.pcapng +0 -0
  165. data/test/pcapng-test/output_le/basic/test017.txt +9 -0
  166. data/test/pcapng-test/output_le/basic/test018.pcapng +0 -0
  167. data/test/pcapng-test/output_le/basic/test018.txt +12 -0
  168. data/test/pcapng-test/output_le/difficult/test200.pcapng +0 -0
  169. data/test/pcapng-test/output_le/difficult/test200.txt +8 -0
  170. data/test/pcapng-test/output_le/difficult/test201.pcapng +0 -0
  171. data/test/pcapng-test/output_le/difficult/test201.txt +11 -0
  172. data/test/pcapng-test/output_le/difficult/test202.pcapng +0 -0
  173. data/test/pcapng-test/output_le/difficult/test202.txt +14 -0
  174. data/test/sample-ipv6.pcapng +0 -0
  175. data/test/sample-spb.pcapng +0 -0
  176. data/test/sample.pcapng +0 -0
  177. data/test/sample2.pcapng +0 -0
  178. metadata +190 -68
  179. checksums.yaml.gz.sig +0 -0
  180. data.tar.gz.sig +0 -2
  181. data/INSTALL.rdoc +0 -40
  182. data/README.rdoc +0 -64
  183. data/examples/examples.rb +0 -4
  184. data/setup.rb +0 -1586
  185. data/test/func_lldp.rb +0 -25
  186. data/test/ptest.rb +0 -16
  187. data/test/test_eth.rb +0 -93
  188. data/test/test_hsrp.rb +0 -20
  189. data/test/test_invalid.rb +0 -28
  190. data/test/test_octets.rb +0 -36
  191. data/test/test_pcap.rb +0 -211
  192. data/test/test_udp.rb +0 -100
  193. metadata.gz.sig +0 -2
@@ -1,4 +1,12 @@
1
1
  require 'spec_helper'
2
+ require 'packetfu/packet'
3
+ require 'packetfu/pcap'
4
+ require 'packetfu/protos/eth'
5
+ require 'packetfu/protos/ip'
6
+ require 'packetfu/protos/ipv6'
7
+ require 'packetfu/protos/tcp'
8
+ require 'packetfu/protos/icmp'
9
+ require 'fake_packets'
2
10
 
3
11
  describe PacketFu::Packet, "abstract packet class behavior" do
4
12
 
@@ -72,4 +80,20 @@ describe PacketFu::Packet, "abstract packet class behavior" do
72
80
  p7.should == p6
73
81
  end
74
82
 
83
+ it "should parse IPv4 packets" do
84
+ packets = PacketFu::PcapFile.read(File.join(File.dirname(__FILE__), 'ipv4_icmp.pcap'))
85
+ packets.size.should == 1
86
+ packet = PacketFu::Packet.parse(packets.first.data.to_s)
87
+ packet.should be_a(PacketFu::ICMPPacket)
88
+ packet.headers[1].should be_a(PacketFu::IPHeader)
89
+ end
90
+
91
+ it "should parse IPv6 packets" do
92
+ packets = PacketFu::PcapFile.read(File.join(File.dirname(__FILE__), 'ipv6_udp.pcap'))
93
+ packets.size.should == 1
94
+ packet = PacketFu::Packet.parse(packets.first.data.to_s)
95
+ packet.should be_a(PacketFu::UDPPacket)
96
+ packet.headers[1].should be_a(PacketFu::IPv6Header)
97
+ end
98
+
75
99
  end
@@ -1,4 +1,9 @@
1
1
  require 'spec_helper'
2
+ require 'packetfu/protos/eth'
3
+ require 'packetfu/protos/ip'
4
+ require 'packetfu/protos/tcp'
5
+ require 'packetfu/version'
6
+ require 'fake_packets'
2
7
 
3
8
  describe PacketFu, "version information" do
4
9
  it "reports a version number" do
@@ -49,7 +54,7 @@ describe PacketFu, "protocol requires" do
49
54
  PacketFu::EthPacket.should_not be_nil
50
55
  PacketFu::IPPacket.should_not be_nil
51
56
  PacketFu::TCPPacket.should_not be_nil
52
- expect { PacketFu::FakePacket }.to raise_error(NameError, "uninitialized constant PacketFu::FakePacket")
57
+ expect { PacketFu::FakePacket }.to raise_error(NameError, /uninitialized constant PacketFu::FakePacket/)
53
58
  end
54
59
  end
55
60
 
@@ -0,0 +1,286 @@
1
+ # -*- coding: binary -*-
2
+ require 'spec_helper'
3
+ require 'packetfu'
4
+ require 'tempfile'
5
+ require 'digest/md5'
6
+
7
+ include PacketFu
8
+
9
+ describe PcapHeader do
10
+ before(:all) do
11
+ @file = File.open("test/sample.pcap") {|f| f.read}
12
+ @file.force_encoding "binary" if @file.respond_to? :force_encoding
13
+ @file_magic = @file[0,4]
14
+ @file_header = @file[0,24]
15
+ end
16
+
17
+ context "when initializing" do
18
+ it "should be a good sample file" do
19
+ expect(@file_magic).to eql("\xd4\xc3\xb2\xa1")
20
+ end
21
+
22
+ it "should have sane defaults (little)" do
23
+ @pcap_header = PcapHeader.new
24
+ expect(@pcap_header.sz).to eql(24)
25
+ expect(@pcap_header.endian).to eql(:little)
26
+ expect(@pcap_header.magic).to eql(StructFu::Int32le.new(2712847316))
27
+ expect(@pcap_header.ver_major).to eql(StructFu::Int16le.new(2))
28
+ expect(@pcap_header.ver_minor).to eql(StructFu::Int16le.new(4))
29
+ expect(@pcap_header.thiszone).to eql(StructFu::Int32le.new)
30
+ expect(@pcap_header.sigfigs).to eql(StructFu::Int32le.new)
31
+ expect(@pcap_header.snaplen).to eql(StructFu::Int32le.new(65535))
32
+ expect(@pcap_header.network).to eql(StructFu::Int32le.new(1))
33
+ expect(@pcap_header.to_s[0,4]).to eql("\xD4\xC3\xB2\xA1")
34
+ expect(@pcap_header.to_s[0,4]).to eql(@file_magic)
35
+ expect(@pcap_header.to_s[0,24]).to eql("\xD4\xC3\xB2\xA1\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00\x01\x00\x00\x00")
36
+ expect(@pcap_header.to_s[0,24]).to eql(@file_header)
37
+ end
38
+
39
+ it "should have sane defaults (big)" do
40
+ @pcap_header = PcapHeader.new(:endian => :big)
41
+ expect(@pcap_header.sz).to eql(24)
42
+ expect(@pcap_header.endian).to eql(:big)
43
+ expect(@pcap_header.magic).to eql(StructFu::Int32be.new(2712847316, :big))
44
+ expect(@pcap_header.ver_major).to eql(StructFu::Int16be.new(2))
45
+ expect(@pcap_header.ver_minor).to eql(StructFu::Int16be.new(4))
46
+ expect(@pcap_header.thiszone).to eql(StructFu::Int32be.new)
47
+ expect(@pcap_header.sigfigs).to eql(StructFu::Int32be.new)
48
+ expect(@pcap_header.snaplen).to eql(StructFu::Int32be.new(65535))
49
+ expect(@pcap_header.network).to eql(StructFu::Int32be.new(1))
50
+ expect(@pcap_header.to_s[0,4]).to eql("\xA1\xB2\xC3\xD4")
51
+ expect(@pcap_header.to_s[0,24]).to eql("\xA1\xB2\xC3\xD4\x00\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00\x00\x01")
52
+ end
53
+
54
+ it "should error on bad endian type" do
55
+ # We want to ensure our endianness is little or big.
56
+ expect{PcapHeader.new(:endian => :just_right)}.to raise_error(ArgumentError)
57
+ end
58
+ end
59
+
60
+ context "when reading from string" do
61
+ it "should be a good sample file" do
62
+ @pcap_header = PcapHeader.new()
63
+ @pcap_header.read(@file)
64
+ expect(@pcap_header.to_s).to eql(@file_header)
65
+ end
66
+ end
67
+ end
68
+
69
+ describe Timestamp do
70
+ before(:all) do
71
+ @file = File.open("test/sample.pcap") {|f| f.read}
72
+ @ts = @file[24,8]
73
+ end
74
+
75
+ context "when initializing" do
76
+ it "should have sane defaults" do
77
+ expect(Timestamp.new.size).to eql(3)
78
+ expect(Timestamp.new.sz).to eql(8)
79
+ end
80
+ end
81
+
82
+ context "when reading" do
83
+ it "should parse from a string" do
84
+ timestamp = Timestamp.new
85
+ timestamp.read(@ts)
86
+ expect(timestamp.to_s).to eql(@ts)
87
+ end
88
+ end
89
+ end
90
+
91
+ describe PcapPacket do
92
+ before(:all) do
93
+ @file = File.open('test/sample.pcap') {|f| f.read}
94
+ @file.force_encoding "binary" if @file.respond_to? :force_encoding
95
+ @header = @file[0,24]
96
+ @packet = @file[24,100] # pkt is 78 bytes + 16 bytes pcap hdr == 94
97
+ end
98
+
99
+ context "when initializing" do
100
+ it "should have sane defaults" do
101
+ pcap_packet = PcapPacket.new(:endian => :little)
102
+ expect(pcap_packet.endian).to eql(:little)
103
+ expect(pcap_packet.timestamp).to eql(PacketFu::Timestamp.new(:endian => :little))
104
+ expect(pcap_packet.incl_len).to eql(StructFu::Int32le.new(0))
105
+ expect(pcap_packet.orig_len).to eql(StructFu::Int32le.new)
106
+ expect(pcap_packet.data).to eql("")
107
+ end
108
+ end
109
+
110
+ context "when reading" do
111
+ it "should parse from a string" do
112
+ pcap_packet = PcapPacket.new :endian => :little
113
+ pcap_packet.read(@packet)
114
+ expect(pcap_packet.endian).to eql(:little)
115
+ expect(pcap_packet.timestamp).to eql(
116
+ PacketFu::Timestamp.new(
117
+ :endian => :little,
118
+ :sec => 1255289346,
119
+ :usec => 244202
120
+ )
121
+ )
122
+ expect(pcap_packet.incl_len).to eql(StructFu::Int32le.new(78))
123
+ expect(pcap_packet.orig_len).to eql(StructFu::Int32le.new(78))
124
+ expect(pcap_packet.data).to eql(
125
+ "\x00\x03/\x1At\xDE\x00\e\x11Q\xB7\xCE\b\x00E\x00\x00@\"" +
126
+ "\xB4\x00\x00\x80\x11\x94=\xC0\xA8\x01i\xC0\xA8\x01\x02" +
127
+ "\xD7\xDD\x005\x00,\x8B\xF8\xA6?\x01\x00\x00\x01\x00\x00" +
128
+ "\x00\x00\x00\x00\x03www\nmetasploit\x03com\x00\x00\x01" +
129
+ "\x00\x01"
130
+ )
131
+
132
+ expect(pcap_packet[:incl_len].to_i).to eql(78)
133
+ expect(pcap_packet.to_s).to eql(@packet[0,94])
134
+ end
135
+ end
136
+ end
137
+
138
+ describe PcapPackets do
139
+ before(:all) do
140
+ @file = File.open('test/sample.pcap') {|f| f.read}
141
+ end
142
+
143
+ context "when initializing" do
144
+ it "should have sane defaults" do
145
+ pcap_packets = PcapPackets.new()
146
+ expect(pcap_packets.endian).to eql(:little)
147
+ expect(pcap_packets.size).to eql(0)
148
+ expect(pcap_packets).to be_kind_of(Array)
149
+ end
150
+ end
151
+
152
+ context "when reading" do
153
+ it "should have read pcap packets" do
154
+ pcap_packets = PcapPackets.new()
155
+ pcap_packets.read @file
156
+ expect(pcap_packets.size).to eql(11)
157
+ expect(pcap_packets.size).to eql(11)
158
+ expect(pcap_packets.to_s).to eql(@file[24,@file.size])
159
+ end
160
+ end
161
+ end
162
+
163
+ describe PcapFile do
164
+ before(:all) do
165
+ @file = File.open('test/sample.pcap') {|f| f.read}
166
+ @md5 = '1be3b5082bb135c6f22de8801feb3495'
167
+ end
168
+
169
+ context "when initializing" do
170
+ it "should have sane defaults" do
171
+ pcap_file = PcapFile.new()
172
+ expect(pcap_file.endian).to eql(nil)
173
+ expect(pcap_file.head).to eql(PcapHeader.new)
174
+ expect(pcap_file.body).to eql(PcapPackets.new)
175
+ end
176
+ end
177
+
178
+ context "when reading and writing" do
179
+ before(:each) { @temp_file = Tempfile.new('pcap_pcap') }
180
+ after(:each) { @temp_file.close; @temp_file.unlink }
181
+
182
+ it "should read via #read and write via #to_file" do
183
+ pcap_file = PcapFile.new
184
+ pcap_file.read @file
185
+ pcap_file.to_file(:filename => @temp_file.path)
186
+ newfile = File.open(@temp_file.path) {|f| f.read(f.stat.size)}
187
+ newfile.force_encoding "binary" if newfile.respond_to? :force_encoding
188
+ expect(newfile).to eql(@file)
189
+
190
+ pcap_file.to_file(:filename => @temp_file.path, :append => true)
191
+ packet_array = PcapFile.new.f2a(:filename => @temp_file.path)
192
+ expect(packet_array.size).to eql(22)
193
+ end
194
+
195
+ it "should read via #file_to_array and write via #to_f" do
196
+ # TODO: Figure out why this is failing to write properly when converted to a Tempfile
197
+ File.unlink('out.pcap') if File.exists? 'out.pcap'
198
+ pcaps = PcapFile.new.file_to_array(:filename => 'test/sample.pcap')
199
+ pcaps.each {|pkt|
200
+ packet = Packet.parse pkt
201
+ packet.recalc
202
+ packet.to_f('out.pcap','a')
203
+ }
204
+ packet_array = PcapFile.new.f2a(:filename => 'out.pcap')
205
+ expect(packet_array.size).to eql(11)
206
+ File.unlink('out.pcap')
207
+ end
208
+
209
+ it "should read via #file_to_array and write via #a2f with timestamp changes" do
210
+ pcap_file = PcapFile.new
211
+ packet_array = pcap_file.file_to_array(:filename => 'test/sample.pcap')
212
+ expect(packet_array.size).to eql(11)
213
+
214
+ pcap_file = PcapFile.new
215
+ pcap_file.a2f(:array => packet_array, :f => @temp_file.path, :ts_inc => 4,
216
+ :timestamp => Time.now.to_i - 1_000_000)
217
+ diff_time = pcap_file.body[0].timestamp.sec.to_i - pcap_file.body[1].timestamp.sec.to_i
218
+ expect(diff_time).to eql(-4)
219
+
220
+ packet_array_2 = pcap_file.file_to_array(:filename => @temp_file.path)
221
+ expect(packet_array_2.size).to eql(11)
222
+ end
223
+ end
224
+
225
+ end
226
+
227
+ describe Read do
228
+ context "when initializing" do
229
+ it "should have sane defaults" do
230
+ pcap_packets = Read.new()
231
+ expect(pcap_packets).to be_kind_of(Read)
232
+ end
233
+ end
234
+
235
+ context "when reading" do
236
+ it "should read from a string" do
237
+ pkts = Read.file_to_array(:file => 'test/sample.pcap')
238
+ expect(pkts).to be_kind_of(Array)
239
+ expect(pkts.size).to eql(11)
240
+
241
+ this_packet = Packet.parse pkts[0]
242
+ expect(this_packet).to be_kind_of(UDPPacket)
243
+
244
+ that_packet = Packet.parse pkts[3]
245
+ expect(that_packet).to be_kind_of(ICMPPacket)
246
+ end
247
+
248
+ it "should read from a hash" do
249
+ pkts = Read.file_to_array(:file => 'test/sample.pcap', :ts => true)
250
+ expect(pkts).to be_kind_of(Array)
251
+ expect(pkts.size).to eql(11)
252
+
253
+ this_packet = Packet.parse pkts[0].values.first
254
+ expect(this_packet).to be_kind_of(UDPPacket)
255
+
256
+ that_packet = Packet.parse pkts[3].values.first
257
+ expect(that_packet).to be_kind_of(ICMPPacket)
258
+ end
259
+ end
260
+ end
261
+
262
+ describe Write do
263
+ context "when initializing" do
264
+ it "should have sane defaults" do
265
+ pcap_packets = Write.new()
266
+ expect(pcap_packets).to be_kind_of(Write)
267
+ end
268
+ end
269
+
270
+ context "when writing" do
271
+ before(:each) { @temp_file = Tempfile.new('write_pcap') }
272
+ after(:each) { @temp_file.close; @temp_file.unlink }
273
+
274
+ it "should read from a string" do
275
+ pkts = Read.file_to_array(:file => 'test/sample.pcap')
276
+ expect(pkts).to be_kind_of(Array)
277
+ expect(pkts.size).to eql(11)
278
+
279
+ Write.array_to_file(:array => pkts, :file => @temp_file.path)
280
+
281
+ pkts_new = Read.file_to_array(:file => @temp_file.path)
282
+ expect(pkts).to be_kind_of(Array)
283
+ expect(pkts.size).to eql(11)
284
+ end
285
+ end
286
+ end
@@ -0,0 +1,81 @@
1
+ # -*- coding: binary -*-
2
+ require 'spec_helper'
3
+ require 'packetfu'
4
+
5
+ module PacketFu
6
+ module PcapNG
7
+ describe EPB do
8
+ before(:each) { @epb = EPB.new }
9
+
10
+ it 'should have correct initialization values' do
11
+ expect(@epb).to be_a(EPB)
12
+ expect(@epb.endian).to eq(:little)
13
+ expect(@epb.type.to_i).to eq(PcapNG::EPB_TYPE.to_i)
14
+ expect(@epb.interface_id.to_i).to eq(0)
15
+ expect(@epb.tsh.to_i).to eq(0)
16
+ expect(@epb.tsl.to_i).to eq(0)
17
+ expect(@epb.cap_len.to_i).to eq(0)
18
+ expect(@epb.orig_len.to_i).to eq(0)
19
+ expect(@epb.block_len.to_i).to eq(EPB::MIN_SIZE)
20
+ expect(@epb.block_len2).to eq(@epb.block_len)
21
+ end
22
+
23
+ context 'when reading' do
24
+ it 'should accept a String' do
25
+ str = ::File.read(::File.join(__dir__, '../..', 'test', 'sample.pcapng'))[84, 112]
26
+ expect { @epb.read(str) }.to_not raise_error
27
+ expect(@epb.type.to_i).to eq(PcapNG::EPB_TYPE.to_i)
28
+ expect(@epb.block_len.to_i).to eq(112)
29
+ expect(@epb.interface_id.to_i).to eq(0)
30
+ expect(@epb.tsh.to_i).to eq(0x475ad)
31
+ expect(@epb.tsl.to_i).to eq(0xd392be6a)
32
+ expect(@epb.cap_len.to_i).to eq(78)
33
+ expect(@epb.orig_len.to_i).to eq(@epb.cap_len.to_i)
34
+ expect(@epb.has_options?).to be(false)
35
+ end
36
+
37
+ it 'should accept an IO' do
38
+ ::File.open(::File.join(__dir__, '../..', 'test', 'sample.pcapng')) do |f|
39
+ f.seek(84, :CUR)
40
+ @epb.read f
41
+ end
42
+ expect(@epb.type.to_i).to eq(PcapNG::EPB_TYPE.to_i)
43
+ expect(@epb.block_len.to_i).to eq(112)
44
+ expect(@epb.interface_id.to_i).to eq(0)
45
+ expect(@epb.tsh.to_i).to eq(0x475ad)
46
+ expect(@epb.tsl.to_i).to eq(0xd392be6a)
47
+ expect(@epb.cap_len.to_i).to eq(78)
48
+ expect(@epb.orig_len.to_i).to eq(@epb.cap_len.to_i)
49
+ expect(@epb.has_options?).to be(false)
50
+ end
51
+
52
+ end
53
+
54
+ it 'should decode packet timestamp with default resolution' do
55
+ ::File.open(::File.join(__dir__, '../..', 'test', 'sample.pcapng')) do |f|
56
+ f.seek(84, :CUR)
57
+ @epb.read f
58
+ end
59
+
60
+ expect(@epb.timestamp.round).to eq(Time.utc(2009, 10, 11, 19, 29, 6))
61
+ end
62
+
63
+ it 'should decode packet timestamp with interface resolution' do
64
+ ::File.open(::File.join(__dir__, '../..', 'test', 'sample.pcapng')) do |f|
65
+ f.seek(84, :CUR)
66
+ @epb.read f
67
+ end
68
+
69
+ idb = IDB.new
70
+ ::File.open(::File.join(__dir__, '../..', 'test', 'sample.pcapng')) do |f|
71
+ f.seek(52, :CUR)
72
+ idb.read f
73
+ end
74
+ idb << @epb
75
+ @epb.interface = idb
76
+
77
+ expect(@epb.timestamp.round).to eq(Time.utc(2009, 10, 11, 19, 29, 6))
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,295 @@
1
+ # -*- coding: binary -*-
2
+ require 'tempfile'
3
+ require 'spec_helper'
4
+ require 'packetfu'
5
+ require_relative 'file_spec_helper'
6
+
7
+ module PacketFu
8
+ module PcapNG
9
+ describe File do
10
+ before(:all) do
11
+ @file = ::File.join(__dir__, '../..', 'test', 'sample.pcapng')
12
+ @file_spb = ::File.join(__dir__, '../..', 'test', 'sample-spb.pcapng')
13
+ end
14
+ before(:each) { @pcapng = File.new }
15
+
16
+ context '#readfile' do
17
+ it 'reads a Pcap-NG file' do
18
+ @pcapng.readfile @file
19
+ expect(@pcapng.sections.size).to eq(1)
20
+ expect(@pcapng.sections[0].unknown_blocks.size).to eq(0)
21
+
22
+ expect(@pcapng.sections.first.interfaces.size).to eq(1)
23
+ intf = @pcapng.sections.first.interfaces.first
24
+ expect(intf.section).to eq(@pcapng.sections.first)
25
+
26
+ expect(intf.packets.size).to eq(11)
27
+ packet = intf.packets.first
28
+ expect(packet.interface).to eq(intf)
29
+ end
30
+
31
+ it 'reads a Pcap-NG file with Simple Packet blocks' do
32
+ @pcapng.readfile @file_spb
33
+ expect(@pcapng.sections.size).to eq(1)
34
+ expect(@pcapng.sections[0].unknown_blocks.size).to eq(0)
35
+ expect(@pcapng.sections.first.interfaces.size).to eq(1)
36
+ intf = @pcapng.sections.first.interfaces.first
37
+ expect(intf.section).to eq(@pcapng.sections.first)
38
+ expect(intf.packets.size).to eq(4)
39
+ expect(intf.snaplen.to_i).to eq(0)
40
+ packet = intf.packets.first
41
+ expect(packet.interface).to eq(intf)
42
+ expect(packet.data.size).to eq(packet.orig_len.to_i)
43
+ end
44
+
45
+ it 'yields xPB object per read packet' do
46
+ idx = 0
47
+ @pcapng.readfile(@file) do |pkt|
48
+ expect(pkt).to be_a(@Pcapng::EPB)
49
+ idx += 1
50
+ end
51
+ expect(idx).to eq(11)
52
+ end
53
+
54
+ it 'reads many kinds of pcapng file' do
55
+ [:little, :big].each do |endian|
56
+ base_dir = ::File.join(__dir__, '..', '..', 'test', 'pcapng-test',
57
+ endian == :little ? 'output_le' : 'output_be')
58
+ PCAPNG_TEST_FILES.each do |file, sections|
59
+ next if file == 'difficult/test202.pcapng'
60
+ @pcapng.clear
61
+ @pcapng.readfile ::File.join(base_dir, file)
62
+ expect(@pcapng.sections[0].endian).to eq(endian)
63
+ expect(@pcapng.sections.size).to eq(sections.size)
64
+ sections.each_with_index do |section, i|
65
+ expect(@pcapng.sections[i].unknown_blocks.size).to eq(section[:unknown])
66
+ expect(@pcapng.sections[i].interfaces.size).to eq(section[:idb])
67
+ packets = @pcapng.sections[i].interfaces.map(&:packets).flatten
68
+ expect(packets.grep(EPB).size).to eq(section[:epb])
69
+ expect(packets.grep(SPB).size).to eq(section[:spb])
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ it 'reads a file with different sections, with different endians' do
76
+ sections = PCAPNG_TEST_FILES['difficult/test202.pcapng']
77
+ [:little, :big].each do |endian|
78
+ other_endian = endian == :little ? :big : :little
79
+ base_dir = ::File.join(__dir__, '..', '..', 'test', 'pcapng-test',
80
+ endian == :little ? 'output_le' : 'output_be')
81
+
82
+ @pcapng.clear
83
+ @pcapng.readfile ::File.join(base_dir, 'difficult', 'test202.pcapng')
84
+
85
+ expect(@pcapng.sections.size).to eq(sections.size)
86
+ expect(@pcapng.sections[0].endian).to eq(endian)
87
+ expect(@pcapng.sections[1].endian).to eq(other_endian)
88
+ expect(@pcapng.sections[2].endian).to eq(endian)
89
+ sections.each_with_index do |section, i|
90
+ expect(@pcapng.sections[i].unknown_blocks.size).to eq(section[:unknown])
91
+ expect(@pcapng.sections[i].interfaces.size).to eq(section[:idb])
92
+ @pcapng.sections[i].unknown_blocks.each do |block|
93
+ expect(block.endian).to eq(@pcapng.sections[i].endian)
94
+ end
95
+ @pcapng.sections[i].interfaces.each do |interface|
96
+ expect(interface.endian).to eq(@pcapng.sections[i].endian)
97
+ interface.packets.each do |packet|
98
+ expect(packet.endian).to eq(@pcapng.sections[i].endian)
99
+ end
100
+ end
101
+ packets = @pcapng.sections[i].interfaces.map(&:packets).flatten
102
+ expect(packets.grep(EPB).size).to eq(section[:epb])
103
+ expect(packets.grep(SPB).size).to eq(section[:spb])
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ context '#read_packets' do
110
+ before(:all) do
111
+ @expected = [UDPPacket] * 2 + [ICMPPacket] * 3 + [ARPPacket] * 2 +
112
+ [TCPPacket] * 3 + [ICMPPacket]
113
+ end
114
+
115
+ it 'returns an array of Packets' do
116
+ packets = @pcapng.read_packets(@file)
117
+ expect(packets.map(&:class)).to eq(@expected)
118
+
119
+ icmp = packets[2]
120
+ expect(icmp.ip_saddr).to eq('192.168.1.105')
121
+ expect(icmp.ip_daddr).to eq('216.75.1.230')
122
+ expect(icmp.icmp_type).to eq(8)
123
+ expect(icmp.icmp_code).to eq(0)
124
+ end
125
+
126
+ it 'yields Packet object per read packet' do
127
+ idx = 0
128
+ @pcapng.read_packets(@file) do |pkt|
129
+ expect(pkt).to be_a(@expected[idx])
130
+ idx += 1
131
+ end
132
+ expect(idx).to eq(11)
133
+ end
134
+ end
135
+
136
+ context '#file_to_array' do
137
+ it 'generates an array from object state' do
138
+ @pcapng.readfile @file
139
+ ary = @pcapng.file_to_array
140
+ expect(ary).to be_a(Array)
141
+ ary.each do |p|
142
+ expect(p).to be_a(String)
143
+ end
144
+ expect(ary[0]).to eq(@pcapng.sections[0].interfaces[0].packets[0].data)
145
+ end
146
+
147
+ it 'generates an array from given file, clearing object state' do
148
+ @pcapng.readfile @file
149
+ ary = @pcapng.file_to_array(filename: @file_spb)
150
+ expect(@pcapng.sections.size).to eq(1)
151
+ expect(@pcapng.sections[0].interfaces[0].packets[0]).to be_a(SPB)
152
+
153
+ expect(ary).to be_a(Array)
154
+ ary.each do |p|
155
+ expect(p).to be_a(String)
156
+ end
157
+ expect(ary[0]).to eq(@pcapng.sections[0].interfaces[0].packets[0].data)
158
+ end
159
+
160
+ it 'generates an array with timestamps' do
161
+ @pcapng.readfile @file
162
+ ary = @pcapng.file_to_array(keep_timestamps: true)
163
+ expect(ary).to be_a(Array)
164
+ ary.each do |p|
165
+ expect(p).to be_a(Hash)
166
+ expect(p.keys.first).to be_a(Time)
167
+ expect(p.values.first).to be_a(String)
168
+ end
169
+
170
+ packet1 = @pcapng.sections[0].interfaces[0].packets[0]
171
+ expect(ary[0].keys.first).to eq(packet1.timestamp)
172
+ expect(ary[0].values.first).to eq(packet1.data)
173
+ end
174
+ end
175
+
176
+ context '#to_file' do
177
+ before(:each) { @write_file = Tempfile.new('pcapng') }
178
+ after(:each) { @write_file.close; @write_file.unlink }
179
+
180
+ it 'creates a file and write self to it' do
181
+ @pcapng.readfile @file
182
+ @pcapng.to_file :filename => @write_file.path
183
+ @write_file.rewind
184
+ expect(@write_file.read).to eq(::File.read(@file))
185
+ end
186
+
187
+ it 'appends a section to an existing file' do
188
+ @pcapng.readfile @file
189
+ @pcapng.to_file :filename => @write_file.path
190
+
191
+ @pcapng.to_file :filename => @write_file.path, :append => true
192
+
193
+ @pcapng.clear
194
+ @pcapng.readfile @write_file.path
195
+ expect(@pcapng.sections.size).to eq(2)
196
+ expect(@pcapng.sections[0].to_s).to eq(@pcapng.sections[1].to_s)
197
+ end
198
+ end
199
+
200
+ context '#array_to_file' do
201
+ before(:each) do
202
+ tmpfile = Tempfile.new('packetfu')
203
+ @tmpfilename = tmpfile.path
204
+ tmpfile.close
205
+ tmpfile.unlink
206
+ end
207
+ after(:each) { ::File.unlink @tmpfilename if ::File.exist? @tmpfilename }
208
+
209
+ it 'gets an array of Packet objects' do
210
+ packets = @pcapng.read_packets(@file)
211
+
212
+ @pcapng.clear
213
+ @pcapng.array_to_file(packets)
214
+ @pcapng.write @tmpfilename
215
+
216
+ @pcapng.clear
217
+ packets2 = @pcapng.read_packets(@tmpfilename)
218
+ expect(packets2.map(&:to_s).join).to eq(packets.map(&:to_s).join)
219
+ end
220
+
221
+ it 'gets a hash containing an array of Packet objects' do
222
+ packets = @pcapng.read_packets(@file)[0..1]
223
+
224
+ @pcapng.clear
225
+ @pcapng.array_to_file(:array => packets)
226
+ @pcapng.write @tmpfilename
227
+
228
+ @pcapng.clear
229
+ packets2 = @pcapng.read_packets(@tmpfilename)
230
+ expect(packets2.map(&:to_s).join).to eq(packets.map(&:to_s).join)
231
+ end
232
+
233
+ it 'gets a hash containing an array of Packet objects and a :timestamp key' do
234
+ packets = @pcapng.read_packets(@file)[0..1]
235
+
236
+ @pcapng.clear
237
+ @pcapng.array_to_file(:array => packets,
238
+ :timestamp => Time.utc(2000, 1, 1),
239
+ :ts_inc => 3600*24)
240
+ @pcapng.write @tmpfilename
241
+
242
+ @pcapng.clear
243
+ @pcapng.readfile(@tmpfilename)
244
+ @pcapng.sections[0].interfaces[0].packets.each_with_index do |pkt, i|
245
+ expect(pkt.data).to eq(packets[i].to_s)
246
+ expect(pkt.timestamp).to eq(Time.utc(2000, 1, 1+i))
247
+ end
248
+ end
249
+
250
+ it 'gets a hash containing couples of Time and Packet objects' do
251
+ packets = @pcapng.read_packets(@file)[0..3]
252
+ timestamp = Time.utc(2000, 1, 1)
253
+ ts_inc = 3600*24 * 2
254
+ array = []
255
+ packets.each_with_index do |pkt, i|
256
+ array << { (timestamp + ts_inc * i) => pkt }
257
+ end
258
+
259
+ @pcapng.clear
260
+ @pcapng.array_to_file(:array => array)
261
+ @pcapng.write @tmpfilename
262
+
263
+ @pcapng.clear
264
+ @pcapng.readfile(@tmpfilename)
265
+ @pcapng.sections[0].interfaces[0].packets.each_with_index do |pkt, i|
266
+ expect(pkt.data).to eq(packets[i].to_s)
267
+ expect(pkt.timestamp).to eq(Time.utc(2000, 1, 1+2*i))
268
+ end
269
+ end
270
+
271
+ it 'gets a hash containing a :filename key' do
272
+ packets = @pcapng.read_packets(@file)[0..2]
273
+
274
+ @pcapng.clear
275
+ @pcapng.array_to_file(:array => packets, :filename => @tmpfilename)
276
+
277
+ @pcapng.clear
278
+ packets2 = @pcapng.read_packets(@tmpfilename)
279
+ expect(packets2.map(&:to_s).join).to eq(packets.map(&:to_s).join)
280
+ end
281
+ end
282
+
283
+ it '#to_s returns object as a String' do
284
+ orig_str = PacketFu.force_binary(::File.read(@file))
285
+ @pcapng.read orig_str
286
+ expect(@pcapng.to_s).to eq(orig_str)
287
+
288
+ @pcapng.clear
289
+ orig_str = PacketFu.force_binary(::File.read(@file_spb))
290
+ @pcapng.read orig_str
291
+ expect(@pcapng.to_s).to eq(orig_str)
292
+ end
293
+ end
294
+ end
295
+ end