Class: Mu::Pcap::SCTP
- Inherits:
-
Packet
show all
- Defined in:
- lib/mu/pcap/sctp.rb,
lib/mu/pcap/sctp/chunk.rb,
lib/mu/pcap/sctp/parameter.rb,
lib/mu/pcap/sctp/chunk/data.rb,
lib/mu/pcap/sctp/chunk/init.rb,
lib/mu/pcap/sctp/chunk/init_ack.rb,
lib/mu/pcap/sctp/parameter/ip_address.rb
Defined Under Namespace
Classes: Chunk, Parameter, ReorderError
Constant Summary
collapse
- CHUNK_DATA =
0x00
- CHUNK_INIT =
0x01
- CHUNK_INIT_ACK =
0x02
- CHUNK_SACK =
0x03
- CHUNK_HEARTBEAT =
0x04
- CHUNK_HEARTBEAT_ACK =
0x05
- CHUNK_ABORT =
0x06
- CHUNK_SHUTDOWN =
0x07
- CHUNK_SHUTDOWN_ACK =
0x08
- CHUNK_ERROR =
0x09
- CHUNK_COOKIE_ECHO =
0x0A
- CHUNK_COOKIE_ACK =
0x0B
- CHUNK_ECNE =
0x0C
- CHUNK_CWR =
0x0D
- CHUNK_SHUTDOWN_COMPLETE =
0x0E
- CHUNK_AUTH =
0x0F
- CHUNK_ASCONF_ACK =
0x80
- CHUNK_PADDING =
0x84
- CHUNK_FORWARD_TSN =
0xC0
- CHUNK_ASCONF =
0xC1
- PARAM_IPV4 =
0x0005
- PARAM_IPV6 =
0x0006
- PARAM_STATE_COOKIE =
0x0007
- PARAM_COOKIE_PRESERVATIVE =
0x0009
- PARAM_HOST_NAME_ADDR =
0x000B
- PARAM_SUPPORTED_ADDR_TYPES =
0x000C
- PARAM_ECN =
0x8000
- PARAM_RANDOM =
0x8002
- PARAM_CHUNK_LIST =
0x8003
- PARAM_HMAC_ALGORITHM =
0x8004
- PARAM_PADDING =
0x8005
- PARAM_SUPPORTED_EXTENSIONS =
0x8006
- PARAM_FORWARD_TSN =
0xC000
- PARAM_SET_PRIMARY_ADDR =
0xC004
- PARAM_ADAPTATION_LAYER_INDICATION =
0xC006
Constants inherited
from Packet
Packet::IGNORE_UDP_PORTS
Instance Attribute Summary collapse
Attributes inherited from Packet
#payload, #payload_raw
Class Method Summary
collapse
Instance Method Summary
collapse
Methods inherited from Packet
#deepdup, isolate_l7, normalize, #payload_bytes, #to_bytes
Constructor Details
#initialize ⇒ SCTP
Returns a new instance of SCTP.
50
51
52
53
54
55
56
57
58
|
# File 'lib/mu/pcap/sctp.rb', line 50
def initialize
super
@src_port = 0
@dst_port = 0
@verify_tag = 0
@checksum = 0
@payload = []
end
|
Instance Attribute Details
#checksum ⇒ Object
Returns the value of attribute checksum.
9
10
11
|
# File 'lib/mu/pcap/sctp.rb', line 9
def checksum
@checksum
end
|
#dst_port ⇒ Object
Returns the value of attribute dst_port.
9
10
11
|
# File 'lib/mu/pcap/sctp.rb', line 9
def dst_port
@dst_port
end
|
#src_port ⇒ Object
Returns the value of attribute src_port.
9
10
11
|
# File 'lib/mu/pcap/sctp.rb', line 9
def src_port
@src_port
end
|
#verify_tag ⇒ Object
Returns the value of attribute verify_tag.
9
10
11
|
# File 'lib/mu/pcap/sctp.rb', line 9
def verify_tag
@verify_tag
end
|
Class Method Details
.crc32(bytes) ⇒ Object
282
283
284
285
286
287
288
289
290
291
292
293
294
|
# File 'lib/mu/pcap/sctp.rb', line 282
def self.crc32 bytes
r = 0xFFFFFFFF
bytes.each_byte do |b|
r ^= b
8.times do
r = (r >> 1) ^ (0xEDB88320 * (r & 1))
end
end
return r ^ 0xFFFFFFFF
end
|
.from_bytes(bytes) ⇒ Object
Creates SCTP packet from the payload
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
# File 'lib/mu/pcap/sctp.rb', line 69
def self.from_bytes bytes
Pcap.assert(bytes.length >= 12,
"Truncated SCTP header: 12 > #{bytes.length}")
Pcap.assert(bytes.length >= 16,
"Truncated SCTP packet: got only #{bytes.length} bytes")
sport, dport, vtag, cksum = bytes.unpack('nnNN')
sctp = SCTP.new
sctp.src_port = sport
sctp.dst_port = dport
sctp.verify_tag = vtag
sctp.checksum = cksum
length = 12
while length < bytes.length
chunk = Chunk.from_bytes(bytes[length..-1])
length += chunk.padded_size
sctp << chunk
end
sctp.sync_payload
return sctp
end
|
.reorder(packets) ⇒ Object
Reorders SCTP packets, if necessary
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
|
# File 'lib/mu/pcap/sctp.rb', line 111
def self.reorder packets
tsns = {}
init_packets = {}
init_ack_packets = {}
reordered_packets = []
while not packets.empty?
packet = packets.shift
if not sctp?(packet)
reordered_packets << packet
else
sctp = packet.payload.payload
if 0 == sctp.verify_tag and not sctp.init?
raise ReorderError, "Non-Init packet with zero verify tag"
elsif sctp.init_or_ack? and 1 < sctp.chunk_count
raise ReorderError, "Init/Ack packet with more than 1 chunk"
elsif sctp.init?
sctp.checksum = sctp[0].init_tag
init_packets[sctp.reverse_flow_id] = sctp
reordered_packets << packet
elsif sctp.init_ack?
init_packet = init_packets.delete(sctp.flow_id)
if init_packet
init_packet.verify_tag = sctp[0].init_tag
sctp.checksum = init_packet.verify_tag
init_packets[init_packet.flow_id] = init_packet
else
Pcap.warning("Orphaned SCTP INIT_ACK packet")
end
init_ack_packets[sctp.flow_id] = sctp
reordered_packets << packet
elsif sctp.has_data?
init_packet = init_packets[sctp.flow_id]
init_ack_packet = init_ack_packets[sctp.flow_id]
if init_packet
sctp.checksum = init_packet.checksum
elsif init_ack_packet
sctp.checksum = init_ack_packet.checksum
else
Pcap.warning("Orphaned SCTP DATA packet detected")
end
if 1 == sctp.chunk_count and not tsns.member?(sctp[0].tsn)
tsns[sctp[0].tsn] = sctp[0]
sctp.sync_payload
reordered_packets << packet
else
sctp.chunk_count.times do
chunk = sctp.shift
if CHUNK_DATA == chunk.type
if not tsns.member?(chunk.tsn)
packet_new = packet.deepdup
sctp_new = SCTP.new
sctp_new.src_port = sctp.src_port
sctp_new.dst_port = sctp.dst_port
sctp_new.verify_tag = sctp.verify_tag
sctp_new.checksum = sctp.checksum
sctp_new << chunk
packet_new.payload.payload = sctp_new
tsns[chunk.tsn] = chunk
sctp_new.sync_payload
reordered_packets << packet_new
else
Pcap.warning("Duplicate chunk: #{chunk.tsn}")
end
else
Pcap.warning("Non-data chunk: #{chunk.type}")
end
end
end
else
end
end
end
return reordered_packets
end
|
.sctp?(packet) ⇒ Boolean
296
297
298
299
300
|
# File 'lib/mu/pcap/sctp.rb', line 296
def self.sctp? packet
return packet.is_a?(Ethernet) &&
packet.payload.is_a?(IP) &&
packet.payload.payload.is_a?(SCTP)
end
|
Instance Method Details
#<<(chunk) ⇒ Object
302
303
304
|
# File 'lib/mu/pcap/sctp.rb', line 302
def << chunk
@payload << chunk
end
|
#==(other) ⇒ Object
331
332
333
334
335
336
337
|
# File 'lib/mu/pcap/sctp.rb', line 331
def == other
return super &&
self.src_port == other.src_port &&
self.dst_port == other.dst_port &&
self.verify_tag == other.verify_tag &&
self.payload.size == other.payload.size
end
|
#[](index) ⇒ Object
310
311
312
|
# File 'lib/mu/pcap/sctp.rb', line 310
def [] index
return @payload[index]
end
|
#chunk_count ⇒ Object
314
315
316
|
# File 'lib/mu/pcap/sctp.rb', line 314
def chunk_count
return @payload.size
end
|
#flow_id ⇒ Object
60
61
62
|
# File 'lib/mu/pcap/sctp.rb', line 60
def flow_id
return [:sctp, @src_port, @dst_port, @verify_tag]
end
|
#has_data? ⇒ Boolean
318
319
320
321
322
|
# File 'lib/mu/pcap/sctp.rb', line 318
def has_data?
return @payload.any? do |chunk|
CHUNK_DATA == chunk.type
end
end
|
#init? ⇒ Boolean
339
340
341
342
343
344
345
|
# File 'lib/mu/pcap/sctp.rb', line 339
def init?
if CHUNK_INIT == @payload[0].type
return true
else
return false
end
end
|
#init_ack? ⇒ Boolean
347
348
349
350
351
352
353
|
# File 'lib/mu/pcap/sctp.rb', line 347
def init_ack?
if CHUNK_INIT_ACK == @payload[0].type
return true
else
return false
end
end
|
#init_or_ack? ⇒ Boolean
355
356
357
358
359
360
361
|
# File 'lib/mu/pcap/sctp.rb', line 355
def init_or_ack?
if CHUNK_INIT == @payload[0].type or CHUNK_INIT_ACK == @payload[0].type
return true
else
return false
end
end
|
#reverse_flow_id ⇒ Object
64
65
66
|
# File 'lib/mu/pcap/sctp.rb', line 64
def reverse_flow_id
return [:sctp, @dst_port, @src_port, @checksum]
end
|
#shift ⇒ Object
306
307
308
|
# File 'lib/mu/pcap/sctp.rb', line 306
def shift
return @payload.shift
end
|
#sync_payload ⇒ Object
269
270
271
272
273
274
275
276
277
278
279
280
|
# File 'lib/mu/pcap/sctp.rb', line 269
def sync_payload
@payload_raw = ''
@payload.each do |chunk|
@payload_raw << chunk.payload_raw
end
@payload_raw = nil if @payload_raw == ''
end
|
#to_s ⇒ Object
324
325
326
327
328
329
|
# File 'lib/mu/pcap/sctp.rb', line 324
def to_s
return "sctp(%d, %d, %d, %s)" % [@src_port,
@dst_port,
@verify_tag,
@payload.join(", ")]
end
|
#write(io, ip) ⇒ Object
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
|
# File 'lib/mu/pcap/sctp.rb', line 248
def write io, ip
if @payload_raw and @payload_raw.length + 20 > 65535
Pcap.warning("SCTP payload is too large")
end
= [@src_port, @dst_port, @verify_tag, @checksum].pack('nnNN')
io.write()
@payload.each do |chunk|
chunk.write(io, ip)
end
end
|