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