packetgen 3.2.0 → 3.2.2
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 +1 -1
- data/bin/pgconsole +3 -3
- data/lib/packetgen/header/arp.rb +24 -13
- data/lib/packetgen/header/asn1_base.rb +2 -2
- data/lib/packetgen/header/base.rb +1 -1
- data/lib/packetgen/header/dhcpv6/duid.rb +6 -0
- data/lib/packetgen/header/dhcpv6/option.rb +11 -13
- data/lib/packetgen/header/dns/opt.rb +2 -2
- data/lib/packetgen/header/dns/rr.rb +61 -28
- data/lib/packetgen/header/dns.rb +13 -6
- data/lib/packetgen/header/dot11/management.rb +2 -5
- data/lib/packetgen/header/dot11.rb +1 -1
- data/lib/packetgen/header/eap.rb +1 -1
- data/lib/packetgen/header/eth.rb +1 -1
- data/lib/packetgen/header/http/headers.rb +16 -1
- data/lib/packetgen/header/http/response.rb +43 -23
- data/lib/packetgen/header/igmp.rb +1 -1
- data/lib/packetgen/header/ip/option.rb +36 -10
- data/lib/packetgen/header/ipv6/addr.rb +3 -0
- data/lib/packetgen/header/mdns.rb +19 -25
- data/lib/packetgen/header/mld.rb +1 -1
- data/lib/packetgen/header/ospfv2/lsa_header.rb +2 -4
- data/lib/packetgen/header/ospfv2.rb +1 -1
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +14 -5
- data/lib/packetgen/header/ospfv3/lsa.rb +1 -1
- data/lib/packetgen/header/ospfv3/lsa_header.rb +2 -4
- data/lib/packetgen/header/ospfv3.rb +1 -1
- data/lib/packetgen/header/snmp.rb +39 -16
- data/lib/packetgen/header/tcp/option.rb +1 -1
- data/lib/packetgen/header/tcp.rb +12 -5
- data/lib/packetgen/header/tftp.rb +15 -9
- data/lib/packetgen/inspect.rb +15 -9
- data/lib/packetgen/packet.rb +48 -2
- data/lib/packetgen/pcapng/file.rb +13 -13
- data/lib/packetgen/pcapng.rb +1 -0
- data/lib/packetgen/pcaprub_wrapper.rb +0 -4
- data/lib/packetgen/types/abstract_tlv.rb +1 -1
- data/lib/packetgen/types/array.rb +35 -13
- data/lib/packetgen/types/fields.rb +19 -19
- data/lib/packetgen/types/int.rb +7 -0
- data/lib/packetgen/types/oui.rb +1 -1
- data/lib/packetgen/types/tlv.rb +17 -9
- data/lib/packetgen/unknown_packet.rb +3 -2
- data/lib/packetgen/utils.rb +67 -24
- data/lib/packetgen/version.rb +1 -1
- data/lib/packetgen.rb +3 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad942df146df9daf8c38e049fc112b13c93fd38a45362e8dd2a43c6e8382b224
|
4
|
+
data.tar.gz: 77b48a6af0170a912e91b888456c31881bfe1fd30a693796c849a946b5e27bac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98f7f9d7dd652741cdce08cbe081310c4f4ca6745702efc5755806614f30c7930498610f9925a6d7abeef1b8b64abfa2857c77bcc638872f31577fe587ad1e63
|
7
|
+
data.tar.gz: cc4e18519b09f7eaa753f9f2e4a500c5b3d0de2aed5bbd275b636d5c21ec763dca2a34da27a16336d65e2ec86d827812c0f546c5e67dfd9b500d683f8baac7ac
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
|
2
2
|
[](https://badge.fury.io/rb/packetgen)
|
3
|
-
|
3
|
+
[](https://github.com/sdaubert/packetgen/actions?query=workflow%3Aci)
|
4
4
|
# PacketGen
|
5
5
|
|
6
6
|
PacketGen provides simple ways to generate, send and capture network packets.
|
data/bin/pgconsole
CHANGED
@@ -31,7 +31,7 @@ class PgConsole
|
|
31
31
|
define_method m, Utils.method(m).to_proc
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
34
|
+
def console_binding
|
35
35
|
binding
|
36
36
|
end
|
37
37
|
end
|
@@ -52,10 +52,10 @@ if use_pry
|
|
52
52
|
}
|
53
53
|
]
|
54
54
|
Pry.config.prompt_name = 'pg'
|
55
|
-
PgConsole.new.
|
55
|
+
PgConsole.new.console_binding.pry
|
56
56
|
else
|
57
57
|
IRB.setup nil
|
58
|
-
irb = IRB::Irb.new(IRB::WorkSpace.new(PgConsole.new.
|
58
|
+
irb = IRB::Irb.new(IRB::WorkSpace.new(PgConsole.new.console_binding))
|
59
59
|
IRB.conf[:MAIN_CONTEXT] = irb.context
|
60
60
|
irb.context.auto_indent_mode = true
|
61
61
|
irb.context.prompt_i = 'pg> '
|
data/lib/packetgen/header/arp.rb
CHANGED
@@ -81,15 +81,7 @@ module PacketGen
|
|
81
81
|
# @option options [String] :tha target hardware address
|
82
82
|
# @option options [String] :tpa targetr internet address
|
83
83
|
def initialize(options={})
|
84
|
-
options
|
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]
|
84
|
+
handle_options(options)
|
93
85
|
super
|
94
86
|
end
|
95
87
|
|
@@ -118,16 +110,35 @@ module PacketGen
|
|
118
110
|
case opcode.to_i
|
119
111
|
when 1
|
120
112
|
self.opcode = 2
|
121
|
-
|
122
|
-
self.sha, self.tha = self.tha, self.sha
|
113
|
+
invert_addresses
|
123
114
|
when 2
|
124
115
|
self.opcode = 1
|
125
|
-
|
126
|
-
self.sha = self.tha
|
116
|
+
invert_addresses
|
127
117
|
self[:tha].from_human('00:00:00:00:00:00')
|
128
118
|
end
|
129
119
|
self
|
130
120
|
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
125
|
+
def handle_options(options)
|
126
|
+
options[:hrd] ||= options[:htype]
|
127
|
+
options[:pro] ||= options[:ptype]
|
128
|
+
options[:hln] ||= options[:hlen]
|
129
|
+
options[:pln] ||= options[:plen]
|
130
|
+
options[:op] ||= options[:opcode]
|
131
|
+
options[:sha] ||= options[:src_mac]
|
132
|
+
options[:spa] ||= options[:src_ip]
|
133
|
+
options[:tha] ||= options[:dst_mac]
|
134
|
+
options[:tpa] ||= options[:dst_ip]
|
135
|
+
end
|
136
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
137
|
+
|
138
|
+
def invert_addresses
|
139
|
+
self.spa, self.tpa = self.tpa, self.spa
|
140
|
+
self.sha, self.tha = self.tha, self.sha
|
141
|
+
end
|
131
142
|
end
|
132
143
|
|
133
144
|
self.add_class ARP
|
@@ -19,7 +19,7 @@ module PacketGen
|
|
19
19
|
class ASN1Base < RASN1::Model
|
20
20
|
include Headerable
|
21
21
|
|
22
|
-
class <<self
|
22
|
+
class << self
|
23
23
|
# Define some methods from given ASN.1 fields to mimic {Base} attributes
|
24
24
|
# @param [Array<Symbol>] attributes
|
25
25
|
# @return [void]
|
@@ -27,7 +27,7 @@ module PacketGen
|
|
27
27
|
@attributes = attributes
|
28
28
|
attributes.each do |attr|
|
29
29
|
class_eval "def #{attr}; @elements[:#{attr}].value; end\n" \
|
30
|
-
|
30
|
+
"def #{attr}=(v); @elements[:#{attr}].value = v; end"
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -53,19 +53,17 @@ module PacketGen
|
|
53
53
|
# @param [Hash] options
|
54
54
|
# @return [Option]
|
55
55
|
def new(options={})
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
else
|
68
|
-
super
|
56
|
+
return super unless self == Option
|
57
|
+
|
58
|
+
case options[:type]
|
59
|
+
when Integer
|
60
|
+
klass = Option.subclasses[options[:type]]
|
61
|
+
klass&.new(options)
|
62
|
+
when String
|
63
|
+
if DHCPv6.const_defined?(options[:type])
|
64
|
+
klass = DHCPv6.const_get(options[:type])
|
65
|
+
options.delete :type
|
66
|
+
klass.new(options) if klass < Option
|
69
67
|
end
|
70
68
|
else
|
71
69
|
super
|
@@ -125,8 +125,8 @@ module PacketGen
|
|
125
125
|
# @return [String]
|
126
126
|
def to_human
|
127
127
|
"#{name} #{human_type} UDPsize:#{udp_size} " \
|
128
|
-
|
129
|
-
|
128
|
+
"extRCODE:#{ext_rcode} EDNSversion:#{version} flags:#{human_flags} " \
|
129
|
+
"options:#{options.empty? ? 'none' : options.to_human}"
|
130
130
|
end
|
131
131
|
end
|
132
132
|
end
|
@@ -50,48 +50,29 @@ module PacketGen
|
|
50
50
|
self[:rdata].read data
|
51
51
|
end
|
52
52
|
|
53
|
+
# rubocop:disable Metrics/AbcSize
|
54
|
+
|
53
55
|
# Get human readable rdata
|
54
56
|
# @return [String]
|
55
57
|
def human_rdata
|
56
|
-
str = self[:rdata].inspect
|
57
|
-
|
58
|
-
# Need to mask: mDNS uses leftmost bit as a flag (CACHE FLUSH)
|
59
|
-
if self.rrclass & 0x7fff == CLASSES['IN']
|
60
|
-
case type
|
61
|
-
when TYPES['A'], TYPES['AAAA']
|
62
|
-
str = IPAddr.new_ntoh(self[:rdata]).to_s
|
63
|
-
end
|
64
|
-
end
|
58
|
+
str = human_ip_rdata || self[:rdata].inspect
|
65
59
|
|
66
|
-
name = Name.new
|
67
|
-
name.dns = self[:name].dns
|
68
60
|
case type
|
69
61
|
when TYPES['NS'], TYPES['PTR'], TYPES['CNAME']
|
62
|
+
name = Name.new
|
63
|
+
name.dns = self[:name].dns
|
70
64
|
str = name.read(self[:rdata]).to_human
|
71
65
|
when TYPES['SOA']
|
72
|
-
|
73
|
-
rname = name.read(self[:rdata][mname.sz..-1])
|
74
|
-
serial = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz, 4])
|
75
|
-
refresh = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 4, 4])
|
76
|
-
retryi = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 8, 4])
|
77
|
-
expire = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 12, 4])
|
78
|
-
minimum = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 16, 4])
|
79
|
-
str = "#{mname.to_human} #{rname.to_human} #{serial.to_i} #{refresh.to_i} " \
|
80
|
-
"#{retryi.to_i} #{expire.to_i} #{minimum.to_i}"
|
66
|
+
str = human_soa_rdata
|
81
67
|
when TYPES['MX']
|
82
|
-
|
83
|
-
exchange = name.read(self[:rdata][2..-1]).to_human
|
84
|
-
str = '%u %s' % [pref.to_i, exchange]
|
68
|
+
str = human_mx_data
|
85
69
|
when TYPES['SRV']
|
86
|
-
|
87
|
-
weight = Types::Int16.new.read(self[:rdata][2, 2])
|
88
|
-
port = Types::Int16.new.read(self[:rdata][4, 2])
|
89
|
-
target = name.read(self[:rdata][6, self[:rdata].size]).to_human
|
90
|
-
str = "#{priority.to_i} #{weight.to_i} #{port.to_i} #{target}"
|
70
|
+
str = human_srv_data
|
91
71
|
end
|
92
72
|
|
93
73
|
str
|
94
74
|
end
|
75
|
+
# rubocop:enable Metrics/AbcSize
|
95
76
|
|
96
77
|
# Get human readable class
|
97
78
|
# @return [String]
|
@@ -109,6 +90,58 @@ module PacketGen
|
|
109
90
|
def to_human
|
110
91
|
"#{human_type} #{human_rrclass} #{name} TTL #{ttl} #{human_rdata}"
|
111
92
|
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def human_ip_rdata
|
97
|
+
# Need to mask: mDNS uses leftmost bit as a flag (CACHE FLUSH)
|
98
|
+
return unless self.rrclass & 0x7fff == CLASSES['IN']
|
99
|
+
|
100
|
+
case type
|
101
|
+
when TYPES['A'], TYPES['AAAA']
|
102
|
+
IPAddr.new_ntoh(self[:rdata]).to_s
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def human_mx_data
|
107
|
+
name = Name.new
|
108
|
+
name.dns = self[:name].dns
|
109
|
+
|
110
|
+
pref = Types::Int16.new.read(self[:rdata][0, 2])
|
111
|
+
exchange = name.read(self[:rdata][2..-1]).to_human
|
112
|
+
|
113
|
+
'%u %s' % [pref.to_i, exchange]
|
114
|
+
end
|
115
|
+
|
116
|
+
# rubocop:disable Metrics/AbcSize
|
117
|
+
def human_soa_rdata
|
118
|
+
name = Name.new
|
119
|
+
name.dns = self[:name].dns
|
120
|
+
mname = name.read(self[:rdata]).dup
|
121
|
+
rname = name.read(self[:rdata][mname.sz..-1])
|
122
|
+
|
123
|
+
serial = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz, 4])
|
124
|
+
refresh = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 4, 4])
|
125
|
+
retryi = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 8, 4])
|
126
|
+
expire = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 12, 4])
|
127
|
+
minimum = Types::Int32.new.read(self[:rdata][mname.sz + rname.sz + 16, 4])
|
128
|
+
|
129
|
+
"#{mname.to_human} #{rname.to_human} #{serial.to_i} #{refresh.to_i} " \
|
130
|
+
"#{retryi.to_i} #{expire.to_i} #{minimum.to_i}"
|
131
|
+
end
|
132
|
+
|
133
|
+
def human_srv_data
|
134
|
+
name = Name.new
|
135
|
+
name.dns = self[:name].dns
|
136
|
+
|
137
|
+
priority = Types::Int16.new.read(self[:rdata][0, 2])
|
138
|
+
weight = Types::Int16.new.read(self[:rdata][2, 2])
|
139
|
+
port = Types::Int16.new.read(self[:rdata][4, 2])
|
140
|
+
target = name.read(self[:rdata][6, self[:rdata].size]).to_human
|
141
|
+
|
142
|
+
"#{priority.to_i} #{weight.to_i} #{port.to_i} #{target}"
|
143
|
+
end
|
144
|
+
# rubocop:enable Metrics/AbcSize
|
112
145
|
end
|
113
146
|
end
|
114
147
|
end
|
data/lib/packetgen/header/dns.rb
CHANGED
@@ -241,18 +241,25 @@ module PacketGen
|
|
241
241
|
super do |attr|
|
242
242
|
next unless attr == :u16
|
243
243
|
|
244
|
-
|
245
|
-
|
246
|
-
str = Inspect.shift_level
|
247
|
-
str << Inspect::FMT_ATTR % ['Flags', 'flags', flags]
|
248
|
-
opcode = '%-16s (%u)' % [OPCODES.key(self.opcode), self.opcode]
|
244
|
+
str = inspect_flags
|
245
|
+
|
249
246
|
str << Inspect.shift_level
|
247
|
+
opcode = '%-16s (%u)' % [OPCODES.key(self.opcode), self.opcode]
|
250
248
|
str << Inspect::FMT_ATTR % ['Integer', 'opcode', opcode]
|
251
|
-
|
249
|
+
|
252
250
|
str << Inspect.shift_level
|
251
|
+
rcode = '%-16s (%u)' % [RCODES.key(self.rcode), self.rcode]
|
253
252
|
str << Inspect::FMT_ATTR % ['Integer', 'rcode', rcode]
|
254
253
|
end
|
255
254
|
end
|
255
|
+
|
256
|
+
private
|
257
|
+
|
258
|
+
def inspect_flags
|
259
|
+
flags = %i[qr aa tc rd ra].select! { |flag| send "#{flag}?" }.map(&:to_s).join(',')
|
260
|
+
str = Inspect.shift_level
|
261
|
+
str << Inspect::FMT_ATTR % ['Flags', 'flags', flags]
|
262
|
+
end
|
256
263
|
end
|
257
264
|
|
258
265
|
self.add_class DNS
|
@@ -53,12 +53,9 @@ module PacketGen
|
|
53
53
|
# @return [self]
|
54
54
|
# @since 2.1.3
|
55
55
|
def add_element(type:, value:)
|
56
|
-
|
57
|
-
self[:body].elements << { type: type, value: value }
|
58
|
-
else
|
59
|
-
raise FormatError, 'Before adding an Element, you have to add a Dot11::SubMngt subclass instance'
|
60
|
-
end
|
56
|
+
raise FormatError, 'Before adding an Element, you have to add a Dot11::SubMngt subclass instance' unless self[:body].is_a? SubMngt
|
61
57
|
|
58
|
+
self[:body].elements << { type: type, value: value }
|
62
59
|
self
|
63
60
|
end
|
64
61
|
|
@@ -355,7 +355,7 @@ module PacketGen
|
|
355
355
|
def added_to_packet(packet)
|
356
356
|
return if packet.respond_to? :dot11
|
357
357
|
|
358
|
-
packet.instance_eval("def dot11(arg=nil); header(#{self.class}, arg); end")
|
358
|
+
packet.instance_eval("def dot11(arg=nil); header(#{self.class}, arg); end") # def dot11(arg=nil); header(Dot11, arg); end
|
359
359
|
end
|
360
360
|
|
361
361
|
private
|
data/lib/packetgen/header/eap.rb
CHANGED
@@ -218,7 +218,7 @@ module PacketGen
|
|
218
218
|
def added_to_packet(packet)
|
219
219
|
return if packet.respond_to? :eap
|
220
220
|
|
221
|
-
packet.instance_eval("def eap(arg=nil); header(#{self.class}, arg); end")
|
221
|
+
packet.instance_eval("def eap(arg=nil); header(#{self.class}, arg); end") # def eap(arg=nil); header(EAP, arg); end
|
222
222
|
end
|
223
223
|
|
224
224
|
# Invert between a request and a response packet. Not action for
|
data/lib/packetgen/header/eth.rb
CHANGED
@@ -34,13 +34,28 @@ module PacketGen
|
|
34
34
|
|
35
35
|
k, v = h.split(':', 2)
|
36
36
|
[k, v.strip]
|
37
|
-
end.
|
37
|
+
end.compact.to_h
|
38
38
|
when Hash
|
39
39
|
@data = s_or_h
|
40
40
|
end
|
41
41
|
self
|
42
42
|
end
|
43
43
|
|
44
|
+
# Get header value from its name
|
45
|
+
# @param [String] header header name
|
46
|
+
# @return [String] header value
|
47
|
+
def [](header)
|
48
|
+
data[header]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Say if +self+ include +header+ header
|
52
|
+
# @param [String] header header name
|
53
|
+
# @return [Boolean]
|
54
|
+
def header?(header)
|
55
|
+
data.key?(header)
|
56
|
+
end
|
57
|
+
alias has_header? header?
|
58
|
+
|
44
59
|
# Get binary string.
|
45
60
|
# @return [String]
|
46
61
|
def to_s
|
@@ -67,11 +67,42 @@ module PacketGen
|
|
67
67
|
# Read in the HTTP portion of the packet, and parse it.
|
68
68
|
# @return [PacketGen::HTTP::Response]
|
69
69
|
def read(str)
|
70
|
-
|
71
|
-
|
70
|
+
headers, data = collect_headers_and_data(str)
|
71
|
+
|
72
|
+
unless headers.empty?
|
73
|
+
extract_info_from_first_line(headers)
|
74
|
+
self[:headers].read(headers.join("\n"))
|
75
|
+
end
|
76
|
+
self[:body].read data.join("\n")
|
77
|
+
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def parse?
|
82
|
+
version.start_with?('HTTP/1.')
|
83
|
+
end
|
84
|
+
|
85
|
+
# String representation of data.
|
86
|
+
# @return [String]
|
87
|
+
def to_s
|
88
|
+
raise_on_bad_version_status
|
89
|
+
|
90
|
+
str = +''
|
91
|
+
str << self.version << ' ' << self.status_code << ' ' << self.status_mesg << "\r\n"
|
92
|
+
str << self[:headers].to_s if self[:headers].given?
|
93
|
+
str << self.body
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def collect_headers_and_data(str)
|
72
99
|
headers = [] # header stream
|
73
100
|
data = [] # data stream
|
74
101
|
switch = false
|
102
|
+
|
103
|
+
str = str.bytes.map!(&:chr).join unless str.valid_encoding?
|
104
|
+
arr = str.split("\r\n")
|
105
|
+
|
75
106
|
arr.each do |line|
|
76
107
|
if line.empty?
|
77
108
|
data << line if switch # already done
|
@@ -85,34 +116,23 @@ module PacketGen
|
|
85
116
|
headers << line
|
86
117
|
end
|
87
118
|
end
|
88
|
-
|
89
|
-
|
90
|
-
if first_line.size >= 3
|
91
|
-
self[:version].read first_line[0]
|
92
|
-
self[:status_code].read first_line[1]
|
93
|
-
self[:status_mesg].read first_line[2..-1].join(' ')
|
94
|
-
end
|
95
|
-
self[:headers].read(headers.join("\n"))
|
96
|
-
end
|
97
|
-
self[:body].read data.join("\n")
|
98
|
-
self
|
119
|
+
|
120
|
+
[headers, data]
|
99
121
|
end
|
100
122
|
|
101
|
-
def
|
102
|
-
|
123
|
+
def extract_info_from_first_line(headers)
|
124
|
+
first_line = headers.shift.split
|
125
|
+
return if first_line.size < 3
|
126
|
+
|
127
|
+
self[:version].read first_line[0]
|
128
|
+
self[:status_code].read first_line[1]
|
129
|
+
self[:status_mesg].read first_line[2..-1].join(' ')
|
103
130
|
end
|
104
131
|
|
105
|
-
|
106
|
-
# @return [String]
|
107
|
-
def to_s
|
132
|
+
def raise_on_bad_version_status
|
108
133
|
raise FormatError, 'Missing #status_code.' if self.status_code.empty?
|
109
134
|
raise FormatError, 'Missing #status_mesg.' if self.status_mesg.empty?
|
110
135
|
raise FormatError, 'Missing #version.' if self.version.empty?
|
111
|
-
|
112
|
-
str = +''
|
113
|
-
str << self.version << ' ' << self.status_code << ' ' << self.status_mesg << "\r\n"
|
114
|
-
str << self[:headers].to_s if self[:headers].given?
|
115
|
-
str << self.body
|
116
136
|
end
|
117
137
|
end
|
118
138
|
end
|
@@ -77,7 +77,7 @@ module PacketGen
|
|
77
77
|
# directly called
|
78
78
|
def added_to_packet(packet)
|
79
79
|
igmp_idx = packet.headers.size
|
80
|
-
packet.instance_eval "def igmpize() @headers[#{igmp_idx}].igmpize; end"
|
80
|
+
packet.instance_eval "def igmpize() @headers[#{igmp_idx}].igmpize; end" # def igmpize() @headers[2].igmpize; end
|
81
81
|
end
|
82
82
|
|
83
83
|
# Get human readbale type
|
@@ -55,7 +55,7 @@ module PacketGen
|
|
55
55
|
# option data
|
56
56
|
# @return [String]
|
57
57
|
define_field :data, Types::String, optional: ->(h) { h.length > 2 },
|
58
|
-
|
58
|
+
builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) }
|
59
59
|
|
60
60
|
# @!attribute copied
|
61
61
|
# 1-bit copied flag from {#type} field
|
@@ -86,25 +86,23 @@ module PacketGen
|
|
86
86
|
# Factory to build an option from its type
|
87
87
|
# @return [Option]
|
88
88
|
def self.build(options={})
|
89
|
-
type = options
|
89
|
+
type = options[:type]
|
90
90
|
klass = case type
|
91
91
|
when String
|
92
92
|
types.key?(type) ? IP.const_get(type) : self
|
93
|
-
when Integer
|
94
|
-
types.value?(type) ? IP.const_get(types.key(type)) : self
|
95
93
|
else
|
96
|
-
self
|
94
|
+
types.value?(type) ? IP.const_get(types.key(type.to_i)) : self
|
97
95
|
end
|
96
|
+
options.delete(:type) if klass != self
|
98
97
|
klass.new(options)
|
99
98
|
end
|
100
99
|
|
101
100
|
def initialize(options={})
|
102
|
-
unless options[:type]
|
103
|
-
|
104
|
-
options[:type] = Option.const_get("#{opt_name}_TYPE") if Option.const_defined? "#{opt_name}_TYPE"
|
105
|
-
end
|
101
|
+
options[:type] = class2type unless options[:type]
|
102
|
+
|
106
103
|
super
|
107
|
-
|
104
|
+
initialize_length_if_needed(options)
|
105
|
+
initialize_data_if_needed(options)
|
108
106
|
end
|
109
107
|
|
110
108
|
# Get binary string. Set {#length} field.
|
@@ -121,6 +119,25 @@ module PacketGen
|
|
121
119
|
str << ":#{self[:data].to_s.inspect}" if respond_to?(:length) && (length > 2) && !self[:data].to_s.empty?
|
122
120
|
str
|
123
121
|
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def class2type
|
126
|
+
opt_name = self.class.to_s.gsub(/.*::/, '')
|
127
|
+
Option.const_get("#{opt_name}_TYPE") if Option.const_defined? "#{opt_name}_TYPE"
|
128
|
+
end
|
129
|
+
|
130
|
+
def initialize_length_if_needed(options)
|
131
|
+
self.length = sz if respond_to?(:length) && options[:length].nil?
|
132
|
+
end
|
133
|
+
|
134
|
+
def initialize_data_if_needed(options)
|
135
|
+
return unless fields.include?(:data) && self[:data].respond_to?(:from_human) && options.key?(:data)
|
136
|
+
|
137
|
+
# Force data if data is set in options but not length
|
138
|
+
self.length += options[:data].size
|
139
|
+
self[:data].from_human(options[:data])
|
140
|
+
end
|
124
141
|
end
|
125
142
|
|
126
143
|
# End-of-option-List IP option
|
@@ -161,6 +178,7 @@ module PacketGen
|
|
161
178
|
|
162
179
|
# Strict Source and Record Route IP option
|
163
180
|
class SSRR < LSRR; end
|
181
|
+
|
164
182
|
# Record Route IP option
|
165
183
|
class RR < LSRR; end
|
166
184
|
|
@@ -172,6 +190,10 @@ module PacketGen
|
|
172
190
|
# 16-bit stream ID
|
173
191
|
# @return [Integer]
|
174
192
|
define_field :id, Types::Int16
|
193
|
+
|
194
|
+
def to_human
|
195
|
+
super << ":#{self.id}"
|
196
|
+
end
|
175
197
|
end
|
176
198
|
|
177
199
|
# Router Alert IP option
|
@@ -182,6 +204,10 @@ module PacketGen
|
|
182
204
|
# 16-bit value. Should be 0.
|
183
205
|
# @return [Integer]
|
184
206
|
define_field :value, Types::Int16, default: 0
|
207
|
+
|
208
|
+
def to_human
|
209
|
+
super << ":#{self.value}"
|
210
|
+
end
|
185
211
|
end
|
186
212
|
end
|
187
213
|
end
|
@@ -49,6 +49,8 @@ module PacketGen
|
|
49
49
|
# @return [Integer]
|
50
50
|
define_field :a8, Types::Int16
|
51
51
|
|
52
|
+
# rubocop:disable Metrics/AbcSize
|
53
|
+
|
52
54
|
# Read a colon-delimited address
|
53
55
|
# @param [String] str
|
54
56
|
# @return [self]
|
@@ -69,6 +71,7 @@ module PacketGen
|
|
69
71
|
self.a8 = addri & 0xffff
|
70
72
|
self
|
71
73
|
end
|
74
|
+
# rubocop:enable Metrics/AbcSize
|
72
75
|
|
73
76
|
# Addr6 in human readable form (colon-delimited hex string)
|
74
77
|
# @return [String]
|