packetgen 2.8.7 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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