packetfu 1.1.8 → 1.1.9

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