packetgen 2.8.7 → 3.0.0

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -1
  3. data/README.md +5 -4
  4. data/lib/packetgen.rb +6 -12
  5. data/lib/packetgen/capture.rb +43 -39
  6. data/lib/packetgen/config.rb +0 -1
  7. data/lib/packetgen/deprecation.rb +1 -1
  8. data/lib/packetgen/header.rb +9 -9
  9. data/lib/packetgen/header/asn1_base.rb +10 -10
  10. data/lib/packetgen/header/base.rb +42 -101
  11. data/lib/packetgen/header/dhcp/option.rb +5 -11
  12. data/lib/packetgen/header/dhcpv6/duid.rb +2 -0
  13. data/lib/packetgen/header/dhcpv6/option.rb +2 -19
  14. data/lib/packetgen/header/dhcpv6/options.rb +7 -0
  15. data/lib/packetgen/header/dns.rb +5 -23
  16. data/lib/packetgen/header/dns/name.rb +1 -0
  17. data/lib/packetgen/header/dns/qdsection.rb +1 -0
  18. data/lib/packetgen/header/dns/question.rb +3 -7
  19. data/lib/packetgen/header/dns/rr.rb +3 -0
  20. data/lib/packetgen/header/dns/rrsection.rb +1 -0
  21. data/lib/packetgen/header/dot11.rb +1 -17
  22. data/lib/packetgen/header/dot1x.rb +1 -0
  23. data/lib/packetgen/header/eap.rb +4 -7
  24. data/lib/packetgen/header/eth.rb +2 -0
  25. data/lib/packetgen/header/http/headers.rb +3 -0
  26. data/lib/packetgen/header/http/request.rb +5 -4
  27. data/lib/packetgen/header/http/response.rb +5 -4
  28. data/lib/packetgen/header/icmp.rb +6 -0
  29. data/lib/packetgen/header/icmpv6.rb +6 -0
  30. data/lib/packetgen/header/igmpv3/mq.rb +2 -0
  31. data/lib/packetgen/header/ip.rb +32 -30
  32. data/lib/packetgen/header/ip/addr.rb +1 -0
  33. data/lib/packetgen/header/ip/option.rb +23 -20
  34. data/lib/packetgen/header/ip/options.rb +11 -24
  35. data/lib/packetgen/header/ipv6.rb +45 -34
  36. data/lib/packetgen/header/ipv6/addr.rb +2 -0
  37. data/lib/packetgen/header/ipv6/hop_by_hop.rb +7 -31
  38. data/lib/packetgen/header/mdns.rb +1 -0
  39. data/lib/packetgen/header/mldv2/mlq.rb +2 -0
  40. data/lib/packetgen/header/ospfv2/lsa.rb +15 -25
  41. data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +1 -1
  42. data/lib/packetgen/header/ospfv3/lsa.rb +8 -25
  43. data/lib/packetgen/header/snmp.rb +2 -0
  44. data/lib/packetgen/header/tcp.rb +23 -2
  45. data/lib/packetgen/header/tcp/option.rb +51 -52
  46. data/lib/packetgen/header/tcp/options.rb +17 -52
  47. data/lib/packetgen/header/tftp.rb +3 -0
  48. data/lib/packetgen/header/udp.rb +8 -0
  49. data/lib/packetgen/packet.rb +119 -102
  50. data/lib/packetgen/pcapng/block.rb +4 -10
  51. data/lib/packetgen/pcapng/epb.rb +4 -4
  52. data/lib/packetgen/pcapng/file.rb +7 -3
  53. data/lib/packetgen/pcapng/idb.rb +2 -2
  54. data/lib/packetgen/pcapng/shb.rb +3 -3
  55. data/lib/packetgen/pcapng/spb.rb +1 -8
  56. data/lib/packetgen/pcapng/unknown_block.rb +0 -7
  57. data/lib/packetgen/types.rb +1 -0
  58. data/lib/packetgen/types/array.rb +73 -71
  59. data/lib/packetgen/types/cstring.rb +1 -1
  60. data/lib/packetgen/types/enum.rb +3 -3
  61. data/lib/packetgen/types/fields.rb +66 -106
  62. data/lib/packetgen/types/int.rb +9 -5
  63. data/lib/packetgen/types/length_from.rb +45 -0
  64. data/lib/packetgen/types/oui.rb +2 -0
  65. data/lib/packetgen/types/string.rb +10 -16
  66. data/lib/packetgen/types/tlv.rb +7 -15
  67. data/lib/packetgen/utils.rb +8 -8
  68. data/lib/packetgen/utils/arp_spoofer.rb +1 -2
  69. data/lib/packetgen/version.rb +1 -1
  70. metadata +3 -21
  71. data/lib/packetgen/header/crypto.rb +0 -62
  72. data/lib/packetgen/header/esp.rb +0 -413
  73. data/lib/packetgen/header/ike.rb +0 -243
  74. data/lib/packetgen/header/ike/auth.rb +0 -165
  75. data/lib/packetgen/header/ike/cert.rb +0 -76
  76. data/lib/packetgen/header/ike/certreq.rb +0 -66
  77. data/lib/packetgen/header/ike/id.rb +0 -99
  78. data/lib/packetgen/header/ike/ke.rb +0 -79
  79. data/lib/packetgen/header/ike/nonce.rb +0 -40
  80. data/lib/packetgen/header/ike/notify.rb +0 -176
  81. data/lib/packetgen/header/ike/payload.rb +0 -315
  82. data/lib/packetgen/header/ike/sa.rb +0 -561
  83. data/lib/packetgen/header/ike/sk.rb +0 -261
  84. data/lib/packetgen/header/ike/ts.rb +0 -270
  85. data/lib/packetgen/header/ike/vendor_id.rb +0 -39
  86. data/lib/packetgen/header/netbios.rb +0 -20
  87. data/lib/packetgen/header/netbios/datagram.rb +0 -105
  88. data/lib/packetgen/header/netbios/name.rb +0 -67
  89. data/lib/packetgen/header/netbios/session.rb +0 -64
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9619d169e7a064e415e479dd208f15339f59700baf805bbc7a79437967c1cd5
4
- data.tar.gz: 4d1ceeeee51b56dab91331e43672b7fe15ddeb87971bb36bc5670399f2e55080
3
+ metadata.gz: 072c0bb14448db25532a552f9b8a5c83b2363d7ccb3692d478f3224a8cc34807
4
+ data.tar.gz: b2b857e9793aa1dabf0a89562958187087afabb10318cf947d9c2ce12696c39d
5
5
  SHA512:
6
- metadata.gz: a0a27dd879ec6c9362bade001b6f6701686f80a589d2dd75478f5894dbaf8bd5b766f00f692437dca4ecbf96ceb830d4fcfeaef2e2354bccec7addd76f4b7ab8
7
- data.tar.gz: bfb2b7de3b541c85cd1d367b4d8976d78d47c9872cabafd46cba12751926128f6a664c687520b28b7224af8439829219f9f6ad5a950de5878c9ee6f1d9b14243
6
+ metadata.gz: d5bb7c964881ae0f2df1845d82b449cf1a80c25432c740dc1e7ce6436b4323e03586d40760939d554daba0080a15d776cbe8b7fed04c07983a77aaad9c2e0e3d
7
+ data.tar.gz: 9a2d0bd3355ec82bb40c0ed3a4377852314e74bb6f3479142810d637ca5f189279c7d8f3ae0bc59eea6ffc8f91d19264a2d0ced8d39c49cfc91a9d004d9bbe47
data/.rubocop.yml CHANGED
@@ -1,4 +1,3 @@
1
- TargetRubyVersion: 2.3
2
1
  Layout/SpaceAroundEqualsInParameterDefault:
3
2
  EnforcedStyle: no_space
4
3
  Lint/EmptyWhen:
data/README.md CHANGED
@@ -114,8 +114,8 @@ First, define the new header class. For example:
114
114
  ```ruby
115
115
  module MyModule
116
116
  class MyHeader < PacketGen::Header::Base
117
- define_field :field1, PacketGen::Types::Int32
118
- define_field :field2, PacketGen::Types::Int32
117
+ define_field :field1, PacketGen::Types::Int32
118
+ define_field :field2, PacketGen::Types::Int32
119
119
  end
120
120
  end
121
121
  ```
@@ -161,8 +161,9 @@ If `pry` gem is installed, it is used as backend for `pgconsole`, else IRB is us
161
161
 
162
162
  PacketGen provides a plugin system (see [wiki](https://github.com/sdaubert/packetgen/wiki/Create-Custom-Protocol)).
163
163
 
164
- For now, there is only one plugin available as a gem:
164
+ Available plugins (available as gem) are:
165
165
 
166
+ * [packetgen-plugin-ipsec](https://github.com/sdaubert/packetgen-plugin-ipsec): add support for ESP and IKEv2 protocols. Before PacketGen3, these protocols were included in packetgen.
166
167
  * [packetgen-plugin-smb](https://github.com/sdaubert/packetgen-plugin-smb): add (limited) support for SMB protocol suite.
167
168
 
168
169
  ## See also
@@ -173,7 +174,7 @@ API documentation: http://www.rubydoc.info/gems/packetgen
173
174
 
174
175
  ## Contributing
175
176
 
176
- Bug reports and pull requests are welcome on GitHub at https://github.com/sdaubert/packetgen-plugin-smb.
177
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sdaubert/packetgen.
177
178
 
178
179
  ## License
179
180
 
data/lib/packetgen.rb CHANGED
@@ -7,6 +7,7 @@
7
7
  # frozen_string_literal: true
8
8
 
9
9
  require 'packetgen/version'
10
+ require 'interfacez'
10
11
 
11
12
  # PacketGen is a network packet generator and analyzor.
12
13
  # @author Sylvain Daubert
@@ -40,11 +41,12 @@ module PacketGen
40
41
  end
41
42
 
42
43
  # Shortcut for {Packet.capture}
43
- # @param [Hash] options capture options. See {Packet.capture}.
44
+ # Same arguments as {Capture#initialize}
45
+ # @see Capture#initialize
44
46
  # @yieldparam [Packet] packet
45
47
  # @return [Array<Packet>]
46
- def self.capture(options={})
47
- Packet.capture(options) { |packet| yield packet if block_given? }
48
+ def self.capture(**kwargs)
49
+ Packet.capture(kwargs) { |packet| yield packet if block_given? }
48
50
  end
49
51
 
50
52
  # Shortcut for {Packet.read}
@@ -72,15 +74,7 @@ module PacketGen
72
74
  # Get default network interface (ie. first non-loopback declared interface)
73
75
  # @return [String]
74
76
  def self.default_iface
75
- return @default_iface if @default_iface
76
-
77
- ipaddr = `ip addr`.split("\n")
78
- @default_iface = ipaddr.each do |line|
79
- m = line.match(/^\d+: (\w+\d+):/)
80
- next if m.nil?
81
- next if m[1].start_with? 'lo'
82
- break m[1]
83
- end
77
+ Interfacez.default
84
78
  end
85
79
 
86
80
  # Shortcut to get a header class
@@ -5,8 +5,6 @@
5
5
 
6
6
  # frozen_string_literal: true
7
7
 
8
- require 'interfacez'
9
-
10
8
  module PacketGen
11
9
  # Capture packets from wire
12
10
  # @author Sylvain Daubert
@@ -15,6 +13,12 @@ module PacketGen
15
13
  # Default snaplen to use if :snaplen option not defined.
16
14
  DEFAULT_SNAPLEN = 0xffff
17
15
 
16
+ private
17
+
18
+ attr_reader :filter, :cap_thread
19
+
20
+ public
21
+
18
22
  # Get captured packets.
19
23
  # @return [Array<Packets>]
20
24
  attr_reader :packets
@@ -27,53 +31,53 @@ module PacketGen
27
31
  # @return [String]
28
32
  attr_reader :iface
29
33
 
30
- # @param [Hash] options
31
- # @option options [String] :iface interface on which capture
34
+ # @param [String] iface interface on which capture
32
35
  # packets on. Default: Use default interface lookup. If no interface found,
33
36
  # use loopback one.
34
- # @option options [Integer] :max maximum number of packets to capture.
35
- # @option options [Integer] :timeout maximum number of seconds before end
37
+ # @param [Integer] max maximum number of packets to capture.
38
+ # @param [Integer] timeout maximum number of seconds before end
36
39
  # of capture. Default: +nil+ (no timeout)
37
- # @option options [String] :filter bpf filter
38
- # @option options [Boolean] :promiscuous (default: +false+)
39
- # @option options [Boolean] :parse parse raw data to generate packets before
40
+ # @param [String] filter bpf filter
41
+ # @param [Boolean] promisc (default: +false+)
42
+ # @param [Boolean] parse parse raw data to generate packets before
40
43
  # yielding. Default: +true+
41
- # @option options [Integer] :snaplen maximum number of bytes to capture for
44
+ # @param [Integer] snaplen maximum number of bytes to capture for
42
45
  # each packet.
43
46
  # @since 2.0.0 remove old 1.x API
44
- def initialize(options={})
45
- @iface = Interfacez.default || Interfacez.loopback
47
+ # @since 3.0.0 arguments are kwargs and nor more a hash
48
+ def initialize(iface: nil, max: nil, timeout: nil, filter: nil, promisc: false, parse: true, snaplen: DEFAULT_SNAPLEN)
49
+ @iface = iface || Interfacez.default || Interfacez.loopback
46
50
 
47
51
  @packets = []
48
52
  @raw_packets = []
49
- @promisc = false
50
- @snaplen = DEFAULT_SNAPLEN
51
- @parse = true
52
- set_options options
53
+ set_options iface, max, timeout, filter, promisc, parse, snaplen
53
54
  end
54
55
 
55
56
  # Start capture
56
- # @param [Hash] options complete see {#initialize}.
57
+ # @see {#initialize} for parameters
57
58
  # @yieldparam [Packet,String] packet if a block is given, yield each
58
59
  # captured packet (Packet or raw data String, depending on +:parse+ option)
59
- def start(options={})
60
- set_options options
61
- @pcap = PCAPRUB::Pcap.open_live(@iface, @snaplen, @promisc, 1)
62
- set_filter
60
+ # @since 3.0.0 arguments are kwargs and nor more a hash
61
+ def start(iface: nil, max: nil, timeout: nil, filter: nil, promisc: false, parse: true, snaplen: DEFAULT_SNAPLEN)
62
+ set_options iface, max, timeout, filter, promisc, parse, snaplen
63
+
64
+ pcap = PCAPRUB::Pcap.open_live(self.iface, @snaplen, @promisc, 1)
65
+ set_filter_on pcap
66
+
63
67
  @cap_thread = Thread.new do
64
- @pcap.each do |packet_data|
65
- @raw_packets << packet_data
68
+ pcap.each do |packet_data|
69
+ raw_packets << packet_data
66
70
  if @parse
67
71
  packet = Packet.parse(packet_data)
68
- @packets << packet
72
+ packets << packet
69
73
  yield packet if block_given?
70
74
  elsif block_given?
71
75
  yield packet_data
72
76
  end
73
- break if @max && @raw_packets.size >= @max
77
+ break if defined?(@max) && (raw_packets.size >= @max)
74
78
  end
75
79
  end
76
- @cap_thread.join(@timeout)
80
+ cap_thread.join(@timeout)
77
81
  end
78
82
 
79
83
  # Stop capture. Should be used from another thread, as {#start} blocks.
@@ -82,25 +86,25 @@ module PacketGen
82
86
  # has been made to make Capture nor PacketGen thread-safe.
83
87
  # @return [void]
84
88
  def stop
85
- @cap_thread.kill
89
+ cap_thread.kill
86
90
  end
87
91
 
88
92
  private
89
93
 
90
- def set_options(options)
91
- @max = options[:max] if options[:max]
92
- @filter = options[:filter] if options[:filter]
93
- @timeout = options[:timeout] if options[:timeout]
94
- @promisc = options[:promisc] if options.key? :promisc
95
- @snaplen = options[:snaplen] if options[:snaplen]
96
- @parse = options[:parse] if options.key? :parse
97
- @iface = options[:iface] if options[:iface]
94
+ def set_options(iface, max, timeout, filter, promisc, parse, snaplen)
95
+ @max = max if max
96
+ @filter = filter unless filter.nil?
97
+ @timeout = timeout unless timeout.nil?
98
+ @promisc = promisc unless promisc.nil?
99
+ @snaplen = snaplen unless snaplen.nil?
100
+ @parse = parse unless parse.nil?
101
+ @iface = iface unless iface.nil?
98
102
  end
99
103
 
100
- def set_filter
101
- return if @filter.nil?
102
- return if @filter.empty?
103
- @pcap.setfilter @filter
104
+ def set_filter_on(pcap)
105
+ return if filter.nil? || filter.empty?
106
+
107
+ pcap.setfilter filter
104
108
  end
105
109
  end
106
110
  end
@@ -7,7 +7,6 @@
7
7
 
8
8
  require 'socket'
9
9
  require 'singleton'
10
- require 'interfacez'
11
10
 
12
11
  module PacketGen
13
12
  # Config class to provide +config+ object to pgconsole
@@ -4,7 +4,7 @@ module PacketGen
4
4
  # @author Sylvain Daubert
5
5
  # @api private
6
6
  module Deprecation
7
- def self.deprecated(klass, deprecated_method, new_method=nil, klass_method: false, remove_version: '3.0.0')
7
+ def self.deprecated(klass, deprecated_method, new_method=nil, klass_method: false, remove_version: '4.0.0')
8
8
  separator = klass_method ? '.' : '#'
9
9
  base_name = klass.to_s + separator
10
10
  complete_deprecated_method_name = base_name + deprecated_method.to_s
@@ -7,9 +7,12 @@
7
7
  # frozen_string_literal: true
8
8
 
9
9
  module PacketGen
10
- # Namespace for protocol header classes
10
+ # Namespace for protocol header classes.
11
+ #
12
+ # This namespace handles all buitlin headers, such as {IP} or {TCP}.
13
+ #
11
14
  # == Add a foreign header class
12
- # Since v1.1.0, PacketGen permits adding you own header classes.
15
+ # PacketGen permits adding you own header classes.
13
16
  # First, define the new header class. By example:
14
17
  # module MyModule
15
18
  # class MyHeader < PacketGen::Header::Base
@@ -40,7 +43,8 @@ module PacketGen
40
43
  # List all available headers.
41
44
  # @return [Array<Class>]
42
45
  def all
43
- return @header_classes if @header_classes
46
+ return @header_classes if defined?(@header_classes) && @header_classes
47
+
44
48
  @header_classes = @added_header_classes.values
45
49
  end
46
50
  alias list all
@@ -51,7 +55,7 @@ module PacketGen
51
55
  # @return [void]
52
56
  # @since 1.1.0
53
57
  def add_class(klass)
54
- protocol_name = klass.new.protocol_name
58
+ protocol_name = klass.protocol_name
55
59
  @added_header_classes[protocol_name] = klass
56
60
  @header_classes = nil
57
61
  end
@@ -62,7 +66,7 @@ module PacketGen
62
66
  # @return [void]
63
67
  # @since 1.1.0
64
68
  def remove_class(klass)
65
- protocol_name = klass.new.protocol_name
69
+ protocol_name = klass.protocol_name
66
70
  @added_header_classes.delete protocol_name
67
71
  @header_classes = nil
68
72
  end
@@ -82,7 +86,6 @@ module PacketGen
82
86
  end
83
87
  end
84
88
 
85
- require_relative 'header/crypto'
86
89
  require_relative 'header/base'
87
90
  require_relative 'header/eth'
88
91
  require_relative 'header/dot11'
@@ -98,8 +101,6 @@ require_relative 'header/gre'
98
101
  require_relative 'header/udp'
99
102
  require_relative 'header/tcp'
100
103
  require_relative 'header/eap'
101
- require_relative 'header/esp'
102
- require_relative 'header/ike'
103
104
  require_relative 'header/dns'
104
105
  require_relative 'header/asn1_base'
105
106
  require_relative 'header/snmp'
@@ -114,5 +115,4 @@ require_relative 'header/mld'
114
115
  require_relative 'header/mldv2'
115
116
  require_relative 'header/ospfv2'
116
117
  require_relative 'header/ospfv3'
117
- require_relative 'header/netbios'
118
118
  require_relative 'header/mdns'
@@ -25,7 +25,14 @@ module PacketGen
25
25
  # @return [String]
26
26
  # @since 2.0.0
27
27
  def self.protocol_name
28
- self.new.protocol_name
28
+ return @protocol_name if defined? @protocol_name
29
+
30
+ classname = to_s
31
+ @protocol_name = if classname.start_with?('PacketGen::Header')
32
+ classname.sub(/.*Header::/, '')
33
+ else
34
+ classname.sub(/.*::/, '')
35
+ end
29
36
  end
30
37
 
31
38
  # Define some methods from given ASN.1 fields to mimic {Base} attributes
@@ -42,21 +49,14 @@ module PacketGen
42
49
  # Return header protocol name
43
50
  # @return [String]
44
51
  def protocol_name
45
- return @protocol_name if @protocol_name
46
-
47
- classname = self.class.to_s
48
- @protocol_name = if classname.start_with?('PacketGen::Header')
49
- classname.sub(/.*Header::/, '')
50
- else
51
- classname.sub(/.*::/, '')
52
- end
52
+ self.class.protocol_name
53
53
  end
54
54
 
55
55
  # return header method name
56
56
  # @return [String]
57
57
  # @since 2.0.0
58
58
  def method_name
59
- return @method_name if @method_name
59
+ return @method_name if defined? @method_name
60
60
 
61
61
  @method_name = protocol_name.downcase.sub(/::/, '_')
62
62
  end
@@ -11,7 +11,7 @@ module PacketGen
11
11
  # Subclasses may define magic methods:
12
12
  # * +#calc_checksum+, which computes header checksum,
13
13
  # * +#calc_length+, which computes header length,
14
- # * +#parse?+,
14
+ # * {#parse?},
15
15
  # * +#reply!+, which inverts needed fields to forge a response.
16
16
  # @author Sylvain Daubert
17
17
  class Base < Types::Fields
@@ -78,30 +78,21 @@ module PacketGen
78
78
  class Bindings
79
79
  include Enumerable
80
80
 
81
- # op type
82
- # @return [:or,:and]
83
- attr_accessor :op
84
81
  # @return [Array<Binding>]
85
82
  attr_accessor :bindings
86
83
 
87
- # @param [:or, :and, :newstyle] operator
88
- def initialize(operator)
89
- @op = operator
84
+ def initialize
90
85
  @bindings = []
91
86
  end
92
87
 
93
88
  def new_set
94
- @bindings << [] if @op == :newstyle
89
+ @bindings << []
95
90
  end
96
91
 
97
92
  # @param [Object] arg
98
- # @return [OldBindings] self
93
+ # @return [Bindings] self
99
94
  def <<(arg)
100
- if op == :newstyle
101
- @bindings.last << arg
102
- else
103
- @bindings << arg
104
- end
95
+ @bindings.last << arg
105
96
  end
106
97
 
107
98
  # each iterator
@@ -117,15 +108,12 @@ module PacketGen
117
108
  @bindings.empty?
118
109
  end
119
110
 
111
+ # Return binding as a hash.
120
112
  # @return [Hash]
121
113
  def to_h
122
114
  hsh = {}
123
115
  each do |b|
124
- if b.is_a? Array
125
- b.each { |sb| hsh[sb.key] = sb.value }
126
- else
127
- hsh[b.key] = b.value
128
- end
116
+ b.each { |sb| hsh[sb.key] = sb.value }
129
117
  end
130
118
  hsh
131
119
  end
@@ -134,26 +122,14 @@ module PacketGen
134
122
  # @param [Types::Fields] fields
135
123
  # @return [Boolean]
136
124
  def check?(fields)
137
- case @op
138
- when :or
139
- empty? || @bindings.any? { |binding| binding.check?(fields) }
140
- when :and
141
- @bindings.all? { |binding| binding.check?(fields) }
142
- when :newstyle
143
- @bindings.any? { |group| group.all? { |binding| binding.check?(fields) } }
144
- end
125
+ @bindings.any? { |group| group.all? { |binding| binding.check?(fields) } }
145
126
  end
146
127
 
147
128
  # Set +fields+ to bindings value
148
129
  # @param [Types::Fields] fields
149
130
  # @return [void]
150
131
  def set(fields)
151
- case @bindings.first
152
- when Array
153
- @bindings.first.each { |b| b.set fields }
154
- else
155
- @bindings.each { |b| b.set fields }
156
- end
132
+ @bindings.first.each { |b| b.set fields }
157
133
  end
158
134
  end
159
135
 
@@ -161,6 +137,7 @@ module PacketGen
161
137
  # @return [Packet,nil]
162
138
  attr_reader :packet
163
139
 
140
+ # @private
164
141
  # On inheritage, create +@known_header+ class variable
165
142
  # @param [Class] klass
166
143
  # @return [void]
@@ -169,79 +146,41 @@ module PacketGen
169
146
  klass.class_eval { @known_headers = {} }
170
147
  end
171
148
 
172
- # Bind a upper header to current class
173
- # Header1.bind_header Header2, field1: 43
174
- # Header1.bind_header Header3, field1: 43, field2: 43
175
- # Header1.bind_header Header4, op: :and, field1: 43, field2: 43
176
- # Header1.bind_header Header5, field1: ->(v) { v.nil? ? 128 : v > 127 }
177
- # Header1.bind_header Header6, procs: [->(hdr) { hdr.field1 = 1 }
178
- # ->(hdr) { hdr.field1 == 1 && hdr.body[0..1] == "\x00\x00" }]
149
+ # Bind a upper header to current one.
179
150
  # @param [Class] header_klass header class to bind to current class
180
151
  # @param [Hash] args current class fields and their value when +header_klass+
181
- # is embedded in current class. Given value may be a lambda, whose alone argument
182
- # is the value extracted from header field (or +nil+ when lambda is used to set
183
- # field while adding a header).
152
+ # is embedded in current class.
184
153
  #
185
- # If multiple fields are given, a special key +:op+ may be given to set parse
186
- # operation on this binding. By default, +:op+ is +:or+ (at least one binding
187
- # must match to parse it). It also may be set to +:and+ (all bindings must match
188
- # to parse it).
154
+ # Given value may be a lambda, whose alone argument is the value extracted
155
+ # from header field (or +nil+ when lambda is used to set field while adding
156
+ # a header).
189
157
  #
190
158
  # Special key +procs+ may be used to set 2 lambdas, the former to set
191
159
  # fields, the latter to check bindings. This may be used when multiple and
192
160
  # non-trivial checks should be made.
193
161
  # @return [void]
194
- # @deprecated Use {.bind} instead.
195
- def self.bind_header(header_klass, args={})
196
- Deprecation.deprecated(self, __method__, 'bind', klass_method: true)
197
- op = args.delete(:op) || :or
198
- if @known_headers[header_klass].nil? || @known_headers[header_klass].op != op
199
- bindings = Bindings.new(op)
200
- @known_headers[header_klass] = bindings
201
- else
202
- bindings = @known_headers[header_klass]
203
- end
204
- args.each do |key, value|
205
- bindings << if key == :procs
206
- ProcBinding.new(value)
207
- else
208
- Binding.new(key, value)
209
- end
210
- end
211
- end
212
-
213
- # Bind a upper header to current one.
162
+ # @example Basic examples
214
163
  # # Bind Header2 to Header1 when field1 from Header1 has a value of 42
215
164
  # Header1.bind Header2, field1: 42
216
165
  # # Bind Header3 to Header1 when field1 from Header1 has a value of 43
217
166
  # # and field2 has value 43 or 44
218
167
  # Header1.bind Header3, field1: 43, field2: 43
219
168
  # Header1.bind Header3, field1: 43, field2: 44
169
+ # @example Defining a binding on a field using a lambda.
220
170
  # # Bind Header4 to Header1 when field1 from Header1 has a value
221
171
  # # greater or equal to 44. When adding a Header2 to a Header1
222
172
  # # with Packet#add, force value to 44.
223
173
  # Header1.bind Header4, field1: ->(v) { v.nil? ? 44 : v >= 44 }
174
+ # @example Defining a binding using procs key
224
175
  # # Bind Header5 to Header1 when field1 from Header1 has a value of 41
225
176
  # # and first two bytes of header1's body are null.
226
177
  # # When adding a Header2 to a Header1 with Packet#add, force value to 44.
227
178
  # Header1.bind Header5, procs: [->(hdr) { hdr.field1 = 41 }
228
179
  # ->(hdr) { hdr.field1 == 41 && hdr.body[0..1] == "\x00\x00" }]
229
- # @param [Class] header_klass header class to bind to current class
230
- # @param [Hash] args current class fields and their value when +header_klass+
231
- # is embedded in current class.
232
- #
233
- # Given value may be a lambda, whose alone argument is the value extracted
234
- # from header field (or +nil+ when lambda is used to set field while adding
235
- # a header).
236
- #
237
- # Special key +procs+ may be used to set 2 lambdas, the former to set
238
- # fields, the latter to check bindings. This may be used when multiple and
239
- # non-trivial checks should be made.
240
- # @return [void]
241
180
  # @since 2.7.0
242
181
  def self.bind(header_klass, args={})
243
182
  if @known_headers[header_klass].nil?
244
- bindings = Bindings.new(:newstyle)
183
+ bindings = Bindings.new
245
184
  @known_headers[header_klass] = bindings
246
185
  else
247
186
  bindings = @known_headers[header_klass]
@@ -260,7 +199,14 @@ module PacketGen
260
199
  # @return [String]
261
200
  # @since 2.0.0
262
201
  def self.protocol_name
263
- new.protocol_name
202
+ return @protocol_name if defined? @protocol_name
203
+
204
+ classname = to_s
205
+ @protocol_name = if classname.start_with?('PacketGen::Header')
206
+ classname.sub(/.*Header::/, '')
207
+ else
208
+ classname.sub(/.*::/, '')
209
+ end
264
210
  end
265
211
 
266
212
  # Helper method to calculate length of +hdr+ and set its +length+ field.
@@ -272,7 +218,7 @@ module PacketGen
272
218
  length = if header_in_size
273
219
  hdr.sz
274
220
  else
275
- hdr.body.sz
221
+ hdr[:body].sz
276
222
  end
277
223
  hdr.length = length
278
224
  end
@@ -293,14 +239,7 @@ module PacketGen
293
239
  # Return header protocol name
294
240
  # @return [String]
295
241
  def protocol_name
296
- return @protocol_name if @protocol_name
297
-
298
- classname = self.class.to_s
299
- @protocol_name = if classname.start_with?('PacketGen::Header')
300
- classname.sub(/.*Header::/, '')
301
- else
302
- classname.sub(/.*::/, '')
303
- end
242
+ self.class.protocol_name
304
243
  end
305
244
 
306
245
  # return header method name
@@ -308,7 +247,7 @@ module PacketGen
308
247
  # @since 2.0.0
309
248
  # @since 2.8.6 permit multiple nesting levels
310
249
  def method_name
311
- return @method_name if @method_name
250
+ return @method_name if defined? @method_name
312
251
 
313
252
  @method_name = protocol_name.downcase.gsub(/::/, '_')
314
253
  end
@@ -340,29 +279,30 @@ module PacketGen
340
279
  def added_to_packet(packet) end
341
280
 
342
281
  # @api private
343
- # Get +header+ id in packet headers array
282
+ # Get +header+ id in {Packet#headers} array
344
283
  # @param [Header] header
345
284
  # @return [Integer]
346
- # @raise FormatError +header+ not in a packet
285
+ # @raise [FormatError] +header+ not in a packet
347
286
  def header_id(header)
348
287
  raise FormatError, "header of type #{header.class} not in a packet" if packet.nil?
288
+
349
289
  id = packet.headers.index(header)
350
- if id.nil?
351
- raise FormatError, "header of type #{header.class} not in packet #{packet}"
352
- end
290
+ raise FormatError, "header of type #{header.class} not in packet #{packet}" if id.nil?
291
+
353
292
  id
354
293
  end
355
294
 
356
295
  # @api private
357
- # Get IP or IPv6 previous header from +header+
296
+ # Get {IP} or {IPv6} previous header from +header+
358
297
  # @param [Header] header
359
298
  # @return [Header]
360
- # @raise FormatError no IP or IPv6 header previous +header+ in packet
361
- # @raise FormatError +header+ not in a packet
299
+ # @raise [FormatError] no IP or IPv6 header previous +header+ in packet
300
+ # @raise [FormatError] +header+ not in a packet
362
301
  def ip_header(header)
363
302
  hid = header_id(header)
364
303
  iph = packet.headers[0...hid].reverse.find { |h| h.is_a?(IP) || h.is_a?(IPv6) }
365
304
  raise FormatError, 'no IP or IPv6 header in packet' if iph.nil?
305
+
366
306
  iph
367
307
  end
368
308
 
@@ -370,12 +310,13 @@ module PacketGen
370
310
  # Get link layer header from given header
371
311
  # @param [Header] header
372
312
  # @return [Header]
373
- # @raise FormatError no link layer header in packet
374
- # @raise FormatError +header+ not in a packet
313
+ # @raise [FormatError] no link layer header in packet
314
+ # @raise [FormatError] +header+ not in a packet
375
315
  def ll_header(header)
376
316
  hid = header_id(header)
377
317
  llh = packet.headers[0...hid].reverse.find { |h| h.is_a?(Eth) || h.is_a?(Dot11) }
378
318
  raise FormatError, 'no link layer header in packet' if llh.nil?
319
+
379
320
  llh
380
321
  end
381
322
  end