packetfu 1.1.10 → 1.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/.gitignore +3 -0
  5. data/.travis.yml +8 -0
  6. data/CONTRIBUTING.md +47 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +1 -1
  9. data/README.rdoc +35 -30
  10. data/Rakefile +4 -4
  11. data/bench/octets.rb +9 -9
  12. data/examples/100kpackets.rb +12 -12
  13. data/examples/ackscan.rb +16 -16
  14. data/examples/arp.rb +35 -35
  15. data/examples/arphood.rb +36 -36
  16. data/examples/dissect_thinger.rb +6 -6
  17. data/examples/new-simple-stats.rb +23 -23
  18. data/examples/packetfu-shell.rb +25 -25
  19. data/examples/simple-sniffer.rb +9 -9
  20. data/examples/simple-stats.rb +23 -23
  21. data/examples/slammer.rb +3 -3
  22. data/gem-public_cert.pem +21 -0
  23. data/lib/packetfu.rb +149 -127
  24. data/lib/packetfu/capture.rb +169 -169
  25. data/lib/packetfu/config.rb +52 -52
  26. data/lib/packetfu/inject.rb +56 -56
  27. data/lib/packetfu/packet.rb +531 -528
  28. data/lib/packetfu/pcap.rb +579 -579
  29. data/lib/packetfu/protos/arp.rb +90 -90
  30. data/lib/packetfu/protos/arp/header.rb +158 -158
  31. data/lib/packetfu/protos/arp/mixin.rb +36 -36
  32. data/lib/packetfu/protos/eth.rb +44 -44
  33. data/lib/packetfu/protos/eth/header.rb +243 -243
  34. data/lib/packetfu/protos/eth/mixin.rb +3 -3
  35. data/lib/packetfu/protos/hsrp.rb +69 -69
  36. data/lib/packetfu/protos/hsrp/header.rb +107 -107
  37. data/lib/packetfu/protos/hsrp/mixin.rb +29 -29
  38. data/lib/packetfu/protos/icmp.rb +71 -71
  39. data/lib/packetfu/protos/icmp/header.rb +82 -82
  40. data/lib/packetfu/protos/icmp/mixin.rb +14 -14
  41. data/lib/packetfu/protos/invalid.rb +49 -49
  42. data/lib/packetfu/protos/ip.rb +69 -69
  43. data/lib/packetfu/protos/ip/header.rb +291 -291
  44. data/lib/packetfu/protos/ip/mixin.rb +40 -40
  45. data/lib/packetfu/protos/ipv6.rb +50 -50
  46. data/lib/packetfu/protos/ipv6/header.rb +188 -188
  47. data/lib/packetfu/protos/ipv6/mixin.rb +29 -29
  48. data/lib/packetfu/protos/tcp.rb +176 -176
  49. data/lib/packetfu/protos/tcp/ecn.rb +35 -35
  50. data/lib/packetfu/protos/tcp/flags.rb +74 -74
  51. data/lib/packetfu/protos/tcp/header.rb +268 -268
  52. data/lib/packetfu/protos/tcp/hlen.rb +32 -32
  53. data/lib/packetfu/protos/tcp/mixin.rb +46 -46
  54. data/lib/packetfu/protos/tcp/option.rb +321 -321
  55. data/lib/packetfu/protos/tcp/options.rb +95 -95
  56. data/lib/packetfu/protos/tcp/reserved.rb +35 -35
  57. data/lib/packetfu/protos/udp.rb +159 -123
  58. data/lib/packetfu/protos/udp/header.rb +91 -91
  59. data/lib/packetfu/protos/udp/mixin.rb +3 -3
  60. data/lib/packetfu/structfu.rb +280 -280
  61. data/lib/packetfu/utils.rb +292 -225
  62. data/lib/packetfu/version.rb +41 -41
  63. data/packetfu.gemspec +14 -3
  64. data/spec/arp_spec.rb +191 -0
  65. data/spec/eth_spec.rb +148 -0
  66. data/spec/icmp_spec.rb +97 -0
  67. data/spec/ip_spec.rb +78 -0
  68. data/spec/ipv6_spec.rb +81 -0
  69. data/spec/packet_spec.rb +61 -59
  70. data/spec/packet_subclasses_spec.rb +9 -10
  71. data/spec/packetfu_spec.rb +55 -62
  72. data/spec/sample3.pcap +0 -0
  73. data/spec/spec_helper.rb +44 -0
  74. data/spec/structfu_spec.rb +270 -271
  75. data/spec/tcp_spec.rb +76 -77
  76. data/spec/udp_spec.rb +32 -0
  77. data/spec/utils_spec.rb +95 -0
  78. data/test/all_tests.rb +14 -17
  79. data/test/func_lldp.rb +3 -3
  80. data/test/ptest.rb +2 -2
  81. data/test/test_capture.rb +45 -45
  82. data/test/test_eth.rb +70 -68
  83. data/test/test_hsrp.rb +9 -9
  84. data/test/test_inject.rb +18 -18
  85. data/test/test_invalid.rb +16 -16
  86. data/test/test_octets.rb +23 -21
  87. data/test/test_packet.rb +156 -154
  88. data/test/test_pcap.rb +172 -170
  89. data/test/test_structfu.rb +99 -97
  90. data/test/test_tcp.rb +322 -320
  91. data/test/test_udp.rb +78 -76
  92. metadata +108 -44
  93. metadata.gz.sig +2 -0
  94. data/spec/ethpacket_spec.rb +0 -74
  95. data/test/test_arp.rb +0 -135
  96. data/test/test_icmp.rb +0 -62
  97. data/test/test_ip.rb +0 -50
  98. data/test/test_ip6.rb +0 -68
@@ -9,85 +9,85 @@ require 'packetfu/protos/icmp/header'
9
9
  require 'packetfu/protos/icmp/mixin'
10
10
 
11
11
  module PacketFu
12
- # ICMPPacket is used to construct ICMP Packets. They contain an EthHeader, an IPHeader, and a ICMPHeader.
13
- #
14
- # == Example
15
- #
16
- # icmp_pkt.new
17
- # icmp_pkt.icmp_type = 8
18
- # icmp_pkt.icmp_code = 0
19
- # icmp_pkt.payload = "ABC, easy as 123. As simple as do-re-mi. ABC, 123, baby, you and me!"
20
- #
21
- # icmp_pkt.ip_saddr="1.2.3.4"
22
- # icmp_pkt.ip_daddr="5.6.7.8"
23
- #
24
- # icmp_pkt.recalc
25
- # icmp_pkt.to_f('/tmp/icmp.pcap')
26
- #
27
- # == Parameters
28
- #
29
- # :eth
30
- # A pre-generated EthHeader object.
31
- # :ip
32
- # A pre-generated IPHeader object.
33
- # :flavor
34
- # TODO: Sets the "flavor" of the ICMP packet. Pings, in particular, often betray their true
35
- # OS.
36
- # :config
37
- # A hash of return address details, often the output of Utils.whoami?
38
- class ICMPPacket < Packet
12
+ # ICMPPacket is used to construct ICMP Packets. They contain an EthHeader, an IPHeader, and a ICMPHeader.
13
+ #
14
+ # == Example
15
+ #
16
+ # icmp_pkt.new
17
+ # icmp_pkt.icmp_type = 8
18
+ # icmp_pkt.icmp_code = 0
19
+ # icmp_pkt.payload = "ABC, easy as 123. As simple as do-re-mi. ABC, 123, baby, you and me!"
20
+ #
21
+ # icmp_pkt.ip_saddr="1.2.3.4"
22
+ # icmp_pkt.ip_daddr="5.6.7.8"
23
+ #
24
+ # icmp_pkt.recalc
25
+ # icmp_pkt.to_f('/tmp/icmp.pcap')
26
+ #
27
+ # == Parameters
28
+ #
29
+ # :eth
30
+ # A pre-generated EthHeader object.
31
+ # :ip
32
+ # A pre-generated IPHeader object.
33
+ # :flavor
34
+ # TODO: Sets the "flavor" of the ICMP packet. Pings, in particular, often betray their true
35
+ # OS.
36
+ # :config
37
+ # A hash of return address details, often the output of Utils.whoami?
38
+ class ICMPPacket < Packet
39
39
  include ::PacketFu::EthHeaderMixin
40
40
  include ::PacketFu::IPHeaderMixin
41
41
  include ::PacketFu::ICMPHeaderMixin
42
42
 
43
- attr_accessor :eth_header, :ip_header, :icmp_header
43
+ attr_accessor :eth_header, :ip_header, :icmp_header
44
44
 
45
- def self.can_parse?(str)
46
- return false unless str.size >= 38
47
- return false unless EthPacket.can_parse? str
48
- return false unless IPPacket.can_parse? str
49
- return false unless str[23,1] == "\x01"
50
- return true
51
- end
45
+ def self.can_parse?(str)
46
+ return false unless str.size >= 38
47
+ return false unless EthPacket.can_parse? str
48
+ return false unless IPPacket.can_parse? str
49
+ return false unless str[23,1] == "\x01"
50
+ return true
51
+ end
52
52
 
53
- def read(str=nil, args={})
54
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
55
- @eth_header.read(str)
56
- super(args)
57
- self
58
- end
53
+ def read(str=nil, args={})
54
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
55
+ @eth_header.read(str)
56
+ super(args)
57
+ self
58
+ end
59
59
 
60
- def initialize(args={})
61
- @eth_header = EthHeader.new(args).read(args[:eth])
62
- @ip_header = IPHeader.new(args).read(args[:ip])
63
- @ip_header.ip_proto = 1
64
- @icmp_header = ICMPHeader.new(args).read(args[:icmp])
60
+ def initialize(args={})
61
+ @eth_header = EthHeader.new(args).read(args[:eth])
62
+ @ip_header = IPHeader.new(args).read(args[:ip])
63
+ @ip_header.ip_proto = 1
64
+ @icmp_header = ICMPHeader.new(args).read(args[:icmp])
65
65
 
66
- @ip_header.body = @icmp_header
67
- @eth_header.body = @ip_header
66
+ @ip_header.body = @icmp_header
67
+ @eth_header.body = @ip_header
68
68
 
69
- @headers = [@eth_header, @ip_header, @icmp_header]
70
- super
71
- end
69
+ @headers = [@eth_header, @ip_header, @icmp_header]
70
+ super
71
+ end
72
72
 
73
- # Peek provides summary data on packet contents.
74
- def peek_format
75
- peek_data = ["IC "] # I is taken by IP
76
- peek_data << "%-5d" % self.to_s.size
77
- type = case self.icmp_type.to_i
78
- when 8
79
- "ping"
80
- when 0
81
- "pong"
82
- else
83
- "%02x-%02x" % [self.icmp_type, self.icmp_code]
84
- end
85
- peek_data << "%-21s" % "#{self.ip_saddr}:#{type}"
86
- peek_data << "->"
87
- peek_data << "%21s" % "#{self.ip_daddr}"
88
- peek_data << "%23s" % "I:"
89
- peek_data << "%04x" % self.ip_id
90
- peek_data.join
91
- end
92
- end
73
+ # Peek provides summary data on packet contents.
74
+ def peek_format
75
+ peek_data = ["IC "] # I is taken by IP
76
+ peek_data << "%-5d" % self.to_s.size
77
+ type = case self.icmp_type.to_i
78
+ when 8
79
+ "ping"
80
+ when 0
81
+ "pong"
82
+ else
83
+ "%02x-%02x" % [self.icmp_type, self.icmp_code]
84
+ end
85
+ peek_data << "%-21s" % "#{self.ip_saddr}:#{type}"
86
+ peek_data << "->"
87
+ peek_data << "%21s" % "#{self.ip_daddr}"
88
+ peek_data << "%23s" % "I:"
89
+ peek_data << "%04x" % self.ip_id
90
+ peek_data.join
91
+ end
92
+ end
93
93
  end
@@ -1,94 +1,94 @@
1
1
  # -*- coding: binary -*-
2
2
  module PacketFu
3
- # ICMPHeader is a complete ICMP struct, used in ICMPPacket. ICMP is
4
- # typically used for network administration and connectivity testing.
5
- #
6
- # For more on ICMP packets, see
7
- # http://www.networksorcery.com/enp/protocol/icmp.htm
8
- #
9
- # ==== Header Definition
10
- #
11
- # Int8 :icmp_type # Type
12
- # Int8 :icmp_code # Code
13
- # Int16 :icmp_sum Default: calculated # Checksum
14
- # String :body
15
- class ICMPHeader < Struct.new(:icmp_type, :icmp_code, :icmp_sum, :body)
3
+ # ICMPHeader is a complete ICMP struct, used in ICMPPacket. ICMP is
4
+ # typically used for network administration and connectivity testing.
5
+ #
6
+ # For more on ICMP packets, see
7
+ # http://www.networksorcery.com/enp/protocol/icmp.htm
8
+ #
9
+ # ==== Header Definition
10
+ #
11
+ # Int8 :icmp_type # Type
12
+ # Int8 :icmp_code # Code
13
+ # Int16 :icmp_sum Default: calculated # Checksum
14
+ # String :body
15
+ class ICMPHeader < Struct.new(:icmp_type, :icmp_code, :icmp_sum, :body)
16
16
 
17
- include StructFu
17
+ include StructFu
18
18
 
19
- def initialize(args={})
20
- super(
21
- Int8.new(args[:icmp_type]),
22
- Int8.new(args[:icmp_code]),
23
- Int16.new(args[:icmp_sum] || icmp_calc_sum),
24
- StructFu::String.new.read(args[:body])
25
- )
26
- end
19
+ def initialize(args={})
20
+ super(
21
+ Int8.new(args[:icmp_type]),
22
+ Int8.new(args[:icmp_code]),
23
+ Int16.new(args[:icmp_sum] || icmp_calc_sum),
24
+ StructFu::String.new.read(args[:body])
25
+ )
26
+ end
27
27
 
28
- # Returns the object in string form.
29
- def to_s
30
- self.to_a.map {|x| x.to_s}.join
31
- end
28
+ # Returns the object in string form.
29
+ def to_s
30
+ self.to_a.map {|x| x.to_s}.join
31
+ end
32
32
 
33
- # Reads a string to populate the object.
34
- def read(str)
35
- force_binary(str)
36
- return self if str.nil?
37
- self[:icmp_type].read(str[0,1])
38
- self[:icmp_code].read(str[1,1])
39
- self[:icmp_sum].read(str[2,2])
40
- self[:body].read(str[4,str.size])
41
- self
42
- end
33
+ # Reads a string to populate the object.
34
+ def read(str)
35
+ force_binary(str)
36
+ return self if str.nil?
37
+ self[:icmp_type].read(str[0,1])
38
+ self[:icmp_code].read(str[1,1])
39
+ self[:icmp_sum].read(str[2,2])
40
+ self[:body].read(str[4,str.size])
41
+ self
42
+ end
43
43
 
44
- # Setter for the type.
45
- def icmp_type=(i); typecast i; end
46
- # Getter for the type.
47
- def icmp_type; self[:icmp_type].to_i; end
48
- # Setter for the code.
49
- def icmp_code=(i); typecast i; end
50
- # Getter for the code.
51
- def icmp_code; self[:icmp_code].to_i; end
52
- # Setter for the checksum. Note, this is calculated automatically with
53
- # icmp_calc_sum.
54
- def icmp_sum=(i); typecast i; end
55
- # Getter for the checksum.
56
- def icmp_sum; self[:icmp_sum].to_i; end
44
+ # Setter for the type.
45
+ def icmp_type=(i); typecast i; end
46
+ # Getter for the type.
47
+ def icmp_type; self[:icmp_type].to_i; end
48
+ # Setter for the code.
49
+ def icmp_code=(i); typecast i; end
50
+ # Getter for the code.
51
+ def icmp_code; self[:icmp_code].to_i; end
52
+ # Setter for the checksum. Note, this is calculated automatically with
53
+ # icmp_calc_sum.
54
+ def icmp_sum=(i); typecast i; end
55
+ # Getter for the checksum.
56
+ def icmp_sum; self[:icmp_sum].to_i; end
57
57
 
58
- # Calculates and sets the checksum for the object.
59
- def icmp_calc_sum
60
- checksum = (icmp_type.to_i << 8) + icmp_code.to_i
61
- chk_body = (body.to_s.size % 2 == 0 ? body.to_s : body.to_s + "\x00")
62
- if 1.respond_to? :ord
63
- chk_body.scan(/../).map { |x| (x[0].ord << 8) + x[1].ord }.each { |y| checksum += y }
64
- else
65
- chk_body.scan(/../).map { |x| (x[0] << 8) + x[1] }.each { |y| checksum += y }
66
- end
67
- checksum = checksum % 0xffff
68
- checksum = 0xffff - checksum
69
- checksum == 0 ? 0xffff : checksum
70
- end
71
-
72
- # Recalculates the calculatable fields for ICMP.
73
- def icmp_recalc(arg=:all)
74
- # How silly is this, you can't intern a symbol in ruby 1.8.7pl72?
75
- # I'm this close to monkey patching Symbol so you can force it...
76
- arg = arg.intern if arg.respond_to? :intern
77
- case arg
78
- when :icmp_sum
79
- self.icmp_sum=icmp_calc_sum
80
- when :all
81
- self.icmp_sum=icmp_calc_sum
82
- else
83
- raise ArgumentError, "No such field `#{arg}'"
84
- end
85
- end
58
+ # Calculates and sets the checksum for the object.
59
+ def icmp_calc_sum
60
+ checksum = (icmp_type.to_i << 8) + icmp_code.to_i
61
+ chk_body = (body.to_s.size % 2 == 0 ? body.to_s : body.to_s + "\x00")
62
+ if 1.respond_to? :ord
63
+ chk_body.split("").each_slice(2).map { |x| (x[0].ord << 8) + x[1].ord }.each { |y| checksum += y }
64
+ else
65
+ chk_body.split("").each_slice(2).map { |x| (x[0] << 8) + x[1] }.each { |y| checksum += y }
66
+ end
67
+ checksum = checksum % 0xffff
68
+ checksum = 0xffff - checksum
69
+ checksum == 0 ? 0xffff : checksum
70
+ end
71
+
72
+ # Recalculates the calculatable fields for ICMP.
73
+ def icmp_recalc(arg=:all)
74
+ # How silly is this, you can't intern a symbol in ruby 1.8.7pl72?
75
+ # I'm this close to monkey patching Symbol so you can force it...
76
+ arg = arg.intern if arg.respond_to? :intern
77
+ case arg
78
+ when :icmp_sum
79
+ self.icmp_sum=icmp_calc_sum
80
+ when :all
81
+ self.icmp_sum=icmp_calc_sum
82
+ else
83
+ raise ArgumentError, "No such field `#{arg}'"
84
+ end
85
+ end
86
86
 
87
- # Readability aliases
87
+ # Readability aliases
88
88
 
89
- def icmp_sum_readable
90
- "0x%04x" % icmp_sum
91
- end
89
+ def icmp_sum_readable
90
+ "0x%04x" % icmp_sum
91
+ end
92
92
 
93
- end
93
+ end
94
94
  end
@@ -1,18 +1,18 @@
1
1
  # -*- coding: binary -*-
2
2
  module PacketFu
3
- # This Mixin simplifies access to the ICMPHeaders. Mix this in with your
4
- # packet interface, and it will add methods that essentially delegate to
5
- # the 'icmp_header' method (assuming that it is a ICMPHeader object)
6
- module ICMPHeaderMixin
7
- def icmp_type=(v); self.icmp_header.icmp_type= v; end
8
- def icmp_type; self.icmp_header.icmp_type; end
9
- def icmp_code=(v); self.icmp_header.icmp_code= v; end
10
- def icmp_code; self.icmp_header.icmp_code; end
11
- def icmp_sum=(v); self.icmp_header.icmp_sum= v; end
12
- def icmp_sum; self.icmp_header.icmp_sum; end
13
- def icmp_calc_sum; self.icmp_header.icmp_calc_sum; end
14
- def icmp_recalc(*v); self.icmp_header.icmp_recalc(*v); end
15
- def icmp_sum_readable; self.icmp_header.icmp_sum_readable; end
16
- end
3
+ # This Mixin simplifies access to the ICMPHeaders. Mix this in with your
4
+ # packet interface, and it will add methods that essentially delegate to
5
+ # the 'icmp_header' method (assuming that it is a ICMPHeader object)
6
+ module ICMPHeaderMixin
7
+ def icmp_type=(v); self.icmp_header.icmp_type= v; end
8
+ def icmp_type; self.icmp_header.icmp_type; end
9
+ def icmp_code=(v); self.icmp_header.icmp_code= v; end
10
+ def icmp_code; self.icmp_header.icmp_code; end
11
+ def icmp_sum=(v); self.icmp_header.icmp_sum= v; end
12
+ def icmp_sum; self.icmp_header.icmp_sum; end
13
+ def icmp_calc_sum; self.icmp_header.icmp_calc_sum; end
14
+ def icmp_recalc(*v); self.icmp_header.icmp_recalc(*v); end
15
+ def icmp_sum_readable; self.icmp_header.icmp_sum_readable; end
16
+ end
17
17
  end
18
18
 
@@ -1,55 +1,55 @@
1
1
  # -*- coding: binary -*-
2
2
  module PacketFu
3
3
 
4
- # InvalidHeader catches all packets that we don't already have a Struct for,
5
- # or for whatever reason, violates some basic packet rules for other packet
6
- # types.
7
- class InvalidHeader < Struct.new(:body)
8
- include StructFu
9
-
10
- def initialize(args={})
11
- args[:body] ||= StructFu::String.new
12
- super(args[:body])
13
- end
14
-
15
- # Returns the object in string form.
16
- def to_s
17
- self.to_a.map {|x| x.to_s}.join
18
- end
19
-
20
- # Reads a string to populate the object.
21
- def read(str)
22
- force_binary(str)
23
- return self if str.nil?
24
- self[:body].read str
25
- self
26
- end
27
-
28
- end
29
-
30
- # You probably don't want to write invalid packets on purpose.
31
- class InvalidPacket < Packet
32
- attr_accessor :invalid_header
33
-
34
- # Any packet is potentially an invalid packet
35
- def self.can_parse?(str)
36
- true
37
- end
38
-
39
- def self.layer
40
- 0
41
- end
42
-
43
- def read(str=nil,args={})
44
- @invalid_header.read(str)
45
- self
46
- end
47
-
48
- def initialize(args={})
49
- @invalid_header = (args[:invalid] || InvalidHeader.new)
50
- @headers = [@invalid_header]
51
- end
52
- end
4
+ # InvalidHeader catches all packets that we don't already have a Struct for,
5
+ # or for whatever reason, violates some basic packet rules for other packet
6
+ # types.
7
+ class InvalidHeader < Struct.new(:body)
8
+ include StructFu
9
+
10
+ def initialize(args={})
11
+ args[:body] ||= StructFu::String.new
12
+ super(args[:body])
13
+ end
14
+
15
+ # Returns the object in string form.
16
+ def to_s
17
+ self.to_a.map {|x| x.to_s}.join
18
+ end
19
+
20
+ # Reads a string to populate the object.
21
+ def read(str)
22
+ force_binary(str)
23
+ return self if str.nil?
24
+ self[:body].read str
25
+ self
26
+ end
27
+
28
+ end
29
+
30
+ # You probably don't want to write invalid packets on purpose.
31
+ class InvalidPacket < Packet
32
+ attr_accessor :invalid_header
33
+
34
+ # Any packet is potentially an invalid packet
35
+ def self.can_parse?(str)
36
+ true
37
+ end
38
+
39
+ def self.layer
40
+ 0
41
+ end
42
+
43
+ def read(str=nil,args={})
44
+ @invalid_header.read(str)
45
+ self
46
+ end
47
+
48
+ def initialize(args={})
49
+ @invalid_header = (args[:invalid] || InvalidHeader.new)
50
+ @headers = [@invalid_header]
51
+ end
52
+ end
53
53
 
54
54
  end # module PacketFu
55
55