packetfu 1.1.11 → 1.1.12.pre

Sign up to get free protection for your applications and to get access to all the features.
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