packetgen 1.2.0 → 1.3.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/packetgen/header/arp.rb +54 -125
  4. data/lib/packetgen/header/base.rb +175 -0
  5. data/lib/packetgen/header/dns/name.rb +110 -0
  6. data/lib/packetgen/header/dns/opt.rb +137 -0
  7. data/lib/packetgen/header/dns/option.rb +17 -0
  8. data/lib/packetgen/header/dns/qdsection.rb +39 -0
  9. data/lib/packetgen/header/dns/question.rb +129 -0
  10. data/lib/packetgen/header/dns/rr.rb +89 -0
  11. data/lib/packetgen/header/dns/rrsection.rb +72 -0
  12. data/lib/packetgen/header/dns.rb +276 -0
  13. data/lib/packetgen/header/esp.rb +38 -70
  14. data/lib/packetgen/header/eth.rb +35 -106
  15. data/lib/packetgen/header/icmp.rb +19 -70
  16. data/lib/packetgen/header/icmpv6.rb +3 -3
  17. data/lib/packetgen/header/ip.rb +54 -210
  18. data/lib/packetgen/header/ipv6.rb +73 -164
  19. data/lib/packetgen/header/tcp/option.rb +34 -50
  20. data/lib/packetgen/header/tcp/options.rb +19 -20
  21. data/lib/packetgen/header/tcp.rb +66 -129
  22. data/lib/packetgen/header/udp.rb +31 -88
  23. data/lib/packetgen/header.rb +5 -10
  24. data/lib/packetgen/inspect.rb +5 -4
  25. data/lib/packetgen/packet.rb +74 -57
  26. data/lib/packetgen/pcapng/block.rb +49 -7
  27. data/lib/packetgen/pcapng/epb.rb +36 -34
  28. data/lib/packetgen/pcapng/file.rb +24 -8
  29. data/lib/packetgen/pcapng/idb.rb +28 -33
  30. data/lib/packetgen/pcapng/shb.rb +35 -39
  31. data/lib/packetgen/pcapng/spb.rb +18 -27
  32. data/lib/packetgen/pcapng/unknown_block.rb +11 -21
  33. data/lib/packetgen/pcapng.rb +9 -7
  34. data/lib/packetgen/types/array.rb +56 -0
  35. data/lib/packetgen/types/fields.rb +325 -0
  36. data/lib/packetgen/types/int.rb +164 -0
  37. data/lib/packetgen/types/int_string.rb +69 -0
  38. data/lib/packetgen/types/string.rb +36 -0
  39. data/lib/packetgen/types/tlv.rb +41 -0
  40. data/lib/packetgen/types.rb +13 -0
  41. data/lib/packetgen/version.rb +1 -1
  42. data/lib/packetgen.rb +1 -1
  43. metadata +19 -6
  44. data/lib/packetgen/header/header_class_methods.rb +0 -106
  45. data/lib/packetgen/header/header_methods.rb +0 -73
  46. data/lib/packetgen/structfu.rb +0 -363
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dfd9d08f263a51dd186442e4b8f8395be3a964a2
4
- data.tar.gz: f68b293509bf734b7aa1760ba976b437ce3fba4c
3
+ metadata.gz: f98c7d5b928554e3d6da92e42f96bf3ee0a397a8
4
+ data.tar.gz: 994ede3f4bc303f98df8bd29e6bcb0b34932bf75
5
5
  SHA512:
6
- metadata.gz: 024c502d411c3ae81f7272bb5476964421738e3357d6a5e8b6308600408a499805f0015497d31ca792278857dc23609f2352c26a23011ef17c6edc40fe44e726
7
- data.tar.gz: 968a82ca1231067f5bc68fefae05c80842ff4b058fb17ff9c269320662e7eb6acb5db4c54435be479294857cadc41fee0d7fcb7d795437b982a30ae2fba17bed
6
+ metadata.gz: d3a0d0198fda11d157d42ca626b6e59d0af792748b194d60dff4d0bd6a928e6b664eeb4d95d5ad70c94e3f38e690e8b616377eb95fffd9fe338158766235148c
7
+ data.tar.gz: '09ba37f246d17b612f0ae247dab1408a799a9782d652e29ac3e798d8b46543225b506c983546b2e5acc7effdc52aca65f17f1fec1e3d32434f68edd535439b18'
data/README.md CHANGED
@@ -166,5 +166,5 @@ Copyright © 2016 Sylvain Daubert
166
166
  ### Other sources
167
167
  All original code maintains its copyright from its original authors and licensing.
168
168
 
169
- This is mainly for StrucFu (copied from [PacketFu](https://github.com/packetfu/packetfu))
170
- and PcapNG module (also copied from PacketFu, but I am the author).
169
+ This is mainly for PcapNG (copied from [PacketFu](https://github.com/packetfu/packetfu),
170
+ but i am the original author).
@@ -7,9 +7,9 @@ module PacketGen
7
7
  module Header
8
8
 
9
9
  # An ARP header consists of:
10
- # * a hardware type ({#hrd} or {#htype}) field ({Int16}),
10
+ # * a hardware type ({#hrd} or {#htype}) field ({Types::Int16}),
11
11
  # * a protocol type ({#pro} or {#ptype}) field (+Int16+),
12
- # * a hardware address length ({#hln} or {#hlen}) field ({Int8}),
12
+ # * a hardware address length ({#hln} or {#hlen}) field ({Types::Int8}),
13
13
  # * a protocol address length ({#pln} or {#plen}) field (+Int8+),
14
14
  # * a {#opcode} (or {#op}) field (+Int16+),
15
15
  # * a source hardware address ({#sha} or {#src_mac}) field ({Eth::MacAddr}),
@@ -27,11 +27,47 @@ module PacketGen
27
27
  # pkt.arp # => PacketGen::Header::ARP
28
28
  #
29
29
  # @author Sylvain Daubert
30
- class ARP < Struct.new(:hrd, :pro, :hln, :pln, :op,
31
- :sha, :spa, :tha, :tpa, :body)
32
- include StructFu
33
- include HeaderMethods
34
- extend HeaderClassMethods
30
+ class ARP < Base
31
+
32
+ # @!attribute hrd
33
+ # 16-bit hardware protocol type
34
+ # # @return [Integer]
35
+ define_field :hrd, Types::Int16, default: 1
36
+ # @!attribute pro
37
+ # 16-bit internet protocol type
38
+ # # @return [Integer]
39
+ define_field :pro, Types::Int16, default: 0x800
40
+ # @!attribute hln
41
+ # 8-bit hardware address length
42
+ # # @return [Integer]
43
+ define_field :hln, Types::Int8, default: 6
44
+ # @!attribute pln
45
+ # 8-bit internet address length
46
+ # # @return [Integer]
47
+ define_field :pln, Types::Int8, default: 4
48
+ # @!attribute op
49
+ # 16-bit operation code
50
+ # # @return [Integer]
51
+ define_field :op, Types::Int16, default: 1
52
+ # @!attribute sha
53
+ # source hardware address
54
+ # @return [Eth::MacAddr]
55
+ define_field :sha, Eth::MacAddr
56
+ # @!attribute spa
57
+ # source protocol address
58
+ # @return [IP::Addr]
59
+ define_field :spa, IP::Addr
60
+ # @!attribute tha
61
+ # target hardware address
62
+ # @return [Eth::MacAddr]
63
+ define_field :tha, Eth::MacAddr
64
+ # @!attribute tpa
65
+ # target protocol address
66
+ # @return [IP::Addr]
67
+ define_field :tpa, IP::Addr
68
+ # @!attribute body
69
+ # @return [Types::String,Header::Base]
70
+ define_field :body, Types::String
35
71
 
36
72
  # @param [Hash] options
37
73
  # @option options [Integer] :hrd network protocol type (default: 1)
@@ -44,143 +80,36 @@ module PacketGen
44
80
  # @option options [String] :spa sender internet address
45
81
  # @option options [String] :tha target hardware address
46
82
  # @option options [String] :tpa targetr internet address
47
- def initialize(options={})
48
- super Int16.new(options[:hrd] || options[:htype] || 1),
49
- Int16.new(options[:pro] || options[:ptype] || 0x800),
50
- Int8.new(options[:hln] || options[:hlen] || 6),
51
- Int8.new(options[:pln] || options[:plen] || 4),
52
- Int16.new(options[:op] || options[:opcode] || 1),
53
- Eth::MacAddr.new.from_human(options[:sha] || options[:src_mac]),
54
- IP::Addr.new.from_human(options[:spa] || options[:src_ip]),
55
- Eth::MacAddr.new.from_human(options[:tha] || options[:dst_mac]),
56
- IP::Addr.new.from_human(options[:tpa] || options[:dst_ip]),
57
- StructFu::String.new.read(options[:body])
83
+ def initialize(options={})
84
+ options[:hrd] ||= options[:htype]
85
+ options[:pro] ||= options[:ptype]
86
+ options[:hln] ||= options[:hlen]
87
+ options[:pln] ||= options[:plen]
88
+ options[:op] ||= options[:opcode]
89
+ options[:sha] ||= options[:src_mac]
90
+ options[:spa] ||= options[:src_ip]
91
+ options[:tha] ||= options[:dst_mac]
92
+ options[:tpa] ||= options[:dst_ip]
93
+ super
58
94
  end
59
95
 
60
- # Read a ARP header from a string
61
- # @param [String] str binary string
62
- # @return [self]
63
- def read(str)
64
- force_binary str
65
- raise ParseError, 'string too short for ARP' if str.size < self.sz
66
- self[:hrd].read str[0, 2]
67
- self[:pro].read str[2, 2]
68
- self[:hln].read str[4, 1]
69
- self[:pln].read str[5, 1]
70
- self[:op].read str[6, 2]
71
- self[:sha].read str[8, 6]
72
- self[:spa].read str[14, 4]
73
- self[:tha].read str[18, 6]
74
- self[:tpa].read str[24, 4]
75
- self[:body].read str[28..-1]
76
- end
77
-
78
- # @!attribute [rw] hrd
79
- # @return [Integer]
80
- def hrd
81
- self[:hrd].to_i
82
- end
83
96
  alias :htype :hrd
84
-
85
- def hrd=(i)
86
- self[:hrd].read i
87
- end
88
97
  alias :htype= :hrd=
89
-
90
- # @!attribute [rw] pro
91
- # @return [Integer]
92
- def pro
93
- self[:pro].to_i
94
- end
95
98
  alias :ptype :pro
96
-
97
- def pro=(i)
98
- self[:pro].read i
99
- end
100
99
  alias :ptype= :pro=
101
-
102
- # @!attribute [rw] hln
103
- # @return [Integer]
104
- def hln
105
- self[:hln].to_i
106
- end
107
100
  alias :hlen :hln
108
-
109
- def hln=(i)
110
- self[:hln].read i
111
- end
112
101
  alias :hlen= :hln=
113
-
114
- # @!attribute [rw] pln
115
- # @return [Integer]
116
- def pln
117
- self[:pln].to_i
118
- end
119
102
  alias :plen :pln
120
-
121
- def pln=(i)
122
- self[:pln].read i
123
- end
124
103
  alias :plen= :pln=
125
-
126
- # @!attribute [rw] op
127
- # @return [Integer]
128
- def op
129
- self[:op].to_i
130
- end
131
104
  alias :opcode :op
132
-
133
- def op=(i)
134
- self[:op].read i
135
- end
136
105
  alias :opcode= :op=
137
-
138
- # @!attribute [rw] sha
139
- # @return [String]
140
- def sha
141
- self[:sha].to_human
142
- end
143
106
  alias :src_mac :sha
144
-
145
- def sha=(addr)
146
- self[:sha].from_human addr
147
- end
148
107
  alias :src_mac= :sha=
149
-
150
- # @!attribute [rw] spa
151
- # @return [String]
152
- def spa
153
- self[:spa].to_human
154
- end
155
108
  alias :src_ip :spa
156
-
157
- def spa=(addr)
158
- self[:spa].from_human addr
159
- end
160
109
  alias :src_ip= :spa=
161
-
162
- # @!attribute [rw] tha
163
- # @return [String]
164
- def tha
165
- self[:tha].to_human
166
- end
167
110
  alias :dst_mac :tha
168
-
169
- def tha=(addr)
170
- self[:tha].from_human addr
171
- end
172
111
  alias :dst_mac= :tha=
173
-
174
- # @!attribute [rw] tpa
175
- # @return [String]
176
- def tpa
177
- self[:tpa].to_human
178
- end
179
112
  alias :dst_ip :tpa
180
-
181
- def tpa=(addr)
182
- self[:tpa].from_human addr
183
- end
184
113
  alias :dst_ip= :tpa=
185
114
  end
186
115
 
@@ -0,0 +1,175 @@
1
+ # This file is part of PacketGen
2
+ # See https://github.com/sdaubert/packetgen for more informations
3
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ module PacketGen
7
+ module Header
8
+
9
+ # @abstract
10
+ # Base class for all header types
11
+ # @author Sylvain Daubert
12
+ class Base < Types::Fields
13
+
14
+ # @api private
15
+ # Simple class to handle a header association
16
+ class Binding < Struct.new(:key, :value)
17
+ # Check +fields+ responds to binding
18
+ # @param [Types::Fields] fields
19
+ # @return [Boolean]
20
+ def check?(fields)
21
+ case self[:value]
22
+ when Proc
23
+ self[:value].call fields.send(self[:key])
24
+ else
25
+ fields.send(self[:key]) == self[:value]
26
+ end
27
+ end
28
+
29
+ # Set +fields+ field to binding value
30
+ # @param [Types::Fields] fields
31
+ # @return [void]
32
+ def set(fields)
33
+ case self[:value]
34
+ when Proc
35
+ fields.send "#{self[:key]}=", self[:value].call(nil)
36
+ else
37
+ fields.send "#{self[:key]}=", self[:value]
38
+ end
39
+ end
40
+ end
41
+
42
+ # @api private
43
+ # Class to handle header associations
44
+ class Bindings
45
+ include Enumerable
46
+
47
+ # op type
48
+ # @return [:or,:and]
49
+ attr_accessor :op
50
+ # @return [Array<Binding>]
51
+ attr_accessor :bindings
52
+
53
+ # @param [:or, :and] op
54
+ def initialize(op)
55
+ @op = op
56
+ @bindings = []
57
+ end
58
+
59
+ # @param [Object] arg
60
+ # @return [Bindings] self
61
+ def <<(arg)
62
+ @bindings << arg
63
+ end
64
+
65
+ # each iterator
66
+ # @return [void]
67
+ def each
68
+ @bindings.each { |b| yield b }
69
+ end
70
+
71
+ # @return [Boolean]
72
+ def empty?
73
+ @bindings.empty?
74
+ end
75
+
76
+ # @return [Hash]
77
+ def to_h
78
+ hsh = {}
79
+ each { |b| hsh[b.key] = b.value }
80
+ hsh
81
+ end
82
+
83
+ # Check +fields+ responds to set of bindings
84
+ # @param [Types::Fields] fields
85
+ # @return [Boolean]
86
+ def check?(fields)
87
+ case @op
88
+ when :or
89
+ @bindings.any? { |binding| binding.check?(fields) }
90
+ when :and
91
+ @bindings.all? { |binding| binding.check?(fields) }
92
+ end
93
+ end
94
+
95
+ # Set +fields+ to bindings value
96
+ # @param [Types::Fields] fields
97
+ # @return [void]
98
+ def set(fields)
99
+ @bindings.each { |b| b.set fields }
100
+ end
101
+ end
102
+
103
+ # @api private
104
+ # Reference on packet which owns this header
105
+ attr_accessor :packet
106
+
107
+ # On inheritage, create +@known_headers+ class variable
108
+ # @param [Class] klass
109
+ # @return [void]
110
+ def self.inherited(klass)
111
+ super
112
+ klass.class_eval { @known_headers = {} }
113
+ end
114
+
115
+ # Bind a upper header to current class
116
+ # Header1.bind_header Header2, field1: 43
117
+ # Header1.bind_header Header2, field1: 43, field2: 43
118
+ # Header1.bind_header Header2, op: :and, field1: 43, field2: 43
119
+ # Header1.bind_header Header2, field1: ->(v) { v.nil? ? 128 : v > 127 }
120
+ # @param [Class] header_klass header class to bind to current class
121
+ # @param [Hash] args current class fields and their value when +header_klass+
122
+ # is embedded in current class. Given value may be a lambda, whose alone argument
123
+ # is the value extracted from header field (or +nil+ when lambda is used to set
124
+ # field while adding a header).
125
+ #
126
+ # If multiple fields are given, a special key +:op+ may be given to set parse
127
+ # operation on this binding. By default, +:op+ is +:or+ (at least one binding
128
+ # must match to parse it). It also may be set to +:and+ (all bindings must match
129
+ # to parse it).
130
+ # @return [void]
131
+ def self.bind_header(header_klass, args={})
132
+ op = args.delete(:op) || :or
133
+ bindings = Bindings.new(op)
134
+ @known_headers[header_klass] = bindings
135
+ args.each do |key, value|
136
+ bindings << Binding.new(key, value)
137
+ end
138
+ end
139
+
140
+ # @api private
141
+ # Get knwon headers
142
+ # @return [Hash] keys: header classes, values: hashes
143
+ def self.known_headers
144
+ @known_headers
145
+ end
146
+
147
+ # @api private
148
+ # Get +header+ id in packet headers array
149
+ # @param [Header] header
150
+ # @return [Integer]
151
+ # @raise FormatError +header+ not in a packet
152
+ def header_id(header)
153
+ raise FormatError, "header of type #{header.class} not in a packet" if packet.nil?
154
+ id = packet.headers.index(header)
155
+ if id.nil?
156
+ raise FormatError, "header of type #{header.class} not in packet #{packet}"
157
+ end
158
+ id
159
+ end
160
+
161
+ # @api private
162
+ # Get IP or IPv6 previous header from +header+
163
+ # @param [Header] header
164
+ # @return [Header]
165
+ # @raise FormatError no IP or IPv6 header previous +header+ in packet
166
+ # @raise FormatError +header+ not in a packet
167
+ def ip_header(header)
168
+ hid = header_id(header)
169
+ iph = packet.headers[0...hid].reverse.find { |h| h.is_a? IP or h.is_a? IPv6 }
170
+ raise FormatError, 'no IP or IPv6 header in packet' if iph.nil?
171
+ iph
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,110 @@
1
+ module PacketGen
2
+ module Header
3
+ class DNS
4
+
5
+ # DNS Name, defined as a suite of labels. A label is of type {Types::IntString}.
6
+ # @author Sylvain Daubert
7
+ class Name < Types::Array
8
+
9
+ # Mask to decode a pointer on another label
10
+ POINTER_MASK = 0xc000
11
+
12
+ # @return [DNS]
13
+ attr_accessor :dns
14
+
15
+ def initialize
16
+ super
17
+ @pointer = nil
18
+ @pointer_name = nil
19
+ end
20
+
21
+ # @!method push(label)
22
+ # @param [Types::IntString] label
23
+ # @return [Name] self
24
+ # @!method <<(label)
25
+ # @param [Types::IntString] label
26
+ # @return [Name] self
27
+
28
+ # Read a set of labels form a dotted string
29
+ # @param [String] str
30
+ # @return [Name] self
31
+ def from_human(str)
32
+ clear
33
+ return self if str.nil?
34
+
35
+ str.split('.').each do |label|
36
+ self << Types::IntString.new(label)
37
+ end
38
+ self << Types::IntString.new('')
39
+ end
40
+
41
+ # Read a sequence of label from a string
42
+ # @param [String] str binary string
43
+ # @return [Name] self
44
+ def read(str)
45
+ @pointer = nil
46
+ @pointer_name = nil
47
+ clear
48
+ return self if str.nil?
49
+
50
+ force_binary str
51
+ start = 0
52
+ while true
53
+ index = str[start, 2].unpack('n').first
54
+ if pointer? index
55
+ # Pointer on another label
56
+ @pointer = str[start, 2]
57
+ break
58
+ else
59
+ label = Types::IntString.new
60
+ label.read(str[start..-1])
61
+ start += label.sz
62
+ self << label
63
+ break if label.length == 0 or str[start..-1].length == 0
64
+ end
65
+ end
66
+ self
67
+ end
68
+
69
+ # Get options binary string
70
+ # @return [String]
71
+ def to_s
72
+ super << @pointer.to_s
73
+ end
74
+
75
+ # Get a human readable string
76
+ # @return [String]
77
+ def to_human
78
+ ary = map(&:string)
79
+ np = name_from_pointer
80
+ ary << np if np
81
+ str = ary.join('.')
82
+ str.empty? ? '.' : str
83
+ end
84
+
85
+ private
86
+
87
+ def pointer?(index)
88
+ return false if index.nil?
89
+ index & POINTER_MASK == POINTER_MASK
90
+ end
91
+
92
+ def name_from_pointer
93
+ return nil unless @pointer
94
+ return @pointer_name if @pointer_name
95
+
96
+ index = @pointer.unpack('n').first
97
+ mask = ~POINTER_MASK & 0xffff
98
+ ptr = index & mask
99
+ name = Name.new
100
+ name.dns = @dns
101
+ @pointer_name = name.read(self.dns.to_s[ptr..-1]).to_human
102
+ end
103
+
104
+ def record_from_hash(hsh)
105
+ raise NotImplementedError, "not supported by #{self.class}"
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,137 @@
1
+ require_relative 'option'
2
+
3
+ module PacketGen
4
+ module Header
5
+ class DNS
6
+
7
+ # OPT pseudo-RR. Used by Extended DNS (EDNS(0), cf. RFC 6891).
8
+ #
9
+ # a OPT record may contain zero or more {Option options} in its {#rdata}.
10
+ # @author Sylvain Daubert
11
+ class OPT < RR
12
+ # @return [Array<Option>]
13
+ attr_reader :options
14
+
15
+ # @param [DNS] dns
16
+ # @param [Hash] options
17
+ # @option options [String] :name domain as a dotted string. Default to +"."+
18
+ # @option options [Integer,String] :type see {TYPES}. Default to +'OPT'+
19
+ # @option options [Integer] :udp_size UDP maximum size. Also +:rrclass+.
20
+ # Default to 512.
21
+ # @option options [Integer] :ext_rcode
22
+ # @option options [Integer] :version
23
+ # @option options [Boolean] :do DO bit
24
+ # @option options [Integer] :ttl set +ext_rcode+, +version+, +do+ and
25
+ # +z+ at once
26
+ # @option options [Integer] :rdlength if not provided, automatically set
27
+ # from +:rdata+ length
28
+ # @option options [String] :rdata
29
+ def initialize(dns, options={})
30
+ opts = { name: '.', rrclass: 512, type: 41 }.merge!(options)
31
+ super dns, opts
32
+ @options = []
33
+
34
+ self.udp_size = options[:udp_size] if options[:udp_size]
35
+ self.ext_rcode = options[:ext_rcode] if options[:ext_rcode]
36
+ self.version = options[:version] if options[:version]
37
+ self.do = options[:do] unless options[:do].nil?
38
+ end
39
+
40
+ # @overload ext_rcode=(v)
41
+ # Setter for upper 8 bits of extended 12-bit RCODE
42
+ # @param [Integer] v
43
+ # @return [Integer]
44
+ # @overload ext_rcode
45
+ # Getter for upper 8 bits of extended 12-bit RCODE
46
+ # @return [Integer]
47
+ # @return [Integer]
48
+ def ext_rcode=(v=nil)
49
+ if v
50
+ self[:ttl].value = self[:ttl].to_i & (0xffffffff & ~(0xff << 24))
51
+ self[:ttl].value |= (v & 0xff) << 24
52
+ end
53
+ (self[:ttl].to_i >> 24) & 0xff
54
+ end
55
+ alias ext_rcode ext_rcode=
56
+
57
+ # @overload version=(v)
58
+ # Setter EDNS version
59
+ # @param [Integer] v
60
+ # @return [Integer]
61
+ # @overload version
62
+ # Getter for EDNS version
63
+ # @return [Integer]
64
+ # @return [Integer]
65
+ def version=(v=nil)
66
+ if v
67
+ self[:ttl].value = self[:ttl].to_i & (0xffffffff & ~(0xff << 16))
68
+ self[:ttl].value |= (v & 0xff) << 16
69
+ end
70
+ (self[:ttl].to_i >> 16) & 0xff
71
+ end
72
+ alias version version=
73
+
74
+ # @overload do=(v)
75
+ # Setter EDNS do
76
+ # @param [Boolean] v
77
+ # @return [Boolean]
78
+ # @overload do?
79
+ # Getter for EDNS do
80
+ # @return [Boolean]
81
+ # @return [Boolean]
82
+ def do=(v=nil)
83
+ b = v ? 1 : 0
84
+ unless v.nil?
85
+ self[:ttl].value = self[:ttl].to_i & (0xffffffff & ~(1 << 15))
86
+ self[:ttl].value |= (b & 1) << 15
87
+ end
88
+ ((self[:ttl].to_i >> 15) & 1) == 1 ? true : false
89
+ end
90
+ alias :do? :do=
91
+
92
+ # @overload z=(v)
93
+ # @param [Integer] v
94
+ # @return [Integer]
95
+ # @overload z
96
+ # @return [Integer]
97
+ # @return [Integer]
98
+ def z=(v=nil)
99
+ if v
100
+ self[:ttl].value = self[:ttl].to_i & (0xffffffff & ~0x7fff)
101
+ self[:ttl].value |= v & 0x7fff
102
+ end
103
+ self[:ttl].to_i & 0x7fff
104
+ end
105
+ alias z z=
106
+
107
+ # @!attribute udp_size
108
+ # @return [Integer] UDP payload size
109
+ alias udp_size rrclass
110
+ alias udp_size= rrclass=
111
+
112
+ # @return [String]
113
+ def human_flags
114
+ do? ? 'do' : 'none'
115
+ end
116
+
117
+ # @return [String]
118
+ def human_options
119
+ str = @options.map(&:to_human).join(';')
120
+ str.empty? ? 'none' : str
121
+ end
122
+
123
+ # @return [String]
124
+ def to_human
125
+ "#{name} #{human_type} UDPsize:#{udp_size} " \
126
+ "extRCODE:#{ext_rcode} EDNSversion:#{version} flags:#{human_flags} " \
127
+ "options:#{human_options}"
128
+ end
129
+
130
+ # @return [String]
131
+ def to_s
132
+ super + @options.map(&:to_s).join
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,17 @@
1
+ module PacketGen
2
+ module Header
3
+ class DNS
4
+
5
+ # DNS option
6
+ # @author Sylvain Daubert
7
+ class Option < Types::TLV
8
+
9
+ # Force {#type} and {#length} fields to be {Types::Int16}
10
+ # @see TLV#initialize
11
+ def initialize(options={})
12
+ super options.merge!(t: Types::Int16, l: Types::Int16)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end