packetfu 1.1.9 → 1.1.10

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -3,105 +3,105 @@ require 'packetfu/protos/tcp/option'
3
3
 
4
4
  module PacketFu
5
5
 
6
- class TcpOptions < Array
6
+ class TcpOptions < Array
7
7
 
8
- include StructFu
8
+ include StructFu
9
9
 
10
- # If args[:pad] is set, the options line is automatically padded out
11
- # with NOPs.
12
- def to_s(args={})
13
- opts = self.map {|x| x.to_s}.join
14
- if args[:pad]
15
- unless (opts.size % 4).zero?
16
- (4 - (opts.size % 4)).times { opts << "\x01" }
17
- end
18
- end
19
- opts
20
- end
10
+ # If args[:pad] is set, the options line is automatically padded out
11
+ # with NOPs.
12
+ def to_s(args={})
13
+ opts = self.map {|x| x.to_s}.join
14
+ if args[:pad]
15
+ unless (opts.size % 4).zero?
16
+ (4 - (opts.size % 4)).times { opts << "\x01" }
17
+ end
18
+ end
19
+ opts
20
+ end
21
21
 
22
- # Reads a string to populate the object.
23
- def read(str)
24
- self.clear
25
- PacketFu.force_binary(str)
26
- return self if(!str.respond_to? :to_s || str.nil?)
27
- i = 0
28
- while i < str.to_s.size
29
- this_opt = case str[i,1].unpack("C").first
30
- when 0; ::PacketFu::TcpOption::EOL.new
31
- when 1; ::PacketFu::TcpOption::NOP.new
32
- when 2; ::PacketFu::TcpOption::MSS.new
33
- when 3; ::PacketFu::TcpOption::WS.new
34
- when 4; ::PacketFu::TcpOption::SACKOK.new
35
- when 5; ::PacketFu::TcpOption::SACK.new
36
- when 6; ::PacketFu::TcpOption::ECHO.new
37
- when 7; ::PacketFu::TcpOption::ECHOREPLY.new
38
- when 8; ::PacketFu::TcpOption::TS.new
39
- else; ::PacketFu::TcpOption.new
40
- end
41
- this_opt.read str[i,str.size]
42
- unless this_opt.has_optlen?
43
- this_opt.value = nil
44
- this_opt.optlen = nil
45
- end
46
- self << this_opt
47
- i += this_opt.sz
48
- end
49
- self
50
- end
22
+ # Reads a string to populate the object.
23
+ def read(str)
24
+ self.clear
25
+ PacketFu.force_binary(str)
26
+ return self if(!str.respond_to? :to_s || str.nil?)
27
+ i = 0
28
+ while i < str.to_s.size
29
+ this_opt = case str[i,1].unpack("C").first
30
+ when 0; ::PacketFu::TcpOption::EOL.new
31
+ when 1; ::PacketFu::TcpOption::NOP.new
32
+ when 2; ::PacketFu::TcpOption::MSS.new
33
+ when 3; ::PacketFu::TcpOption::WS.new
34
+ when 4; ::PacketFu::TcpOption::SACKOK.new
35
+ when 5; ::PacketFu::TcpOption::SACK.new
36
+ when 6; ::PacketFu::TcpOption::ECHO.new
37
+ when 7; ::PacketFu::TcpOption::ECHOREPLY.new
38
+ when 8; ::PacketFu::TcpOption::TS.new
39
+ else; ::PacketFu::TcpOption.new
40
+ end
41
+ this_opt.read str[i,str.size]
42
+ unless this_opt.has_optlen?
43
+ this_opt.value = nil
44
+ this_opt.optlen = nil
45
+ end
46
+ self << this_opt
47
+ i += this_opt.sz
48
+ end
49
+ self
50
+ end
51
51
 
52
- # Decode parses the TcpOptions object's member options, and produces a
53
- # human-readable string by iterating over each element's decode() function.
54
- # If TcpOptions elements were not initially created as TcpOptions, an
55
- # attempt will be made to convert them.
56
- #
57
- # The output of decode is suitable as input for TcpOptions#encode.
58
- def decode
59
- decoded = self.map do |x|
60
- if x.kind_of? TcpOption
61
- x.decode
62
- else
63
- x = TcpOptions.new.read(x).decode
64
- end
65
- end
66
- decoded.join(",")
67
- end
52
+ # Decode parses the TcpOptions object's member options, and produces a
53
+ # human-readable string by iterating over each element's decode() function.
54
+ # If TcpOptions elements were not initially created as TcpOptions, an
55
+ # attempt will be made to convert them.
56
+ #
57
+ # The output of decode is suitable as input for TcpOptions#encode.
58
+ def decode
59
+ decoded = self.map do |x|
60
+ if x.kind_of? TcpOption
61
+ x.decode
62
+ else
63
+ x = TcpOptions.new.read(x).decode
64
+ end
65
+ end
66
+ decoded.join(",")
67
+ end
68
68
 
69
- # Encode takes a human-readable string and appends the corresponding
70
- # binary options to the TcpOptions object. To completely replace the contents
71
- # of the object, use TcpOptions#encode! instead.
72
- #
73
- # Options are comma-delimited, and are identical to the output of the
74
- # TcpOptions#decode function. Note that the syntax can be unforgiving, so
75
- # it may be easier to create the subclassed TcpOptions themselves directly,
76
- # but this method can be less typing if you know what you're doing.
77
- #
78
- # Note that by using TcpOptions#encode, strings supplied as values which
79
- # can be converted to numbers will be converted first.
80
- #
81
- # === Example
82
- #
83
- # t = TcpOptions.new
84
- # t.encode("MS:1460,WS:6")
85
- # t.to_s # => "\002\004\005\264\002\003\006"
86
- # t.encode("NOP")
87
- # t.to_s # => "\002\004\005\264\002\003\006\001"
88
- def encode(str)
89
- opts = str.split(/[\s]*,[\s]*/)
90
- opts.each do |o|
91
- kind,value = o.split(/[\s]*:[\s]*/)
92
- klass = TcpOption.const_get(kind.upcase)
93
- value = value.to_i if value =~ /^[0-9]+$/
94
- this_opt = klass.new
95
- this_opt.encode(value)
96
- self << this_opt
97
- end
98
- self
99
- end
69
+ # Encode takes a human-readable string and appends the corresponding
70
+ # binary options to the TcpOptions object. To completely replace the contents
71
+ # of the object, use TcpOptions#encode! instead.
72
+ #
73
+ # Options are comma-delimited, and are identical to the output of the
74
+ # TcpOptions#decode function. Note that the syntax can be unforgiving, so
75
+ # it may be easier to create the subclassed TcpOptions themselves directly,
76
+ # but this method can be less typing if you know what you're doing.
77
+ #
78
+ # Note that by using TcpOptions#encode, strings supplied as values which
79
+ # can be converted to numbers will be converted first.
80
+ #
81
+ # === Example
82
+ #
83
+ # t = TcpOptions.new
84
+ # t.encode("MS:1460,WS:6")
85
+ # t.to_s # => "\002\004\005\264\002\003\006"
86
+ # t.encode("NOP")
87
+ # t.to_s # => "\002\004\005\264\002\003\006\001"
88
+ def encode(str)
89
+ opts = str.split(/[\s]*,[\s]*/)
90
+ opts.each do |o|
91
+ kind,value = o.split(/[\s]*:[\s]*/)
92
+ klass = TcpOption.const_get(kind.upcase)
93
+ value = value.to_i if value =~ /^[0-9]+$/
94
+ this_opt = klass.new
95
+ this_opt.encode(value)
96
+ self << this_opt
97
+ end
98
+ self
99
+ end
100
100
 
101
- # Like TcpOption#encode, except the entire contents are replaced.
102
- def encode!(str)
103
- self.clear if self.size > 0
104
- encode(str)
105
- end
106
- end
101
+ # Like TcpOption#encode, except the entire contents are replaced.
102
+ def encode!(str)
103
+ self.clear if self.size > 0
104
+ encode(str)
105
+ end
106
+ end
107
107
  end
@@ -1,43 +1,43 @@
1
1
  # -*- coding: binary -*-
2
2
  module PacketFu
3
- # Implements the Reserved bits for TCPHeader.
4
- #
5
- # ==== Header Definition
6
- #
7
- #
8
- # Fixnum (1 bit) :r1
9
- # Fixnum (1 bit) :r2
10
- # Fixnum (1 bit) :r3
11
- class TcpReserved < Struct.new(:r1, :r2, :r3)
3
+ # Implements the Reserved bits for TCPHeader.
4
+ #
5
+ # ==== Header Definition
6
+ #
7
+ #
8
+ # Fixnum (1 bit) :r1
9
+ # Fixnum (1 bit) :r2
10
+ # Fixnum (1 bit) :r3
11
+ class TcpReserved < Struct.new(:r1, :r2, :r3)
12
12
 
13
- include StructFu
13
+ include StructFu
14
14
 
15
- def initialize(args={})
16
- super(
17
- args[:r1] || 0,
18
- args[:r2] || 0,
19
- args[:r3] || 0) if args.kind_of? Hash
20
- end
15
+ def initialize(args={})
16
+ super(
17
+ args[:r1] || 0,
18
+ args[:r2] || 0,
19
+ args[:r3] || 0) if args.kind_of? Hash
20
+ end
21
21
 
22
- # Returns the Reserved field as an integer.
23
- def to_i
24
- (r1.to_i << 2) + (r2.to_i << 1) + r3.to_i
25
- end
22
+ # Returns the Reserved field as an integer.
23
+ def to_i
24
+ (r1.to_i << 2) + (r2.to_i << 1) + r3.to_i
25
+ end
26
26
 
27
- # Reads a string to populate the object.
28
- def read(str)
29
- force_binary(str)
30
- return self if str.nil? || str.size.zero?
31
- if 1.respond_to? :ord
32
- byte = str[0].ord
33
- else
34
- byte = str[0]
35
- end
36
- self[:r1] = byte & 0b00000100 == 0b00000100 ? 1 : 0
37
- self[:r2] = byte & 0b00000010 == 0b00000010 ? 1 : 0
38
- self[:r3] = byte & 0b00000001 == 0b00000001 ? 1 : 0
39
- self
40
- end
27
+ # Reads a string to populate the object.
28
+ def read(str)
29
+ force_binary(str)
30
+ return self if str.nil? || str.size.zero?
31
+ if 1.respond_to? :ord
32
+ byte = str[0].ord
33
+ else
34
+ byte = str[0]
35
+ end
36
+ self[:r1] = byte & 0b00000100 == 0b00000100 ? 1 : 0
37
+ self[:r2] = byte & 0b00000010 == 0b00000010 ? 1 : 0
38
+ self[:r3] = byte & 0b00000001 == 0b00000001 ? 1 : 0
39
+ self
40
+ end
41
41
 
42
- end
42
+ end
43
43
  end
@@ -10,133 +10,133 @@ require 'packetfu/protos/udp/mixin'
10
10
 
11
11
  module PacketFu
12
12
 
13
- # UDPPacket is used to construct UDP Packets. They contain an EthHeader, an IPHeader, and a UDPHeader.
14
- #
15
- # == Example
16
- #
17
- # udp_pkt = PacketFu::UDPPacket.new
18
- # udp_pkt.udp_src=rand(0xffff-1024) + 1024
19
- # udp_pkt.udp_dst=53
20
- #
21
- # udp_pkt.ip_saddr="1.2.3.4"
22
- # udp_pkt.ip_daddr="10.20.30.40"
23
- #
24
- # udp_pkt.recalc
25
- # udp_pkt.to_f('/tmp/udp.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 UDP packet. UDP packets don't tend have a lot of
35
- # flavor, but their underlying ip headers do.
36
- # :config
37
- # A hash of return address details, often the output of Utils.whoami?
38
- class UDPPacket < Packet
13
+ # UDPPacket is used to construct UDP Packets. They contain an EthHeader, an IPHeader, and a UDPHeader.
14
+ #
15
+ # == Example
16
+ #
17
+ # udp_pkt = PacketFu::UDPPacket.new
18
+ # udp_pkt.udp_src=rand(0xffff-1024) + 1024
19
+ # udp_pkt.udp_dst=53
20
+ #
21
+ # udp_pkt.ip_saddr="1.2.3.4"
22
+ # udp_pkt.ip_daddr="10.20.30.40"
23
+ #
24
+ # udp_pkt.recalc
25
+ # udp_pkt.to_f('/tmp/udp.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 UDP packet. UDP packets don't tend have a lot of
35
+ # flavor, but their underlying ip headers do.
36
+ # :config
37
+ # A hash of return address details, often the output of Utils.whoami?
38
+ class UDPPacket < Packet
39
39
  include ::PacketFu::EthHeaderMixin
40
40
  include ::PacketFu::IPHeaderMixin
41
41
  include ::PacketFu::UDPHeaderMixin
42
42
 
43
- attr_accessor :eth_header, :ip_header, :udp_header
43
+ attr_accessor :eth_header, :ip_header, :udp_header
44
44
 
45
- def self.can_parse?(str)
46
- return false unless str.size >= 28
47
- return false unless EthPacket.can_parse? str
48
- return false unless IPPacket.can_parse? str
49
- return false unless str[23,1] == "\x11"
50
- return true
51
- end
45
+ def self.can_parse?(str)
46
+ return false unless str.size >= 28
47
+ return false unless EthPacket.can_parse? str
48
+ return false unless IPPacket.can_parse? str
49
+ return false unless str[23,1] == "\x11"
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
- if args[:strip]
57
- udp_body_len = self.ip_len - self.ip_hlen - 8
58
- @udp_header.body.read(@udp_header.body.to_s[0,udp_body_len])
59
- end
60
- super(args)
61
- self
62
- end
53
+ def read(str=nil, args={})
54
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
55
+ @eth_header.read(str)
56
+ if args[:strip]
57
+ udp_body_len = self.ip_len - self.ip_hlen - 8
58
+ @udp_header.body.read(@udp_header.body.to_s[0,udp_body_len])
59
+ end
60
+ super(args)
61
+ self
62
+ end
63
63
 
64
- def initialize(args={})
65
- @eth_header = EthHeader.new(args).read(args[:eth])
66
- @ip_header = IPHeader.new(args).read(args[:ip])
67
- @ip_header.ip_proto=0x11
68
- @udp_header = UDPHeader.new(args).read(args[:icmp])
69
- @ip_header.body = @udp_header
70
- @eth_header.body = @ip_header
71
- @headers = [@eth_header, @ip_header, @udp_header]
72
- super
73
- udp_calc_sum
74
- end
64
+ def initialize(args={})
65
+ @eth_header = EthHeader.new(args).read(args[:eth])
66
+ @ip_header = IPHeader.new(args).read(args[:ip])
67
+ @ip_header.ip_proto=0x11
68
+ @udp_header = UDPHeader.new(args).read(args[:icmp])
69
+ @ip_header.body = @udp_header
70
+ @eth_header.body = @ip_header
71
+ @headers = [@eth_header, @ip_header, @udp_header]
72
+ super
73
+ udp_calc_sum
74
+ end
75
75
 
76
- # udp_calc_sum() computes the UDP checksum, and is called upon intialization.
77
- # It usually should be called just prior to dropping packets to a file or on the wire.
78
- def udp_calc_sum
79
- # This is /not/ delegated down to @udp_header since we need info
80
- # from the IP header, too.
81
- checksum = (ip_src.to_i >> 16)
82
- checksum += (ip_src.to_i & 0xffff)
83
- checksum += (ip_dst.to_i >> 16)
84
- checksum += (ip_dst.to_i & 0xffff)
85
- checksum += 0x11
86
- checksum += udp_len.to_i
87
- checksum += udp_src.to_i
88
- checksum += udp_dst.to_i
89
- checksum += udp_len.to_i
90
- if udp_len.to_i >= 8
91
- # For IP trailers. This isn't very reliable. :/
92
- real_udp_payload = payload.to_s[0,(udp_len.to_i-8)]
93
- else
94
- # I'm not going to mess with this right now.
95
- real_udp_payload = payload
96
- end
97
- chk_payload = (real_udp_payload.size % 2 == 0 ? real_udp_payload : real_udp_payload + "\x00")
98
- chk_payload.unpack("n*").each {|x| checksum = checksum+x}
99
- checksum = checksum % 0xffff
100
- checksum = 0xffff - checksum
101
- checksum == 0 ? 0xffff : checksum
102
- @udp_header.udp_sum = checksum
103
- end
76
+ # udp_calc_sum() computes the UDP checksum, and is called upon intialization.
77
+ # It usually should be called just prior to dropping packets to a file or on the wire.
78
+ def udp_calc_sum
79
+ # This is /not/ delegated down to @udp_header since we need info
80
+ # from the IP header, too.
81
+ checksum = (ip_src.to_i >> 16)
82
+ checksum += (ip_src.to_i & 0xffff)
83
+ checksum += (ip_dst.to_i >> 16)
84
+ checksum += (ip_dst.to_i & 0xffff)
85
+ checksum += 0x11
86
+ checksum += udp_len.to_i
87
+ checksum += udp_src.to_i
88
+ checksum += udp_dst.to_i
89
+ checksum += udp_len.to_i
90
+ if udp_len.to_i >= 8
91
+ # For IP trailers. This isn't very reliable. :/
92
+ real_udp_payload = payload.to_s[0,(udp_len.to_i-8)]
93
+ else
94
+ # I'm not going to mess with this right now.
95
+ real_udp_payload = payload
96
+ end
97
+ chk_payload = (real_udp_payload.size % 2 == 0 ? real_udp_payload : real_udp_payload + "\x00")
98
+ chk_payload.unpack("n*").each {|x| checksum = checksum+x}
99
+ checksum = checksum % 0xffff
100
+ checksum = 0xffff - checksum
101
+ checksum == 0 ? 0xffff : checksum
102
+ @udp_header.udp_sum = checksum
103
+ end
104
104
 
105
- # udp_recalc() recalculates various fields of the UDP packet. Valid arguments are:
106
- #
107
- # :all
108
- # Recomputes all calculated fields.
109
- # :udp_sum
110
- # Recomputes the UDP checksum.
111
- # :udp_len
112
- # Recomputes the UDP length.
113
- def udp_recalc(args=:all)
114
- case args
115
- when :udp_len
116
- @udp_header.udp_recalc
117
- when :udp_sum
118
- udp_calc_sum
119
- when :all
120
- @udp_header.udp_recalc
121
- udp_calc_sum
122
- else
123
- raise ArgumentError, "No such field `#{arg}'"
124
- end
125
- end
105
+ # udp_recalc() recalculates various fields of the UDP packet. Valid arguments are:
106
+ #
107
+ # :all
108
+ # Recomputes all calculated fields.
109
+ # :udp_sum
110
+ # Recomputes the UDP checksum.
111
+ # :udp_len
112
+ # Recomputes the UDP length.
113
+ def udp_recalc(args=:all)
114
+ case args
115
+ when :udp_len
116
+ @udp_header.udp_recalc
117
+ when :udp_sum
118
+ udp_calc_sum
119
+ when :all
120
+ @udp_header.udp_recalc
121
+ udp_calc_sum
122
+ else
123
+ raise ArgumentError, "No such field `#{arg}'"
124
+ end
125
+ end
126
126
 
127
- # Peek provides summary data on packet contents.
128
- def peek_format
129
- peek_data = ["U "]
130
- peek_data << "%-5d" % self.to_s.size
131
- peek_data << "%-21s" % "#{self.ip_saddr}:#{self.udp_sport}"
132
- peek_data << "->"
133
- peek_data << "%21s" % "#{self.ip_daddr}:#{self.udp_dport}"
134
- peek_data << "%23s" % "I:"
135
- peek_data << "%04x" % self.ip_id
136
- peek_data.join
137
- end
127
+ # Peek provides summary data on packet contents.
128
+ def peek_format
129
+ peek_data = ["U "]
130
+ peek_data << "%-5d" % self.to_s.size
131
+ peek_data << "%-21s" % "#{self.ip_saddr}:#{self.udp_sport}"
132
+ peek_data << "->"
133
+ peek_data << "%21s" % "#{self.ip_daddr}:#{self.udp_dport}"
134
+ peek_data << "%23s" % "I:"
135
+ peek_data << "%04x" % self.ip_id
136
+ peek_data.join
137
+ end
138
138
 
139
- end
139
+ end
140
140
 
141
141
  end
142
142