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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/packetgen/header/arp.rb +54 -125
- data/lib/packetgen/header/base.rb +175 -0
- data/lib/packetgen/header/dns/name.rb +110 -0
- data/lib/packetgen/header/dns/opt.rb +137 -0
- data/lib/packetgen/header/dns/option.rb +17 -0
- data/lib/packetgen/header/dns/qdsection.rb +39 -0
- data/lib/packetgen/header/dns/question.rb +129 -0
- data/lib/packetgen/header/dns/rr.rb +89 -0
- data/lib/packetgen/header/dns/rrsection.rb +72 -0
- data/lib/packetgen/header/dns.rb +276 -0
- data/lib/packetgen/header/esp.rb +38 -70
- data/lib/packetgen/header/eth.rb +35 -106
- data/lib/packetgen/header/icmp.rb +19 -70
- data/lib/packetgen/header/icmpv6.rb +3 -3
- data/lib/packetgen/header/ip.rb +54 -210
- data/lib/packetgen/header/ipv6.rb +73 -164
- data/lib/packetgen/header/tcp/option.rb +34 -50
- data/lib/packetgen/header/tcp/options.rb +19 -20
- data/lib/packetgen/header/tcp.rb +66 -129
- data/lib/packetgen/header/udp.rb +31 -88
- data/lib/packetgen/header.rb +5 -10
- data/lib/packetgen/inspect.rb +5 -4
- data/lib/packetgen/packet.rb +74 -57
- data/lib/packetgen/pcapng/block.rb +49 -7
- data/lib/packetgen/pcapng/epb.rb +36 -34
- data/lib/packetgen/pcapng/file.rb +24 -8
- data/lib/packetgen/pcapng/idb.rb +28 -33
- data/lib/packetgen/pcapng/shb.rb +35 -39
- data/lib/packetgen/pcapng/spb.rb +18 -27
- data/lib/packetgen/pcapng/unknown_block.rb +11 -21
- data/lib/packetgen/pcapng.rb +9 -7
- data/lib/packetgen/types/array.rb +56 -0
- data/lib/packetgen/types/fields.rb +325 -0
- data/lib/packetgen/types/int.rb +164 -0
- data/lib/packetgen/types/int_string.rb +69 -0
- data/lib/packetgen/types/string.rb +36 -0
- data/lib/packetgen/types/tlv.rb +41 -0
- data/lib/packetgen/types.rb +13 -0
- data/lib/packetgen/version.rb +1 -1
- data/lib/packetgen.rb +1 -1
- metadata +19 -6
- data/lib/packetgen/header/header_class_methods.rb +0 -106
- data/lib/packetgen/header/header_methods.rb +0 -73
- data/lib/packetgen/structfu.rb +0 -363
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f98c7d5b928554e3d6da92e42f96bf3ee0a397a8
|
4
|
+
data.tar.gz: 994ede3f4bc303f98df8bd29e6bcb0b34932bf75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
170
|
-
|
169
|
+
This is mainly for PcapNG (copied from [PacketFu](https://github.com/packetfu/packetfu),
|
170
|
+
but i am the original author).
|
data/lib/packetgen/header/arp.rb
CHANGED
@@ -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 <
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|