packetgen 3.2.0 → 3.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/packetgen.svg)](https://badge.fury.io/rb/packetgen)
|
3
|
-
|
3
|
+
[![Action status](https://github.com/sdaubert/packetgen/workflows/ci/badge.svg?branch=master)](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]
|