packetfu 1.1.9 → 1.1.10

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 (77) hide show
  1. data/bench/octets.rb +9 -9
  2. data/examples/100kpackets.rb +12 -12
  3. data/examples/ackscan.rb +16 -16
  4. data/examples/arp.rb +35 -35
  5. data/examples/arphood.rb +36 -36
  6. data/examples/dissect_thinger.rb +6 -6
  7. data/examples/new-simple-stats.rb +23 -23
  8. data/examples/packetfu-shell.rb +25 -25
  9. data/examples/simple-sniffer.rb +9 -9
  10. data/examples/simple-stats.rb +23 -23
  11. data/examples/slammer.rb +3 -3
  12. data/lib/packetfu.rb +127 -127
  13. data/lib/packetfu/capture.rb +169 -169
  14. data/lib/packetfu/config.rb +52 -52
  15. data/lib/packetfu/inject.rb +56 -56
  16. data/lib/packetfu/packet.rb +528 -528
  17. data/lib/packetfu/pcap.rb +579 -579
  18. data/lib/packetfu/protos/arp.rb +90 -90
  19. data/lib/packetfu/protos/arp/header.rb +158 -158
  20. data/lib/packetfu/protos/arp/mixin.rb +36 -36
  21. data/lib/packetfu/protos/eth.rb +44 -44
  22. data/lib/packetfu/protos/eth/header.rb +243 -243
  23. data/lib/packetfu/protos/eth/mixin.rb +3 -3
  24. data/lib/packetfu/protos/hsrp.rb +69 -69
  25. data/lib/packetfu/protos/hsrp/header.rb +107 -107
  26. data/lib/packetfu/protos/hsrp/mixin.rb +29 -29
  27. data/lib/packetfu/protos/icmp.rb +71 -71
  28. data/lib/packetfu/protos/icmp/header.rb +82 -82
  29. data/lib/packetfu/protos/icmp/mixin.rb +14 -14
  30. data/lib/packetfu/protos/invalid.rb +49 -49
  31. data/lib/packetfu/protos/ip.rb +69 -69
  32. data/lib/packetfu/protos/ip/header.rb +291 -291
  33. data/lib/packetfu/protos/ip/mixin.rb +40 -40
  34. data/lib/packetfu/protos/ipv6.rb +50 -50
  35. data/lib/packetfu/protos/ipv6/header.rb +188 -188
  36. data/lib/packetfu/protos/ipv6/mixin.rb +29 -29
  37. data/lib/packetfu/protos/tcp.rb +176 -176
  38. data/lib/packetfu/protos/tcp/ecn.rb +35 -35
  39. data/lib/packetfu/protos/tcp/flags.rb +74 -74
  40. data/lib/packetfu/protos/tcp/header.rb +268 -268
  41. data/lib/packetfu/protos/tcp/hlen.rb +32 -32
  42. data/lib/packetfu/protos/tcp/mixin.rb +46 -46
  43. data/lib/packetfu/protos/tcp/option.rb +321 -321
  44. data/lib/packetfu/protos/tcp/options.rb +95 -95
  45. data/lib/packetfu/protos/tcp/reserved.rb +35 -35
  46. data/lib/packetfu/protos/udp.rb +116 -116
  47. data/lib/packetfu/protos/udp/header.rb +91 -91
  48. data/lib/packetfu/protos/udp/mixin.rb +3 -3
  49. data/lib/packetfu/structfu.rb +280 -280
  50. data/lib/packetfu/utils.rb +226 -217
  51. data/lib/packetfu/version.rb +41 -41
  52. data/packetfu.gemspec +2 -1
  53. data/spec/ethpacket_spec.rb +48 -48
  54. data/spec/packet_spec.rb +57 -57
  55. data/spec/packet_subclasses_spec.rb +8 -8
  56. data/spec/packetfu_spec.rb +59 -59
  57. data/spec/structfu_spec.rb +268 -268
  58. data/spec/tcp_spec.rb +75 -75
  59. data/test/all_tests.rb +13 -13
  60. data/test/func_lldp.rb +3 -3
  61. data/test/ptest.rb +2 -2
  62. data/test/test_arp.rb +116 -116
  63. data/test/test_capture.rb +45 -45
  64. data/test/test_eth.rb +68 -68
  65. data/test/test_hsrp.rb +9 -9
  66. data/test/test_icmp.rb +52 -52
  67. data/test/test_inject.rb +18 -18
  68. data/test/test_invalid.rb +16 -16
  69. data/test/test_ip.rb +36 -36
  70. data/test/test_ip6.rb +48 -48
  71. data/test/test_octets.rb +21 -21
  72. data/test/test_packet.rb +154 -154
  73. data/test/test_pcap.rb +170 -170
  74. data/test/test_structfu.rb +97 -97
  75. data/test/test_tcp.rb +320 -320
  76. data/test/test_udp.rb +76 -76
  77. metadata +4 -3
@@ -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.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
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