packetgen 3.1.1 → 3.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/bin/pgconsole +1 -0
  3. data/lib/packetgen.rb +33 -4
  4. data/lib/packetgen/capture.rb +51 -28
  5. data/lib/packetgen/config.rb +17 -11
  6. data/lib/packetgen/deprecation.rb +34 -8
  7. data/lib/packetgen/header.rb +2 -9
  8. data/lib/packetgen/header/arp.rb +2 -2
  9. data/lib/packetgen/header/asn1_base.rb +2 -2
  10. data/lib/packetgen/header/base.rb +70 -74
  11. data/lib/packetgen/header/bootp.rb +3 -3
  12. data/lib/packetgen/header/dhcp.rb +2 -2
  13. data/lib/packetgen/header/dhcp/option.rb +2 -2
  14. data/lib/packetgen/header/dhcp/options.rb +2 -2
  15. data/lib/packetgen/header/dhcpv6.rb +12 -12
  16. data/lib/packetgen/header/dhcpv6/duid.rb +11 -5
  17. data/lib/packetgen/header/dhcpv6/option.rb +8 -16
  18. data/lib/packetgen/header/dhcpv6/options.rb +2 -2
  19. data/lib/packetgen/header/dhcpv6/relay.rb +2 -2
  20. data/lib/packetgen/header/dns.rb +9 -9
  21. data/lib/packetgen/header/dns/name.rb +20 -9
  22. data/lib/packetgen/header/dns/opt.rb +2 -2
  23. data/lib/packetgen/header/dns/option.rb +2 -2
  24. data/lib/packetgen/header/dns/qdsection.rb +3 -3
  25. data/lib/packetgen/header/dns/question.rb +37 -35
  26. data/lib/packetgen/header/dns/rr.rb +3 -3
  27. data/lib/packetgen/header/dns/rrsection.rb +2 -2
  28. data/lib/packetgen/header/dot11.rb +30 -51
  29. data/lib/packetgen/header/dot11/control.rb +5 -5
  30. data/lib/packetgen/header/dot11/data.rb +11 -7
  31. data/lib/packetgen/header/dot11/element.rb +16 -16
  32. data/lib/packetgen/header/dot11/management.rb +2 -2
  33. data/lib/packetgen/header/dot11/sub_mngt.rb +2 -12
  34. data/lib/packetgen/header/dot1q.rb +2 -2
  35. data/lib/packetgen/header/dot1x.rb +7 -20
  36. data/lib/packetgen/header/eap.rb +30 -33
  37. data/lib/packetgen/header/eap/fast.rb +2 -2
  38. data/lib/packetgen/header/eap/md5.rb +2 -2
  39. data/lib/packetgen/header/eap/tls.rb +2 -2
  40. data/lib/packetgen/header/eap/ttls.rb +2 -2
  41. data/lib/packetgen/header/eth.rb +13 -11
  42. data/lib/packetgen/header/gre.rb +2 -2
  43. data/lib/packetgen/header/http.rb +2 -0
  44. data/lib/packetgen/header/http/headers.rb +6 -4
  45. data/lib/packetgen/header/http/request.rb +36 -21
  46. data/lib/packetgen/header/http/response.rb +7 -7
  47. data/lib/packetgen/header/http/verbs.rb +3 -3
  48. data/lib/packetgen/header/icmp.rb +2 -2
  49. data/lib/packetgen/header/icmpv6.rb +2 -2
  50. data/lib/packetgen/header/igmp.rb +4 -4
  51. data/lib/packetgen/header/igmpv3.rb +3 -3
  52. data/lib/packetgen/header/igmpv3/group_record.rb +8 -6
  53. data/lib/packetgen/header/igmpv3/mq.rb +2 -2
  54. data/lib/packetgen/header/igmpv3/mr.rb +2 -2
  55. data/lib/packetgen/header/ip.rb +30 -31
  56. data/lib/packetgen/header/ip/addr.rb +10 -3
  57. data/lib/packetgen/header/ip/option.rb +8 -10
  58. data/lib/packetgen/header/ip/options.rb +3 -5
  59. data/lib/packetgen/header/ipv6.rb +2 -2
  60. data/lib/packetgen/header/ipv6/addr.rb +9 -2
  61. data/lib/packetgen/header/ipv6/extension.rb +2 -2
  62. data/lib/packetgen/header/ipv6/hop_by_hop.rb +3 -3
  63. data/lib/packetgen/header/llc.rb +2 -2
  64. data/lib/packetgen/header/mdns.rb +2 -2
  65. data/lib/packetgen/header/mld.rb +2 -2
  66. data/lib/packetgen/header/mldv2.rb +2 -2
  67. data/lib/packetgen/header/mldv2/mcast_address_record.rb +4 -2
  68. data/lib/packetgen/header/mldv2/mlq.rb +2 -2
  69. data/lib/packetgen/header/mldv2/mlr.rb +2 -2
  70. data/lib/packetgen/header/ospfv2.rb +9 -9
  71. data/lib/packetgen/header/ospfv2/db_description.rb +2 -2
  72. data/lib/packetgen/header/ospfv2/hello.rb +2 -2
  73. data/lib/packetgen/header/ospfv2/ls_ack.rb +2 -2
  74. data/lib/packetgen/header/ospfv2/ls_request.rb +4 -2
  75. data/lib/packetgen/header/ospfv2/ls_update.rb +2 -2
  76. data/lib/packetgen/header/ospfv2/lsa.rb +9 -5
  77. data/lib/packetgen/header/ospfv2/lsa_header.rb +8 -7
  78. data/lib/packetgen/header/ospfv3.rb +2 -2
  79. data/lib/packetgen/header/ospfv3/db_description.rb +2 -2
  80. data/lib/packetgen/header/ospfv3/hello.rb +2 -2
  81. data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +4 -2
  82. data/lib/packetgen/header/ospfv3/ls_ack.rb +2 -2
  83. data/lib/packetgen/header/ospfv3/ls_request.rb +4 -2
  84. data/lib/packetgen/header/ospfv3/ls_update.rb +2 -2
  85. data/lib/packetgen/header/ospfv3/lsa.rb +5 -5
  86. data/lib/packetgen/header/ospfv3/lsa_header.rb +9 -8
  87. data/lib/packetgen/header/snmp.rb +33 -29
  88. data/lib/packetgen/header/tcp.rb +4 -23
  89. data/lib/packetgen/header/tcp/option.rb +11 -11
  90. data/lib/packetgen/header/tcp/options.rb +2 -2
  91. data/lib/packetgen/header/tftp.rb +6 -6
  92. data/lib/packetgen/header/udp.rb +3 -3
  93. data/lib/packetgen/headerable.rb +5 -4
  94. data/lib/packetgen/inject.rb +23 -0
  95. data/lib/packetgen/inspect.rb +23 -20
  96. data/lib/packetgen/packet.rb +96 -53
  97. data/lib/packetgen/pcap.rb +29 -0
  98. data/lib/packetgen/pcapng.rb +13 -13
  99. data/lib/packetgen/pcapng/block.rb +26 -13
  100. data/lib/packetgen/pcapng/epb.rb +25 -22
  101. data/lib/packetgen/pcapng/file.rb +260 -138
  102. data/lib/packetgen/pcapng/idb.rb +36 -38
  103. data/lib/packetgen/pcapng/shb.rb +51 -53
  104. data/lib/packetgen/pcapng/spb.rb +19 -19
  105. data/lib/packetgen/pcapng/unknown_block.rb +5 -13
  106. data/lib/packetgen/pcaprub_wrapper.rb +81 -0
  107. data/lib/packetgen/proto.rb +2 -2
  108. data/lib/packetgen/types.rb +3 -0
  109. data/lib/packetgen/types/abstract_tlv.rb +28 -8
  110. data/lib/packetgen/types/array.rb +22 -15
  111. data/lib/packetgen/types/cstring.rb +40 -16
  112. data/lib/packetgen/types/enum.rb +8 -3
  113. data/lib/packetgen/types/fieldable.rb +65 -0
  114. data/lib/packetgen/types/fields.rb +182 -117
  115. data/lib/packetgen/types/int.rb +18 -6
  116. data/lib/packetgen/types/int_string.rb +10 -2
  117. data/lib/packetgen/types/length_from.rb +20 -12
  118. data/lib/packetgen/types/oui.rb +4 -2
  119. data/lib/packetgen/types/string.rb +46 -8
  120. data/lib/packetgen/types/tlv.rb +4 -2
  121. data/lib/packetgen/utils.rb +4 -4
  122. data/lib/packetgen/utils/arp_spoofer.rb +2 -2
  123. data/lib/packetgen/version.rb +3 -3
  124. metadata +35 -50
  125. data/.gitignore +0 -13
  126. data/.rubocop.yml +0 -28
  127. data/.travis.yml +0 -17
  128. data/Gemfile +0 -4
  129. data/Rakefile +0 -21
  130. data/packetgen.gemspec +0 -36
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of PacketGen
2
4
  # See https://github.com/sdaubert/packetgen for more informations
3
5
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen
9
9
  module Header
10
10
  # TCP header ({https://tools.ietf.org/html/rfc793 RFC 793})
@@ -121,7 +121,7 @@ module PacketGen
121
121
  # @!attribute options
122
122
  # TCP options
123
123
  # @return [Options]
124
- define_field :options, TCP::Options
124
+ define_field :options, TCP::Options, builder: ->(h, t) { t.new(length_from: -> { h.data_offset > 5 ? (h.data_offset - 5) * 4 : 0 }) }
125
125
  # @!attribute body
126
126
  # @return [Types::String,Header::Base]
127
127
  define_field :body, Types::String
@@ -189,25 +189,6 @@ module PacketGen
189
189
  # @return [Boolean] 1-bit FIN flag
190
190
  define_bit_fields_on :u16, :_, 7, :flag_ns, :flag_cwr, :flag_ece, :flag_urg,
191
191
  :flag_ack, :flag_psh, :flag_rst, :flag_syn, :flag_fin
192
- # Read a TCP header from a string
193
- # @param [String] str binary string
194
- # @return [self]
195
- def read(str)
196
- return self if str.nil?
197
-
198
- force_binary str
199
- self[:sport].read str[0, 2]
200
- self[:dport].read str[2, 2]
201
- self[:seqnum].read str[4, 4]
202
- self[:acknum].read str[8, 4]
203
- self[:u16].read str[12, 2]
204
- self[:window].read str[14, 2]
205
- self[:checksum].read str[16, 2]
206
- self[:urg_pointer].read str[18, 2]
207
- self[:options].read str[20, (self.data_offset - 5) * 4] if self.data_offset > 5
208
- self[:body].read str[self.data_offset * 4..-1]
209
- self
210
- end
211
192
 
212
193
  # Compute checksum and set +checksum+ field
213
194
  # @return [Integer]
@@ -235,7 +216,7 @@ module PacketGen
235
216
  doff = Inspect.int_dec_hex(data_offset, 1)
236
217
  str << shift << Inspect::FMT_ATTR % ['', 'data_offset', doff]
237
218
  str << shift << Inspect::FMT_ATTR % ['', 'reserved', reserved]
238
- flags = ''.dup
219
+ flags = +''
239
220
  %w[ns cwr ece urg ack psh rst syn fin].each do |fl|
240
221
  flags << (send("flag_#{fl}?") ? fl[0].upcase : '.')
241
222
  end
@@ -1,16 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of PacketGen
2
4
  # See https://github.com/sdaubert/packetgen for more informations
3
5
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen
9
9
  module Header
10
10
  class TCP
11
11
  # Base class to describe a TCP option
12
12
  # @author Sylvain Daubert
13
13
  class Option < Types::Fields
14
+ include Types::Fieldable
15
+
14
16
  # EOL option value
15
17
  EOL_KIND = 0
16
18
  # NOP option value
@@ -91,15 +93,15 @@ module PacketGen
91
93
  # Setter for value attribute
92
94
  # @param[String,Integer]
93
95
  # @return [String, Integer]
94
- def value=(v)
96
+ def value=(val)
95
97
  case self[:value]
96
98
  when Types::Int
97
99
  self.length = 2 + self[:value].sz
98
- when String
99
- self.length = 2 + Types::String.new.read(v).sz
100
+ when Types::String
101
+ self.length = 2 + Types::String.new.read(val).sz
100
102
  end
101
- self[:value].read v
102
- v
103
+ self[:value].read val
104
+ val
103
105
  end
104
106
 
105
107
  # Get binary string
@@ -112,10 +114,8 @@ module PacketGen
112
114
  # Get option as a human readable string
113
115
  # @return [String]
114
116
  def to_human
115
- str = self.class == Option ? +"unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
116
- if (length > 2) && !self[:value].to_s.empty?
117
- str << ":#{self[:value].to_s.inspect}"
118
- end
117
+ str = self.instance_of?(Option) ? +"unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
118
+ str << ":#{self[:value].to_s.inspect}" if (length > 2) && !self[:value].to_s.empty?
119
119
  str
120
120
  end
121
121
 
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of PacketGen
2
4
  # See https://github.com/sdaubert/packetgen for more informations
3
5
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  require_relative 'option'
9
9
 
10
10
  module PacketGen
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of PacketGen
2
4
  # See https://github.com/sdaubert/packetgen for more informations
3
5
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen
9
9
  module Header
10
10
  # A TFTP (Trivial File Transfer Protocol,
@@ -49,10 +49,10 @@ module PacketGen
49
49
  class TFTP < Base
50
50
  # Known opcodes
51
51
  OPCODES = {
52
- 'RRQ' => 1,
53
- 'WRQ' => 2,
54
- 'DATA' => 3,
55
- 'ACK' => 4,
52
+ 'RRQ' => 1,
53
+ 'WRQ' => 2,
54
+ 'DATA' => 3,
55
+ 'ACK' => 4,
56
56
  'Error' => 5
57
57
  }.freeze
58
58
 
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of PacketGen
2
4
  # See https://github.com/sdaubert/packetgen for more informations
3
5
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen
9
9
  module Header
10
10
  # UDP header ({https://tools.ietf.org/html/rfc768 RFC 768})
@@ -71,7 +71,7 @@ module PacketGen
71
71
  # option is set.
72
72
  def initialize(options={})
73
73
  super
74
- self.length += self[:body].sz if self[:body].sz > 0
74
+ self.length += self[:body].sz if self[:body].sz.positive?
75
75
  end
76
76
 
77
77
  # Compute checksum and set +checksum+ field
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of PacketGen
2
4
  # See https://github.com/sdaubert/packetgen for more informations
3
5
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen
9
9
  # This mixin module defines minimal API for a class to act as a header
10
10
  # in {Packet}.
@@ -85,9 +85,10 @@ module PacketGen
85
85
  # @return [self]
86
86
  # @raise [NotImplementedError]
87
87
  def read(str)
88
+ # Do not call super and rescue NoMethodError: too slow
89
+ raise NotImplementedError, "#{self.class} should implement #read" if method(:read).super_method.nil?
90
+
88
91
  super
89
- rescue NoMethodError
90
- raise NotImplementedError, "#{self.class} should implement #read"
91
92
  end
92
93
  end
93
94
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of PacketGen
4
+ # See https://github.com/sdaubert/packetgen for more informations
5
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
6
+ # This program is published under MIT license.
7
+ require_relative 'pcaprub_wrapper'
8
+
9
+ module PacketGen
10
+ # Module to inject packets on wire
11
+ # @author Sylvain Daubert
12
+ # @api private
13
+ # @since 3.1.4
14
+ module Inject
15
+ # Inject given data onto wire
16
+ # @param [String] iface interface name
17
+ # @param [String,Packet,Header::Base] data to inject
18
+ # @return [void]
19
+ def self.inject(iface:, data:)
20
+ PCAPRUBWrapper.inject(iface: iface, data: data.to_s)
21
+ end
22
+ end
23
+ end
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of PacketGen
2
4
  # See https://github.com/sdaubert/packetgen for more informations
3
5
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen
9
9
  # {Inspect} module provides methods to help writing +inspect+
10
10
  # @api private
@@ -37,6 +37,25 @@ module PacketGen
37
37
  "%-16s (0x%0#{hexsize}x)" % [value.to_i, value.to_i]
38
38
  end
39
39
 
40
+ # @param [String] str
41
+ # @param [Integer] int
42
+ # @param [Integer] hexsize
43
+ # @return [String]
44
+ def self.enum_human_hex(str, int, hexsize)
45
+ "%-16s (0x%0#{hexsize}x)" % [str, int]
46
+ end
47
+
48
+ # Simple formatter to inspect an attribute
49
+ # @param [String] type attribute type
50
+ # @param [String] attr attribute name
51
+ # @param [String] value
52
+ # @param [Integer] level
53
+ # @return [String]
54
+ def self.format(type, attr, value, level=1)
55
+ str = Inspect.shift_level(level)
56
+ str << Inspect::FMT_ATTR % [type, attr, value]
57
+ end
58
+
40
59
  # Format an attribute for +#inspect+.
41
60
  # 3 cases are handled:
42
61
  # * attribute value is a {Types::Int}: show value as integer and in
@@ -48,24 +67,8 @@ module PacketGen
48
67
  # @param [Integer] level
49
68
  # @return [String]
50
69
  def self.inspect_attribute(attr, value, level=1)
51
- str = shift_level(level)
52
- val = case value
53
- when Types::Enum
54
- "%-16s (0x%0#{value.sz * 2}x)" % [value.to_human, value.to_i]
55
- when Types::Int
56
- int_dec_hex(value, value.sz * 2)
57
- when Integer
58
- int_dec_hex(value, value.sz * 2)
59
- when String
60
- value.to_s.inspect
61
- else
62
- if value.respond_to? :to_human
63
- value.to_human
64
- else
65
- value.to_s.inspect
66
- end
67
- end
68
- str << FMT_ATTR % [value.class.to_s.sub(/.*::/, ''), attr, val]
70
+ type = value.class.to_s.sub(/.*::/, '')
71
+ self.format(type, attr, value.format_inspect, level)
69
72
  end
70
73
 
71
74
  # Format a ASN.1 attribute for +#inspect+.
@@ -1,12 +1,12 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
3
+
2
4
  # This file is part of PacketGen
3
5
  # See https://github.com/sdaubert/packetgen for more informations
4
6
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
5
7
  # This program is published under MIT license.
6
8
 
7
- # frozen_string_literal: true
8
-
9
- require 'pcaprub'
9
+ # rubocop:disable Metrics/ClassLength
10
10
 
11
11
  module PacketGen
12
12
  # An object of type {Packet} handles a network packet. This packet may contain
@@ -79,36 +79,31 @@ module PacketGen
79
79
  # @yieldparam [Packet,String] packet if a block is given, yield each
80
80
  # captured packet (Packet or raw data String, depending on +:parse+ option)
81
81
  # @return [Array<Packet>] captured packet
82
- def self.capture(**kwargs)
83
- capture = Capture.new(kwargs)
82
+ def self.capture(**kwargs, &block)
83
+ capture = Capture.new(**kwargs)
84
84
  if block_given?
85
- capture.start { |packet| yield packet }
85
+ capture.start(&block)
86
86
  else
87
87
  capture.start
88
88
  end
89
89
  capture.packets
90
90
  end
91
91
 
92
- # Read packets from +filename+. Mays read Pcap and Pcap-NG formats.
92
+ # Read packets from +filename+. May read Pcap and Pcap-NG formats.
93
93
  #
94
- # For more control, see {PcapNG::File} or +PCAPRUB::Pcap+.
94
+ # For more control (on Pcap-ng only), see {PcapNG::File}.
95
95
  # @param [String] filename PcapNG or Pcap file.
96
96
  # @return [Array<Packet>]
97
+ # @raise [ArgumentError] unknown file format
97
98
  # @author Sylvain Daubert
98
99
  # @author Kent Gruber - Pcap format
99
100
  # @since 2.0.0 Also read Pcap format.
100
101
  def self.read(filename)
101
- PcapNG::File.new.read_packets filename
102
+ PcapNG::File.new.read_packets(filename)
102
103
  rescue StandardError => e
103
104
  raise ArgumentError, e unless File.extname(filename.downcase) == '.pcap'
104
105
 
105
- packets = []
106
- PCAPRUB::Pcap.open_offline(filename).each_packet do |packet|
107
- next unless (packet = PacketGen.parse(packet.to_s))
108
-
109
- packets << packet
110
- end
111
- packets
106
+ Pcap.read(filename)
112
107
  end
113
108
 
114
109
  # Write packets to +filename+
@@ -132,11 +127,13 @@ module PacketGen
132
127
  # @param [String] protocol
133
128
  # @param [Hash] options protocol specific options
134
129
  # @return [self]
135
- # @raise [ArgumentError] unknown protocol
130
+ # @raise [BindingError] unknown protocol
136
131
  def add(protocol, options={})
137
132
  klass = check_protocol(protocol)
138
133
 
139
- header = klass.new(options.merge!(packet: self))
134
+ # options[:packet]= self is speedier than options.merge(packet: self)
135
+ options[:packet] = self
136
+ header = klass.new(options)
140
137
  add_header header
141
138
  self
142
139
  end
@@ -146,12 +143,14 @@ module PacketGen
146
143
  # @param [String] protocol protocol to insert
147
144
  # @param [Hash] options protocol specific options
148
145
  # @return [self]
149
- # @raise [ArgumentError] unknown protocol
146
+ # @raise [BindingError] unknown protocol
150
147
  def insert(prev, protocol, options={})
151
148
  klass = check_protocol(protocol)
152
149
 
153
150
  nxt = prev.body
154
- header = klass.new(options.merge!(packet: self))
151
+ # options[:packet]= self is speedier than options.merge(packet: self)
152
+ options[:packet] = self
153
+ header = klass.new(options)
155
154
  add_header header, previous_header: prev
156
155
  idx = headers.index(prev) + 1
157
156
  headers[idx, 0] = header
@@ -217,7 +216,7 @@ module PacketGen
217
216
  # @return [Array] see return from {PcapNG::File#to_file}
218
217
  # @see File
219
218
  def to_f(filename)
220
- PcapNG::File.new.array_to_file(filename: filename, array: [self])
219
+ PcapNG::File.new.array_to_file(file: filename, array: [self])
221
220
  end
222
221
  alias write to_f
223
222
 
@@ -251,10 +250,11 @@ module PacketGen
251
250
  # from binding with first other's one. Use only when current header field
252
251
  # has its value set accordingly.
253
252
  # @return [self] +self+ with new headers from +other+
253
+ # @raise [BindingError] do not known how to encapsulate
254
254
  # @since 1.1.0
255
255
  def encapsulate(other, parsing: false)
256
256
  other.headers.each_with_index do |h, i|
257
- add_header h, parsing: (i > 0) || parsing
257
+ add_header h, parsing: i.positive? || parsing
258
258
  end
259
259
  end
260
260
 
@@ -262,36 +262,32 @@ module PacketGen
262
262
  # @param [Array<Header>] hdrs
263
263
  # @return [self] +self+ with some headers removed
264
264
  # @raise [FormatError] any headers not in +self+
265
- # @raise [FormatError] removed headers result in an unknown binding
265
+ # @raise [BindingError] removed headers result in an unknown binding
266
266
  # @since 1.1.0
267
267
  def decapsulate(*hdrs)
268
268
  hdrs.each do |hdr|
269
- idx = headers.index(hdr)
270
- raise FormatError, 'header not in packet!' if idx.nil?
271
-
272
- prev_hdr = idx > 0 ? headers[idx - 1] : nil
273
- next_hdr = (idx + 1) < headers.size ? headers[idx + 1] : nil
274
- headers.delete_at(idx)
269
+ prev_hdr = previous_header(hdr)
270
+ next_hdr = next_header(hdr)
271
+ headers.delete(hdr)
275
272
  add_header(next_hdr, previous_header: prev_hdr) if prev_hdr && next_hdr
276
273
  end
277
- rescue ArgumentError => ex
278
- raise FormatError, ex.message
274
+ rescue ArgumentError => e
275
+ raise FormatError, e.message
279
276
  end
280
277
 
281
278
  # Parse a binary string and populate Packet from it.
282
279
  # @param [String] binary_str
283
280
  # @param [String,nil] first_header First protocol header. +nil+ means discover it!
284
281
  # @return [Packet] self
285
- # @raise [ArgumentError] +first_header+ is an unknown header
282
+ # @raise [ParseError] +first_header+ is an unknown header
283
+ # @raise [BindingError] unknwon binding between some headers
286
284
  def parse(binary_str, first_header: nil)
287
285
  headers.clear
288
286
 
289
287
  if first_header.nil?
290
288
  # No decoding forced for first header. Have to guess it!
291
289
  first_header = guess_first_header(binary_str)
292
- if first_header.nil?
293
- raise ParseError, 'cannot identify first header in string'
294
- end
290
+ raise ParseError, 'cannot identify first header in string' if first_header.nil?
295
291
  end
296
292
 
297
293
  add first_header
@@ -318,6 +314,20 @@ module PacketGen
318
314
  to_s == other.to_s
319
315
  end
320
316
 
317
+ # @param [Packet] other
318
+ # @return [Boolean]
319
+ # @since 3.1.2
320
+ def ===(other)
321
+ case other
322
+ when PacketGen::Packet
323
+ self == other
324
+ when String
325
+ is? other
326
+ else
327
+ false
328
+ end
329
+ end
330
+
321
331
  # Invert all possible fields in packet to create a reply.
322
332
  # @return [self]
323
333
  # @since 2.7.0
@@ -360,6 +370,35 @@ module PacketGen
360
370
  headers.last
361
371
  end
362
372
 
373
+ # Give header index in packet
374
+ # @param [Headerable] hdr
375
+ # @return [Integer]
376
+ # @raise [FormatError] +hdr+ not in packet
377
+ def header_index(hdr)
378
+ idx = headers.index(hdr)
379
+ raise FormatError, 'header not in packet!' if idx.nil?
380
+
381
+ idx
382
+ end
383
+
384
+ # Give header previous +hdr+ in packet
385
+ # @param [Headerable] hdr
386
+ # @return [Headerable,nil] May return +nil+ if +hdr+ is the first header in packet
387
+ # @raise [FormatError] +hdr+ not in packet
388
+ def previous_header(hdr)
389
+ idx = header_index(hdr)
390
+ idx.positive? ? headers[idx - 1] : nil
391
+ end
392
+
393
+ # Give header next +hdr+ in packet
394
+ # @param [Headerable] hdr
395
+ # @return [Headerable,nil] May return +nil+ if +hdr+ is the last header in packet
396
+ # @raise [FormatError] +hdr+ not in packet
397
+ def next_header(hdr)
398
+ idx = header_index(hdr)
399
+ (idx + 1) < headers.size ? headers[idx + 1] : nil
400
+ end
401
+
363
402
  # @overload header(klass, layer=1)
364
403
  # @param [Class] klass
365
404
  # @param [Integer] layer
@@ -374,9 +413,8 @@ module PacketGen
374
413
  return header unless arg.is_a? Hash
375
414
 
376
415
  arg.each do |key, value|
377
- unless header.respond_to? "#{key}="
378
- raise ArgumentError, "unknown #{key} attribute for #{klass}"
379
- end
416
+ raise ArgumentError, "unknown #{key} attribute for #{klass}" unless header.respond_to? "#{key}="
417
+
380
418
  header.send "#{key}=", value
381
419
  end
382
420
 
@@ -394,26 +432,15 @@ module PacketGen
394
432
  end
395
433
 
396
434
  # Add a header to packet
397
- # @param [Header::Base] header
398
- # @param [Header::Base] previous_header
435
+ # @param [Headerable] header
436
+ # @param [Headerable] previous_header
399
437
  # @param [Boolean] parsing
400
438
  # @return [void]
439
+ # @raise [BindingError]
401
440
  def add_header(header, previous_header: nil, parsing: false)
402
441
  prev_header = previous_header || last_header
403
- if prev_header
404
- bindings = prev_header.class.known_headers[header.class]
405
- bindings = prev_header.class.known_headers[header.class.superclass] if bindings.nil?
406
- if bindings.nil?
407
- msg = "#{prev_header.class} knowns no layer association with #{header.protocol_name}. ".dup
408
- msg << "Try #{prev_header.class}.bind_layer(#{header.class}, "
409
- msg << "#{prev_header.method_name}_proto_field: "
410
- msg << "value_for_#{header.method_name})"
411
- raise ArgumentError, msg
412
- end
442
+ add_to_previous_header(prev_header, header, parsing) if prev_header
413
443
 
414
- bindings.set(prev_header) if !bindings.empty? && !parsing
415
- prev_header[:body] = header
416
- end
417
444
  header.packet = self
418
445
  headers << header unless previous_header
419
446
 
@@ -422,6 +449,20 @@ module PacketGen
422
449
  add_magic_header_method header
423
450
  end
424
451
 
452
+ # Bind +header+ to +prev_header+.
453
+ # @param [Headerable] prev_header
454
+ # @param [Headerable] header
455
+ # @param [Boolean] parsing
456
+ # @return [void]
457
+ # @raise [BindingError]
458
+ def add_to_previous_header(prev_header, header, parsing)
459
+ bindings = prev_header.class.known_headers[header.class] || prev_header.class.known_headers[header.class.superclass]
460
+ raise BindingError.new(prev_header, header) if bindings.nil?
461
+
462
+ bindings.set(prev_header) if !bindings.empty? && !parsing
463
+ prev_header[:body] = header
464
+ end
465
+
425
466
  # Add method to access +header+
426
467
  # @param [Header::Base] header
427
468
  # @return [void]
@@ -483,5 +524,7 @@ module PacketGen
483
524
  end
484
525
  end
485
526
 
527
+ # rubocop:enable Metrics/ClassLength
528
+
486
529
  require_relative 'headerable'
487
530
  require_relative 'header'