packetgen 3.1.6 → 3.2.1
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 -2
- data/bin/pgconsole +3 -3
- data/lib/packetgen/capture.rb +5 -1
- data/lib/packetgen/header/arp.rb +24 -13
- data/lib/packetgen/header/asn1_base.rb +19 -9
- data/lib/packetgen/header/base.rb +1 -1
- 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/data.rb +19 -29
- 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/request.rb +5 -1
- data/lib/packetgen/header/http/response.rb +46 -20
- data/lib/packetgen/header/http/verbs.rb +1 -1
- data/lib/packetgen/header/igmp.rb +1 -1
- data/lib/packetgen/header/ip/option.rb +2 -1
- 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.rb +7 -3
- 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 +8 -4
- data/lib/packetgen/header/ospfv3/lsa_header.rb +2 -4
- data/lib/packetgen/header/ospfv3.rb +1 -1
- data/lib/packetgen/header/snmp.rb +20 -14
- 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 +51 -5
- data/lib/packetgen/pcapng/file.rb +17 -15
- 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 +8 -1
- data/lib/packetgen/types/cstring.rb +20 -7
- 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/string.rb +16 -3
- data/lib/packetgen/types/tlv.rb +17 -9
- data/lib/packetgen/unknown_packet.rb +84 -0
- data/lib/packetgen/utils.rb +60 -27
- data/lib/packetgen/version.rb +1 -1
- data/lib/packetgen.rb +13 -4
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79dc573da10eb15bbd9f38e0c84ecdf9a92d076980628635d1b9e240e3ca2210
|
4
|
+
data.tar.gz: 0ae2bafa08e5a4a0b176276a141b8c8326265873bb20d86a75e07bb7018275ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c405a57b79c4a9bf0d9032b34d7381b33e8c0705c554023f6a8131c19c48fb0118201d94da62e4f74b9d53551cdbcd434cb6363f27a84e5c3e8459cb28d613b
|
7
|
+
data.tar.gz: 835969235415864e05b227dd5f0fb48535e3f414e60852cf788d6d90bf29be9a3a8dcf9b636ce8d500d29720753246e11459da925fea3f72f6cb8e11291565b8
|
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
|
2
2
|
[](https://badge.fury.io/rb/packetgen)
|
3
|
-
[](https://github.com/sdaubert/packetgen/actions?query=workflow%3Aci)
|
5
4
|
# PacketGen
|
6
5
|
|
7
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/capture.rb
CHANGED
@@ -122,7 +122,11 @@ module PacketGen
|
|
122
122
|
def add_packet(data, &block)
|
123
123
|
raw_packets << data
|
124
124
|
if @parse
|
125
|
-
|
125
|
+
begin
|
126
|
+
packet = Packet.parse(data)
|
127
|
+
rescue ParseError
|
128
|
+
packet = UnknownPacket.new.parse(data)
|
129
|
+
end
|
126
130
|
packets << packet
|
127
131
|
block&.call(packet)
|
128
132
|
elsif block
|
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,14 +19,20 @@ module PacketGen
|
|
19
19
|
class ASN1Base < RASN1::Model
|
20
20
|
include Headerable
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
class << self
|
23
|
+
# Define some methods from given ASN.1 fields to mimic {Base} attributes
|
24
|
+
# @param [Array<Symbol>] attributes
|
25
|
+
# @return [void]
|
26
|
+
def define_attributes(*attributes)
|
27
|
+
@attributes = attributes
|
28
|
+
attributes.each do |attr|
|
29
|
+
class_eval "def #{attr}; @elements[:#{attr}].value; end\n" \
|
30
|
+
"def #{attr}=(v); @elements[:#{attr}].value = v; end"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def known_headers
|
35
|
+
@known_headers ||= {}.freeze
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
@@ -37,7 +43,11 @@ module PacketGen
|
|
37
43
|
# @param [String] str
|
38
44
|
# @return [ASN1Base] self
|
39
45
|
def read(str)
|
40
|
-
|
46
|
+
begin
|
47
|
+
parse(str, ber: true)
|
48
|
+
rescue RASN1::ASN1Error
|
49
|
+
# suppress exception to allow guessing
|
50
|
+
end
|
41
51
|
self
|
42
52
|
end
|
43
53
|
|
@@ -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
|
@@ -67,59 +67,49 @@ module PacketGen
|
|
67
67
|
# Get destination MAC address
|
68
68
|
# @return [String]
|
69
69
|
def dst
|
70
|
-
|
71
|
-
|
72
|
-
when 0, 2
|
73
|
-
self.mac1
|
74
|
-
when 1, 3
|
75
|
-
self.mac3
|
76
|
-
end
|
70
|
+
_src_mac, dst_mac = src_dst_from_mac
|
71
|
+
self.send(dst_mac)
|
77
72
|
end
|
78
73
|
|
79
74
|
# Set destination MAC address
|
80
75
|
# @param [String] mac MAC address to set
|
81
76
|
# @return [String]
|
82
77
|
def dst=(mac)
|
83
|
-
|
84
|
-
|
85
|
-
when 0, 2
|
86
|
-
self.mac1 = mac
|
87
|
-
when 1, 3
|
88
|
-
self.mac3 = mac
|
89
|
-
end
|
78
|
+
_src_mac, dst_mac = src_dst_from_mac
|
79
|
+
self.send("#{dst_mac}=", mac)
|
90
80
|
end
|
91
81
|
|
92
82
|
# Get source MAC address
|
93
83
|
# @return [String]
|
94
84
|
def src
|
95
|
-
|
96
|
-
|
97
|
-
when 0, 1
|
98
|
-
self.mac2
|
99
|
-
when 2
|
100
|
-
self.mac3
|
101
|
-
when 3
|
102
|
-
self.mac4
|
103
|
-
end
|
85
|
+
src_mac, = src_dst_from_mac
|
86
|
+
self.send(src_mac)
|
104
87
|
end
|
105
88
|
|
106
89
|
# Set source MAC address
|
107
90
|
# @param [String] mac MAC address to set
|
108
91
|
# @return [String]
|
109
92
|
def src=(mac)
|
93
|
+
src_mac, = src_dst_from_mac
|
94
|
+
self.send("#{src_mac}=", mac)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def src_dst_from_mac
|
110
100
|
ds = frame_ctrl & 3
|
111
101
|
case ds
|
112
|
-
when 0
|
113
|
-
|
102
|
+
when 0
|
103
|
+
%i[mac2 mac1]
|
104
|
+
when 1
|
105
|
+
%i[mac2 mac3]
|
114
106
|
when 2
|
115
|
-
|
107
|
+
%i[mac3 mac1]
|
116
108
|
when 3
|
117
|
-
|
109
|
+
%i[mac4 mac3]
|
118
110
|
end
|
119
111
|
end
|
120
112
|
|
121
|
-
private
|
122
|
-
|
123
113
|
def define_applicable_fields
|
124
114
|
super
|
125
115
|
if (subtype >= 8) && !@applicable_fields.include?(:qos_ctrl)
|
@@ -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
@@ -81,6 +81,10 @@ module PacketGen
|
|
81
81
|
self
|
82
82
|
end
|
83
83
|
|
84
|
+
def parse?
|
85
|
+
VERBS.include?(self.verb) && self.version.start_with?('HTTP/1.')
|
86
|
+
end
|
87
|
+
|
84
88
|
# String representation of data.
|
85
89
|
# @return [String]
|
86
90
|
def to_s
|
@@ -116,6 +120,6 @@ module PacketGen
|
|
116
120
|
end
|
117
121
|
|
118
122
|
self.add_class HTTP::Request
|
119
|
-
TCP.bind HTTP::Request, body: ->(b) { HTTP::REQUEST_REGEX =~ b
|
123
|
+
TCP.bind HTTP::Request, body: ->(b) { b.nil? ? '' : HTTP::REQUEST_REGEX =~ b }
|
120
124
|
end
|
121
125
|
end
|
@@ -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,33 +116,28 @@ module PacketGen
|
|
85
116
|
headers << line
|
86
117
|
end
|
87
118
|
end
|
88
|
-
|
89
|
-
|
90
|
-
self[:version].read first_line[0]
|
91
|
-
self[:status_code].read first_line[1]
|
92
|
-
self[:status_mesg].read first_line[2..-1].join(' ')
|
93
|
-
self[:headers].read(headers.join("\n"))
|
94
|
-
end
|
95
|
-
self[:body].read data.join("\n")
|
96
|
-
self
|
119
|
+
|
120
|
+
[headers, data]
|
97
121
|
end
|
98
122
|
|
99
|
-
|
100
|
-
|
101
|
-
|
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(' ')
|
130
|
+
end
|
131
|
+
|
132
|
+
def raise_on_bad_version_status
|
102
133
|
raise FormatError, 'Missing #status_code.' if self.status_code.empty?
|
103
134
|
raise FormatError, 'Missing #status_mesg.' if self.status_mesg.empty?
|
104
135
|
raise FormatError, 'Missing #version.' if self.version.empty?
|
105
|
-
|
106
|
-
str = +''
|
107
|
-
str << self.version << ' ' << self.status_code << ' ' << self.status_mesg << "\r\n"
|
108
|
-
str << self[:headers].to_s if self[:headers].given?
|
109
|
-
str << self.body
|
110
136
|
end
|
111
137
|
end
|
112
138
|
end
|
113
139
|
|
114
140
|
self.add_class HTTP::Response
|
115
|
-
TCP.bind HTTP::Response, body: ->(b) { %r[^HTTP/1\.1\s\d{3,}\s.+] =~ b
|
141
|
+
TCP.bind HTTP::Response, body: ->(b) { b.nil? ? '' : %r[^HTTP/1\.1\s\d{3,}\s.+] =~ b }
|
116
142
|
end
|
117
143
|
end
|
@@ -16,7 +16,7 @@ module PacketGen
|
|
16
16
|
VERBS = %w[GET HEAD POST PUT DELETE CONNECT OPTIONS TRACE PATCH].freeze
|
17
17
|
|
18
18
|
# Identifiable HTTP request regular expression.
|
19
|
-
REQUEST_REGEX = Regexp.new("(#{VERBS.dup.join('|')})\\s+\\S+\\s+HTTP/1.1")
|
19
|
+
REQUEST_REGEX = Regexp.new("^(#{VERBS.dup.join('|')})\\s+\\S+\\s+HTTP/1.1")
|
20
20
|
end
|
21
21
|
end
|
22
22
|
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
|
@@ -161,6 +161,7 @@ module PacketGen
|
|
161
161
|
|
162
162
|
# Strict Source and Record Route IP option
|
163
163
|
class SSRR < LSRR; end
|
164
|
+
|
164
165
|
# Record Route IP option
|
165
166
|
class RR < LSRR; end
|
166
167
|
|
@@ -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]
|