packetfu 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.gitignore +3 -0
  2. data/INSTALL.rdoc +40 -0
  3. data/LICENSE.txt +25 -0
  4. data/examples/100kpackets.rb +41 -0
  5. data/examples/ackscan.rb +38 -0
  6. data/examples/arp.rb +60 -0
  7. data/examples/arphood.rb +59 -0
  8. data/examples/dissect_thinger.rb +22 -0
  9. data/examples/ethernet.rb +10 -0
  10. data/examples/examples.rb +3 -0
  11. data/examples/ids.rb +4 -0
  12. data/examples/idsv2.rb +6 -0
  13. data/examples/new-simple-stats.rb +52 -0
  14. data/examples/oui.txt +84177 -0
  15. data/examples/packetfu-shell.rb +113 -0
  16. data/examples/simple-sniffer.rb +40 -0
  17. data/examples/simple-stats.rb +50 -0
  18. data/examples/slammer.rb +33 -0
  19. data/examples/uniqpcap.rb +15 -0
  20. data/lib/packetfu.rb +147 -0
  21. data/lib/packetfu/capture.rb +169 -0
  22. data/lib/packetfu/config.rb +58 -0
  23. data/lib/packetfu/inject.rb +65 -0
  24. data/lib/packetfu/packet.rb +533 -0
  25. data/lib/packetfu/pcap.rb +594 -0
  26. data/lib/packetfu/protos/arp.rb +268 -0
  27. data/lib/packetfu/protos/eth.rb +296 -0
  28. data/lib/packetfu/protos/hsrp.rb +206 -0
  29. data/lib/packetfu/protos/icmp.rb +179 -0
  30. data/lib/packetfu/protos/invalid.rb +55 -0
  31. data/lib/packetfu/protos/ip.rb +378 -0
  32. data/lib/packetfu/protos/ipv6.rb +250 -0
  33. data/lib/packetfu/protos/tcp.rb +1127 -0
  34. data/lib/packetfu/protos/udp.rb +240 -0
  35. data/lib/packetfu/structfu.rb +294 -0
  36. data/lib/packetfu/utils.rb +194 -0
  37. data/lib/packetfu/version.rb +50 -0
  38. data/packetfu.gemspec +21 -0
  39. data/setup.rb +1586 -0
  40. data/test/all_tests.rb +41 -0
  41. data/test/ethpacket_spec.rb +74 -0
  42. data/test/packet_spec.rb +73 -0
  43. data/test/packet_subclasses_spec.rb +13 -0
  44. data/test/packetfu_spec.rb +90 -0
  45. data/test/ptest.rb +16 -0
  46. data/test/sample-ipv6.pcap +0 -0
  47. data/test/sample.pcap +0 -0
  48. data/test/sample2.pcap +0 -0
  49. data/test/sample_hsrp_pcapr.cap +0 -0
  50. data/test/structfu_spec.rb +335 -0
  51. data/test/tcp_spec.rb +101 -0
  52. data/test/test_arp.rb +135 -0
  53. data/test/test_eth.rb +91 -0
  54. data/test/test_hsrp.rb +20 -0
  55. data/test/test_icmp.rb +54 -0
  56. data/test/test_inject.rb +31 -0
  57. data/test/test_invalid.rb +28 -0
  58. data/test/test_ip.rb +69 -0
  59. data/test/test_ip6.rb +68 -0
  60. data/test/test_octets.rb +37 -0
  61. data/test/test_packet.rb +174 -0
  62. data/test/test_pcap.rb +209 -0
  63. data/test/test_structfu.rb +112 -0
  64. data/test/test_tcp.rb +327 -0
  65. data/test/test_udp.rb +73 -0
  66. data/test/vlan-pcapr.cap +0 -0
  67. metadata +85 -6
data/test/tcp_spec.rb ADDED
@@ -0,0 +1,101 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+ require 'packetfu'
3
+
4
+ include PacketFu
5
+
6
+ def unusual_numeric_handling_headers(header,i)
7
+ camelized_header = header.to_s.split("_").map {|x| x.capitalize}.join
8
+ header_class = PacketFu.const_get camelized_header
9
+ specify { subject.send(header).should == i }
10
+ specify { subject.send(header).should be_kind_of Integer }
11
+ specify { subject.headers.last[header].should be_kind_of header_class }
12
+ end
13
+
14
+ def tcp_hlen_numeric(i)
15
+ unusual_numeric_handling_headers(:tcp_hlen,i)
16
+ end
17
+
18
+ def tcp_reserved_numeric(i)
19
+ unusual_numeric_handling_headers(:tcp_reserved,i)
20
+ end
21
+
22
+ def tcp_ecn_numeric(i)
23
+ unusual_numeric_handling_headers(:tcp_ecn,i)
24
+ end
25
+
26
+
27
+ describe TCPPacket do
28
+
29
+ subject do
30
+ bytes = PcapFile.file_to_array("sample2.pcap")[2]
31
+ packet = Packet.parse(bytes)
32
+ end
33
+
34
+ context "TcpHlen reading and setting" do
35
+ context "TcpHlen set via #read" do
36
+ tcp_hlen_numeric(8)
37
+ end
38
+ context "TcpHlen set via an Integer for the setter" do
39
+ (0..15).each do |i|
40
+ context "i is #{i}" do
41
+ before { subject.tcp_hlen = i }
42
+ tcp_hlen_numeric(i)
43
+ end
44
+ end
45
+ end
46
+ context "TcpHlen set via a String for the setter" do
47
+ before { subject.tcp_hlen = "\x60" }
48
+ tcp_hlen_numeric(6)
49
+ end
50
+ context "TcpHlen set via a TcpHlen for the setter" do
51
+ before { subject.tcp_hlen = TcpHlen.new(:hlen => 7) }
52
+ tcp_hlen_numeric(7)
53
+ end
54
+ end
55
+
56
+ context "TcpReserved reading and setting" do
57
+ context "TcpReserved set via #read" do
58
+ tcp_reserved_numeric(0)
59
+ end
60
+ context "TcpReserved set via an Integer for the setter" do
61
+ (0..7).each do |i|
62
+ context "i is #{i}" do
63
+ before { subject.tcp_reserved = i }
64
+ tcp_reserved_numeric(i)
65
+ end
66
+ end
67
+ end
68
+ context "TcpReserved set via a String for the setter" do
69
+ before { subject.tcp_reserved = "\x03" }
70
+ tcp_reserved_numeric(3)
71
+ end
72
+ context "TcpReserved set via a TcpReserved for the setter" do
73
+ before { subject.tcp_reserved = TcpReserved.new(:r1 => 1, :r2 => 0, :r3 => 1) }
74
+ tcp_reserved_numeric(5)
75
+ end
76
+ end
77
+
78
+ context "TcpEcn reading and setting" do
79
+ context "TcpEcn set via #read" do
80
+ tcp_ecn_numeric(0)
81
+ end
82
+ context "TcpEcn set via an Integer for the setter" do
83
+ (0..7).each do |i|
84
+ context "i is #{i}" do
85
+ before { subject.tcp_ecn = i }
86
+ tcp_ecn_numeric(i)
87
+ end
88
+ end
89
+ end
90
+ context "TcpEcn set via a String for the setter" do
91
+ before { subject.tcp_ecn = "\x00\xc0" }
92
+ tcp_ecn_numeric(3)
93
+ end
94
+ context "TcpEcn set via a TcpEcn for the setter" do
95
+ before { subject.tcp_ecn = TcpEcn.new(:n => 1, :c => 0, :e => 1) }
96
+ tcp_ecn_numeric(5)
97
+ end
98
+ end
99
+
100
+ end
101
+
data/test/test_arp.rb ADDED
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
4
+ require 'packetfu'
5
+ class ArpTest < Test::Unit::TestCase
6
+ include PacketFu
7
+
8
+ def test_arp_header
9
+ a = ARPHeader.new
10
+ assert_kind_of ARPHeader, a
11
+ assert_kind_of StructFu::Int16, a[:arp_hw]
12
+ assert_kind_of Fixnum, a.arp_hw
13
+ assert_kind_of Octets, a[:arp_src_ip]
14
+ assert_kind_of String, a.arp_src_ip
15
+ assert_kind_of EthMac, a[:arp_dst_mac]
16
+ assert_kind_of String, a.arp_dst_mac
17
+ assert_kind_of StructFu::String, a.body
18
+ end
19
+
20
+ def test_read_header
21
+ a = ARPHeader.new
22
+ sample_arp = "000108000604000200032f1a74dec0a80102001b1151b7cec0a80169"
23
+ sample_arp = sample_arp.scan(/../).map {|x| x.to_i(16)}.pack("C*")
24
+ a.read(sample_arp)
25
+ assert_equal(sample_arp, a.to_s)
26
+ assert_equal("192.168.1.105", a.arp_daddr_ip)
27
+ assert_equal("192.168.1.2", a.arp_saddr_ip)
28
+ assert_equal("00:1b:11:51:b7:ce", a.arp_daddr_mac)
29
+ assert_equal("00:03:2f:1a:74:de", a.arp_saddr_mac)
30
+ end
31
+
32
+ def test_arp_read
33
+ a = ARPPacket.new
34
+ sample_arp = "001b1151b7ce00032f1a74de0806000108000604000200032f1a74dec0a80102001b1151b7cec0a80169c0a80169"
35
+ sample_arp = sample_arp.scan(/../).map {|x| x.to_i(16)}.pack("C*")
36
+ a.read(sample_arp)
37
+ assert_equal(sample_arp, a.to_s)
38
+ end
39
+
40
+ def test_write_ip
41
+ a = ARPPacket.new
42
+ a.arp_saddr_ip="1.2.3.4"
43
+ a.arp_daddr_ip="5.6.7.8"
44
+ assert_equal("1.2.3.4",a.arp_saddr_ip)
45
+ assert_equal("5.6.7.8",a.arp_daddr_ip)
46
+ assert_equal("\x01\x02\x03\x04",a.arp_src_ip)
47
+ assert_equal("\x05\x06\x07\x08",a.arp_dst_ip)
48
+ end
49
+
50
+ def test_write_mac
51
+ a = ARPPacket.new
52
+ a.arp_saddr_mac = "00:01:02:03:04:05"
53
+ a.arp_daddr_mac = "00:06:07:08:09:0a"
54
+ assert_equal("00:01:02:03:04:05",a.arp_saddr_mac)
55
+ assert_equal("00:06:07:08:09:0a",a.arp_daddr_mac)
56
+ assert_equal("\x00\x01\x02\x03\x04\x05",a.arp_src_mac)
57
+ assert_equal("\x00\x06\x07\x08\x09\x0a",a.arp_dst_mac)
58
+ end
59
+
60
+ def test_arp_flavors
61
+ a = ARPPacket.new(:flavor => "Windows")
62
+ assert_equal("\x00" * 64, a.payload)
63
+ a = ARPPacket.new(:flavor => "Linux")
64
+ assert_equal(32, a.payload.size)
65
+ a = ARPPacket.new(:flavor => :hp_deskjet)
66
+ assert_equal(18, a.payload.size)
67
+ a = ARPPacket.new
68
+ assert_equal("\x00" * 18, a.payload)
69
+ end
70
+
71
+ def test_arp_create
72
+ sample_arp = "000108000604000200032f1a74dec0a80102001b1151b7cec0a80169"
73
+ sample_arp = sample_arp.scan(/../).map {|x| x.to_i(16)}.pack("C*")
74
+ a = ARPPacket.new
75
+ assert_kind_of ARPPacket, a
76
+ a.arp_hw = 1
77
+ a.arp_proto = 0x0800
78
+ a.arp_hw_len = 6
79
+ a.arp_proto_len = 4
80
+ a.arp_opcode = 2
81
+ a.arp_src_mac = "\x00\x03\x2f\x1a\x74\xde"
82
+ a.arp_src_ip = "\xc0\xa8\x01\x02"
83
+ a.arp_dst_mac = "\x00\x1b\x11\x51\xb7\xce"
84
+ a.arp_dst_ip = "\xc0\xa8\x01\x69"
85
+ a.payload = ""
86
+ assert_equal(sample_arp,a.to_s[14,0xffff])
87
+ end
88
+
89
+ def test_arp_new
90
+ sample_arp = "000108000604000200032f1a74dec0a80102001b1151b7cec0a80169c0a80169"
91
+ sample_arp = sample_arp.scan(/../).map {|x| x.to_i(16)}.pack("C*")
92
+ arp = ARPPacket.new(:arp_hw => 1, :arp_proto => 0x0800,
93
+ :arp_opcode => 2, :arp_src_ip => "\xc0\xa8\x01\x02")
94
+ assert_kind_of ARPPacket, arp
95
+ arp.arp_hw_len = 6
96
+ arp.arp_proto_len = 4
97
+ arp.arp_src_mac = "\x00\x03\x2f\x1a\x74\xde"
98
+ arp.arp_dst_mac = "\x00\x1b\x11\x51\xb7\xce"
99
+ arp.arp_dst_ip = "\xc0\xa8\x01\x69"
100
+ arp.payload = "\xc0\xa8\x01\x69"
101
+ assert_equal(sample_arp,arp.to_s[14,0xffff])
102
+ end
103
+
104
+ def test_arp_peek
105
+ a = ARPPacket.new
106
+ puts "\n"
107
+ puts "ARP Peek format: "
108
+ puts a.peek
109
+ puts "\n"
110
+ assert(a.peek.size <= 80)
111
+ end
112
+
113
+ def test_arp_pcap
114
+ a = ARPPacket.new
115
+ assert_kind_of ARPPacket, a
116
+ a.to_f('arp_test.pcap','w')
117
+ a.arp_hw = 1
118
+ a.arp_proto = 0x0800
119
+ a.arp_hw_len = 6
120
+ a.arp_proto_len = 4
121
+ a.arp_opcode = 2
122
+ a.arp_src_mac = "\x00\x03\x2f\x1a\x74\xde"
123
+ a.arp_src_ip = "\xc0\xa8\x01\x02"
124
+ a.arp_dst_mac = "\x00\x1b\x11\x51\xb7\xce"
125
+ a.arp_dst_ip = "\xc0\xa8\x01\x69"
126
+ a.payload = ""
127
+ a.eth_daddr = "00:1b:11:51:b7:ce"
128
+ a.eth_saddr = "00:03:2f:1a:74:de"
129
+ a.to_f('arp_test.pcap','a')
130
+ end
131
+
132
+ end
133
+
134
+
135
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
data/test/test_eth.rb ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
4
+ require 'packetfu'
5
+ puts "Testing #{PacketFu.version}: #{$0}"
6
+
7
+ class EthTest < Test::Unit::TestCase
8
+
9
+ def test_ethmac
10
+ dst = "\x00\x03\x2f\x1a\x74\xde"
11
+ e = PacketFu::EthMac.new
12
+ e.read dst
13
+ assert_equal(dst, e.to_s)
14
+ assert_equal(0x32f, e.oui.oui)
15
+ assert_equal("\x1a\x74\xde", e.nic.to_s)
16
+ assert_equal(222, e.nic.n2)
17
+ end
18
+
19
+ def test_ethmac_ipad
20
+ dst = "\x7c\x6d\x62\x01\x02\x03"
21
+ e = PacketFu::EthMac.new
22
+ e.read dst
23
+ assert_equal(dst, e.to_s)
24
+ assert_equal(0x6d62, e.oui.oui)
25
+ end
26
+
27
+ def test_ethmac_class
28
+ src = "\x00\x1b\x11\x51\xb7\xce"
29
+ e = PacketFu::EthMac.new
30
+ e.read src
31
+ assert_instance_of(PacketFu::EthMac, e)
32
+ end
33
+
34
+ def test_eth
35
+ header = "00032f1a74de001b1151b7ce0800".scan(/../).map { |x| x.to_i(16) }.pack("C*")
36
+ src = "\x00\x1b\x11\x51\xb7\xce"
37
+ dst = "\x00\x03\x2f\x1a\x74\xde"
38
+ e = PacketFu::EthHeader.new
39
+ e.eth_dst = dst
40
+ e.eth_src = src
41
+ e.eth_proto = "\x08\x00"
42
+ assert_equal(header, e.to_s)
43
+ assert_equal(header, PacketFu::EthHeader.new.read(header).to_s)
44
+ end
45
+
46
+ def test_macaddr
47
+ dst = "\x00\x03\x2f\x1a\x74\xde"
48
+ dstmac = "00:03:2f:1a:74:de"
49
+ assert_equal(dstmac,PacketFu::EthHeader.str2mac(dst))
50
+ assert_equal(dst, PacketFu::EthHeader.mac2str(dstmac))
51
+ end
52
+
53
+ end
54
+
55
+ class EthPacketTest < Test::Unit::TestCase
56
+ include PacketFu
57
+
58
+ def test_eth_create
59
+ sample_packet = PcapFile.new.file_to_array(:f => 'sample.pcap')[0]
60
+ e = EthPacket.new
61
+ header = "00032f1a74de001b1151b7ce0800".scan(/../).map { |x| x.to_i(16) }.pack("C*")
62
+ assert_kind_of EthPacket, e
63
+ assert_kind_of EthHeader, e.headers[0]
64
+ assert e.is_eth?
65
+ assert !e.is_tcp?
66
+ e.eth_dst = "\x00\x03\x2f\x1a\x74\xde"
67
+ e.eth_src = "\x00\x1b\x11\x51\xb7\xce"
68
+ e.eth_proto = 0x0800
69
+ assert_equal header, e.to_s[0,14]
70
+ end
71
+
72
+ def test_eth_new
73
+ p = EthPacket.new(
74
+ :eth_dst => "\x00\x03\x2f\x1a\x74\xde",
75
+ :eth_src => "\x00\x1b\x11\x51\xb7\xce",
76
+ :eth_proto => 0x0800)
77
+ header = "00032f1a74de001b1151b7ce0800".scan(/../).map { |x| x.to_i(16) }.pack("C*")
78
+ assert_equal header, p.to_s[0,14]
79
+ end
80
+
81
+ def test_eth_write
82
+ p = EthPacket.new(
83
+ :eth_dst => "\x00\x03\x2f\x1a\x74\xde",
84
+ :eth_src => "\x00\x1b\x11\x51\xb7\xce",
85
+ :eth_proto => 0x0800)
86
+ p.to_f('eth_test.pcap')
87
+ end
88
+
89
+ end
90
+
91
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
data/test/test_hsrp.rb ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
4
+ require 'packetfu'
5
+
6
+ class HSRPTest < Test::Unit::TestCase
7
+ include PacketFu
8
+
9
+ def test_hsrp_read
10
+ sample_packet = PcapFile.new.file_to_array(:f => 'sample_hsrp_pcapr.cap')[0]
11
+ pkt = Packet.parse(sample_packet)
12
+ assert pkt.is_hsrp?
13
+ assert pkt.is_udp?
14
+ assert_equal(0x2d8d, pkt.udp_sum.to_i)
15
+ # pkt.to_f('udp_test.pcap','a')
16
+ end
17
+
18
+ end
19
+
20
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
data/test/test_icmp.rb ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
4
+ require 'packetfu'
5
+
6
+ class ICMPTest < Test::Unit::TestCase
7
+ include PacketFu
8
+
9
+ def test_icmp_header_new
10
+ i = ICMPHeader.new
11
+ assert_kind_of ICMPHeader, i
12
+ assert_equal("\x00\x00\xff\xff", i.to_s)
13
+ i.icmp_type = 1
14
+ i.icmp_recalc :icmp_sum
15
+ assert_equal("\x01\x00\xfe\xff", i.to_s)
16
+ end
17
+
18
+ def test_icmp_peek
19
+ i = ICMPPacket.new
20
+ i.ip_saddr = "10.20.30.40"
21
+ i.ip_daddr = "50.60.70.80"
22
+ i.payload = "abcdefghijklmnopqrstuvwxyz"
23
+ i.recalc
24
+ puts "\n"
25
+ puts "ICMP Peek format: "
26
+ puts i.peek
27
+ assert (i.peek.size <= 80)
28
+ end
29
+
30
+ def test_icmp_pcap
31
+ i = ICMPPacket.new
32
+ assert_kind_of ICMPPacket, i
33
+ i.recalc
34
+ i.to_f('icmp_test.pcap')
35
+ i.ip_saddr = "10.20.30.40"
36
+ i.ip_daddr = "50.60.70.80"
37
+ i.payload = "\x00\x01\x00\01abcdefghijklmnopqrstuvwxyz"
38
+ i.icmp_code = 8
39
+ i.recalc
40
+ i.to_f('icmp_test.pcap','a')
41
+ assert File.exists?('icmp_test.pcap')
42
+ end
43
+
44
+ def test_icmp_read
45
+ sample_packet = PcapFile.new.file_to_array(:f => 'sample.pcap')[2]
46
+ pkt = Packet.parse(sample_packet)
47
+ assert_kind_of ICMPPacket, pkt
48
+ assert_equal(0x4d58, pkt.icmp_sum.to_i)
49
+ assert_equal(8, pkt.icmp_type.to_i)
50
+ end
51
+
52
+ end
53
+
54
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
4
+ require 'packetfu'
5
+
6
+
7
+ class InjectTest < Test::Unit::TestCase
8
+
9
+ def test_cap
10
+ assert_nothing_raised { PacketFu::Capture }
11
+ end
12
+
13
+ def test_whoami
14
+ assert_nothing_raised { PacketFu::Utils.whoami?(:iface => (ENV['IFACE'] || 'lo')) }
15
+ end
16
+
17
+ def test_to_w
18
+ assert_equal(Process.euid, 0, "TEST FAIL: This test must be run as root")
19
+ conf = PacketFu::Utils.whoami?(:iface => (ENV['IFACE'] || 'lo'))
20
+ p = PacketFu::UDPPacket.new(:config => conf)
21
+ p.udp_dport = 12345
22
+ p.udp_sport = 12345
23
+ p.payload = "PacketFu test packet"
24
+ p.recalc
25
+ assert p.to_w
26
+ end
27
+
28
+ end
29
+
30
+
31
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
4
+ require 'packetfu'
5
+
6
+ class InvalidTest < Test::Unit::TestCase
7
+ include PacketFu
8
+
9
+ def test_create_invalid
10
+ p = InvalidPacket.new
11
+ assert_kind_of InvalidPacket, p
12
+ assert_kind_of Packet, p
13
+ assert p.is_invalid?
14
+ assert_equal false, p.is_eth?
15
+ assert_not_equal EthPacket, p.class
16
+ end
17
+
18
+ # Sadly, the only way to generate an "InvalidPacket" is
19
+ # to read a packet that's less than 14 bytes. Otherwise,
20
+ # it's presumed to be an EthPacket. TODO: Fix this assumption!
21
+ def test_parse_invalid
22
+ p = Packet.parse("A" * 13)
23
+ assert_kind_of InvalidPacket, p
24
+ end
25
+
26
+ end
27
+
28
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby