DIY-pcap 0.4.1 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/.gitignore +4 -4
  2. data/DIY-pcap.gemspec +17 -17
  3. data/Gemfile +3 -3
  4. data/Rakefile +1 -1
  5. data/lib/DIY-pcap.rb +2 -2
  6. data/lib/diy/command.rb +7 -1
  7. data/lib/diy/controller.rb +10 -15
  8. data/lib/diy/live.rb +9 -2
  9. data/lib/diy/parser/mu/pcap/ethernet.rb +148 -148
  10. data/lib/diy/parser/mu/pcap/header.rb +75 -75
  11. data/lib/diy/parser/mu/pcap/io_pair.rb +67 -67
  12. data/lib/diy/parser/mu/pcap/io_wrapper.rb +76 -76
  13. data/lib/diy/parser/mu/pcap/ip.rb +61 -61
  14. data/lib/diy/parser/mu/pcap/ipv4.rb +257 -257
  15. data/lib/diy/parser/mu/pcap/ipv6.rb +148 -148
  16. data/lib/diy/parser/mu/pcap/packet.rb +104 -104
  17. data/lib/diy/parser/mu/pcap/pkthdr.rb +155 -155
  18. data/lib/diy/parser/mu/pcap/reader.rb +61 -61
  19. data/lib/diy/parser/mu/pcap/reader/http_family.rb +170 -170
  20. data/lib/diy/parser/mu/pcap/sctp.rb +367 -367
  21. data/lib/diy/parser/mu/pcap/sctp/chunk.rb +123 -123
  22. data/lib/diy/parser/mu/pcap/sctp/chunk/data.rb +134 -134
  23. data/lib/diy/parser/mu/pcap/sctp/chunk/init.rb +100 -100
  24. data/lib/diy/parser/mu/pcap/sctp/chunk/init_ack.rb +68 -68
  25. data/lib/diy/parser/mu/pcap/sctp/parameter.rb +110 -110
  26. data/lib/diy/parser/mu/pcap/sctp/parameter/ip_address.rb +48 -48
  27. data/lib/diy/parser/mu/pcap/stream_packetizer.rb +72 -72
  28. data/lib/diy/parser/mu/pcap/tcp.rb +505 -505
  29. data/lib/diy/parser/mu/pcap/udp.rb +69 -69
  30. data/lib/diy/parser/mu/scenario/pcap.rb +172 -172
  31. data/lib/diy/parser/mu/scenario/pcap/fields.rb +50 -50
  32. data/lib/diy/parser/mu/scenario/pcap/rtp.rb +71 -71
  33. data/lib/diy/parser/pcap.rb +109 -109
  34. data/lib/diy/version.rb +1 -1
  35. metadata +7 -9
@@ -1,367 +1,367 @@
1
- # http://www.mudynamics.com
2
- # http://labs.mudynamics.com
3
- # http://www.pcapr.net
4
-
5
- module Mu
6
- class Pcap
7
-
8
- class SCTP < Packet
9
- attr_accessor :src_port, :dst_port, :verify_tag, :checksum
10
-
11
- # SCTP chunk types
12
- CHUNK_DATA = 0x00
13
- CHUNK_INIT = 0x01
14
- CHUNK_INIT_ACK = 0x02
15
- CHUNK_SACK = 0x03
16
- CHUNK_HEARTBEAT = 0x04
17
- CHUNK_HEARTBEAT_ACK = 0x05
18
- CHUNK_ABORT = 0x06
19
- CHUNK_SHUTDOWN = 0x07
20
- CHUNK_SHUTDOWN_ACK = 0x08
21
- CHUNK_ERROR = 0x09
22
- CHUNK_COOKIE_ECHO = 0x0A
23
- CHUNK_COOKIE_ACK = 0x0B
24
- CHUNK_ECNE = 0x0C
25
- CHUNK_CWR = 0x0D
26
- CHUNK_SHUTDOWN_COMPLETE = 0x0E
27
- CHUNK_AUTH = 0x0F
28
- CHUNK_ASCONF_ACK = 0x80
29
- CHUNK_PADDING = 0x84
30
- CHUNK_FORWARD_TSN = 0xC0
31
- CHUNK_ASCONF = 0xC1
32
-
33
- # SCTP parameter types
34
- PARAM_IPV4 = 0x0005
35
- PARAM_IPV6 = 0x0006
36
- PARAM_STATE_COOKIE = 0x0007
37
- PARAM_COOKIE_PRESERVATIVE = 0x0009
38
- PARAM_HOST_NAME_ADDR = 0x000B
39
- PARAM_SUPPORTED_ADDR_TYPES = 0x000C
40
- PARAM_ECN = 0x8000
41
- PARAM_RANDOM = 0x8002
42
- PARAM_CHUNK_LIST = 0x8003
43
- PARAM_HMAC_ALGORITHM = 0x8004
44
- PARAM_PADDING = 0x8005
45
- PARAM_SUPPORTED_EXTENSIONS = 0x8006
46
- PARAM_FORWARD_TSN = 0xC000
47
- PARAM_SET_PRIMARY_ADDR = 0xC004
48
- PARAM_ADAPTATION_LAYER_INDICATION = 0xC006
49
-
50
- def initialize
51
- super
52
-
53
- @src_port = 0
54
- @dst_port = 0
55
- @verify_tag = 0
56
- @checksum = 0
57
- @payload = []
58
- end
59
-
60
- def flow_id
61
- return [:sctp, @src_port, @dst_port, @verify_tag]
62
- end
63
-
64
- def reverse_flow_id
65
- return [:sctp, @dst_port, @src_port, @checksum]
66
- end
67
-
68
- # Creates SCTP packet from the payload
69
- def self.from_bytes bytes
70
- # Basic packet validation
71
- Pcap.assert(bytes.length >= 12,
72
- "Truncated SCTP header: 12 > #{bytes.length}")
73
- Pcap.assert(bytes.length >= 16,
74
- "Truncated SCTP packet: got only #{bytes.length} bytes")
75
-
76
- # Read SCTP header
77
- sport, dport, vtag, cksum = bytes.unpack('nnNN')
78
-
79
- # Create SCTP packet and populate SCTP header fields
80
- sctp = SCTP.new
81
- sctp.src_port = sport
82
- sctp.dst_port = dport
83
- sctp.verify_tag = vtag
84
- sctp.checksum = cksum
85
-
86
- # Initialize the counter
87
- length = 12
88
-
89
- # Collect the chunks
90
- while length < bytes.length
91
- # Parse new chunk from the bytes
92
- chunk = Chunk.from_bytes(bytes[length..-1])
93
-
94
- # Get chunk size with padding
95
- length += chunk.padded_size
96
-
97
- # Add chunk to the list
98
- sctp << chunk
99
- end
100
-
101
- # Sync the payload
102
- sctp.sync_payload
103
-
104
- # Return the result
105
- return sctp
106
- end
107
-
108
- class ReorderError < StandardError ; end
109
-
110
- # Reorders SCTP packets, if necessary
111
- def self.reorder packets
112
- # Initialize
113
- tsns = {}
114
- init_packets = {}
115
- init_ack_packets = {}
116
- reordered_packets = []
117
-
118
- # Iterate over each packet
119
- while not packets.empty?
120
- # Get next packet
121
- packet = packets.shift
122
-
123
- # Do not reorder non-SCTP packets
124
- if not sctp?(packet)
125
- reordered_packets << packet
126
- else
127
- # Get SCTP portion
128
- sctp = packet.payload.payload
129
-
130
- # Sanity checks and packet filtering/preprocessing
131
- if 0 == sctp.verify_tag and not sctp.init?
132
- # Non-Init packet with 0 verify tag
133
- raise ReorderError, "Non-Init packet with zero verify tag"
134
- elsif sctp.init_or_ack? and 1 < sctp.chunk_count
135
- # Init/InitAck packet with more with one chunk
136
- raise ReorderError, "Init/Ack packet with more than 1 chunk"
137
- elsif sctp.init?
138
- # Use checksum to save reverse verify tag in the Init packet
139
- sctp.checksum = sctp[0].init_tag
140
-
141
- # Save orphaned Init packets until we find the Ack
142
- init_packets[sctp.reverse_flow_id] = sctp
143
-
144
- # Add packet for further processing
145
- reordered_packets << packet
146
- elsif sctp.init_ack?
147
- # Lookup Init packet and construct it's flow it
148
- init_packet = init_packets.delete(sctp.flow_id)
149
-
150
- # Did we find anything?
151
- if init_packet
152
- # Set verify tag in the Init packet
153
- init_packet.verify_tag = sctp[0].init_tag
154
-
155
- # Set reverse verify tag in the InitAck packet
156
- sctp.checksum = init_packet.verify_tag
157
-
158
- # Re-insert INIT packet keyed by its flow id
159
- init_packets[init_packet.flow_id] = init_packet
160
- else
161
- Pcap.warning("Orphaned SCTP INIT_ACK packet")
162
- end
163
-
164
- # Save InitAck packet
165
- init_ack_packets[sctp.flow_id] = sctp
166
-
167
- # Add packet for further processing
168
- reordered_packets << packet
169
- elsif sctp.has_data?
170
- # SCTP packet with user data; lookup Init or InitAck packet
171
- init_packet = init_packets[sctp.flow_id]
172
- init_ack_packet = init_ack_packets[sctp.flow_id]
173
-
174
- # It should belong to either one flow id or the other
175
- if init_packet
176
- # Set reverse verify tag from Init packet
177
- sctp.checksum = init_packet.checksum
178
- elsif init_ack_packet
179
- # Set reverse flow id from InitAck packet
180
- sctp.checksum = init_ack_packet.checksum
181
- else
182
- # Orphaned SCTP packet -- not very good
183
- Pcap.warning("Orphaned SCTP DATA packet detected")
184
- end
185
-
186
- # If we have just one chunk we are done
187
- if 1 == sctp.chunk_count and not tsns.member?(sctp[0].tsn)
188
- # Save TSN
189
- tsns[sctp[0].tsn] = sctp[0]
190
-
191
- # sync the payload
192
- sctp.sync_payload
193
-
194
- # Add packet for further processing
195
- reordered_packets << packet
196
- else
197
- # Split each data chunk in a separate SCTP packet
198
- sctp.chunk_count.times do
199
- # Get next chunk
200
- chunk = sctp.shift
201
-
202
- # Is it data?
203
- if CHUNK_DATA == chunk.type
204
- # Yes, check for duplicate TSNs
205
- if not tsns.member?(chunk.tsn)
206
- # Not a duplicate; create new SCTP packet
207
- packet_new = packet.deepdup
208
-
209
- # Create new SCTP payload
210
- sctp_new = SCTP.new
211
- sctp_new.src_port = sctp.src_port
212
- sctp_new.dst_port = sctp.dst_port
213
- sctp_new.verify_tag = sctp.verify_tag
214
- sctp_new.checksum = sctp.checksum
215
-
216
- # Add the chunk
217
- sctp_new << chunk
218
-
219
- # Add SCTP payload to the new packet
220
- packet_new.payload.payload = sctp_new
221
-
222
- # Save TSN
223
- tsns[chunk.tsn] = chunk
224
-
225
- # Sync the payload
226
- sctp_new.sync_payload
227
-
228
- # Add packet for further processing
229
- reordered_packets << packet_new
230
- else
231
- Pcap.warning("Duplicate chunk: #{chunk.tsn}")
232
- end
233
- else
234
- Pcap.warning("Non-data chunk: #{chunk.type}")
235
- end
236
- end
237
- end
238
- else
239
- # Other SCTP packet; we are not interested at this time
240
- end
241
- end
242
- end
243
-
244
- # Return the result
245
- return reordered_packets
246
- end
247
-
248
- def write io, ip
249
- # Give a warning if packet size exceeds maximum allowed
250
- if @payload_raw and @payload_raw.length + 20 > 65535
251
- Pcap.warning("SCTP payload is too large")
252
- end
253
-
254
- # Calculate CRC32 checksum on the packet; temporarily removed due to a
255
- # hack that uses checksum to link forward and reverse SCTP flow IDs.
256
- #header = [@src_port, @dst_port, @verify_tag, 0].pack('nnNN')
257
- #checksum = SCTP.crc32(header + @payload_raw)
258
- header = [@src_port, @dst_port, @verify_tag, @checksum].pack('nnNN')
259
-
260
- # Write SCTP header followed by each chunk
261
- io.write(header)
262
-
263
- # Write each chunks' data
264
- @payload.each do |chunk|
265
- chunk.write(io, ip)
266
- end
267
- end
268
-
269
- def sync_payload
270
- # Reset raw bytes
271
- @payload_raw = ''
272
-
273
- # Iterate over each chunk
274
- @payload.each do |chunk|
275
- @payload_raw << chunk.payload_raw
276
- end
277
-
278
- # Reset raw payload if it's empty
279
- @payload_raw = nil if @payload_raw == ''
280
- end
281
-
282
- def self.crc32 bytes
283
- r = 0xFFFFFFFF
284
-
285
- bytes.each_byte do |b|
286
- r ^= b
287
-
288
- 8.times do
289
- r = (r >> 1) ^ (0xEDB88320 * (r & 1))
290
- end
291
- end
292
-
293
- return r ^ 0xFFFFFFFF
294
- end
295
-
296
- def self.sctp? packet
297
- return packet.is_a?(Ethernet) &&
298
- packet.payload.is_a?(IP) &&
299
- packet.payload.payload.is_a?(SCTP)
300
- end
301
-
302
- def << chunk
303
- @payload << chunk
304
- end
305
-
306
- def shift
307
- return @payload.shift
308
- end
309
-
310
- def [] index
311
- return @payload[index]
312
- end
313
-
314
- def chunk_count
315
- return @payload.size
316
- end
317
-
318
- def has_data?
319
- return @payload.any? do |chunk|
320
- CHUNK_DATA == chunk.type
321
- end
322
- end
323
-
324
- def to_s
325
- return "sctp(%d, %d, %d, %s)" % [@src_port,
326
- @dst_port,
327
- @verify_tag,
328
- @payload.join(", ")]
329
- end
330
-
331
- def == other
332
- return super &&
333
- self.src_port == other.src_port &&
334
- self.dst_port == other.dst_port &&
335
- self.verify_tag == other.verify_tag &&
336
- self.payload.size == other.payload.size
337
- end
338
-
339
- def init?
340
- if CHUNK_INIT == @payload[0].type
341
- return true
342
- else
343
- return false
344
- end
345
- end
346
-
347
- def init_ack?
348
- if CHUNK_INIT_ACK == @payload[0].type
349
- return true
350
- else
351
- return false
352
- end
353
- end
354
-
355
- def init_or_ack?
356
- if CHUNK_INIT == @payload[0].type or CHUNK_INIT_ACK == @payload[0].type
357
- return true
358
- else
359
- return false
360
- end
361
- end
362
- end # class SCTP
363
-
364
- end # class Pcap
365
- end # module Mu
366
-
367
- require 'mu/pcap/sctp/chunk'
1
+ # http://www.mudynamics.com
2
+ # http://labs.mudynamics.com
3
+ # http://www.pcapr.net
4
+
5
+ module Mu
6
+ class Pcap
7
+
8
+ class SCTP < Packet
9
+ attr_accessor :src_port, :dst_port, :verify_tag, :checksum
10
+
11
+ # SCTP chunk types
12
+ CHUNK_DATA = 0x00
13
+ CHUNK_INIT = 0x01
14
+ CHUNK_INIT_ACK = 0x02
15
+ CHUNK_SACK = 0x03
16
+ CHUNK_HEARTBEAT = 0x04
17
+ CHUNK_HEARTBEAT_ACK = 0x05
18
+ CHUNK_ABORT = 0x06
19
+ CHUNK_SHUTDOWN = 0x07
20
+ CHUNK_SHUTDOWN_ACK = 0x08
21
+ CHUNK_ERROR = 0x09
22
+ CHUNK_COOKIE_ECHO = 0x0A
23
+ CHUNK_COOKIE_ACK = 0x0B
24
+ CHUNK_ECNE = 0x0C
25
+ CHUNK_CWR = 0x0D
26
+ CHUNK_SHUTDOWN_COMPLETE = 0x0E
27
+ CHUNK_AUTH = 0x0F
28
+ CHUNK_ASCONF_ACK = 0x80
29
+ CHUNK_PADDING = 0x84
30
+ CHUNK_FORWARD_TSN = 0xC0
31
+ CHUNK_ASCONF = 0xC1
32
+
33
+ # SCTP parameter types
34
+ PARAM_IPV4 = 0x0005
35
+ PARAM_IPV6 = 0x0006
36
+ PARAM_STATE_COOKIE = 0x0007
37
+ PARAM_COOKIE_PRESERVATIVE = 0x0009
38
+ PARAM_HOST_NAME_ADDR = 0x000B
39
+ PARAM_SUPPORTED_ADDR_TYPES = 0x000C
40
+ PARAM_ECN = 0x8000
41
+ PARAM_RANDOM = 0x8002
42
+ PARAM_CHUNK_LIST = 0x8003
43
+ PARAM_HMAC_ALGORITHM = 0x8004
44
+ PARAM_PADDING = 0x8005
45
+ PARAM_SUPPORTED_EXTENSIONS = 0x8006
46
+ PARAM_FORWARD_TSN = 0xC000
47
+ PARAM_SET_PRIMARY_ADDR = 0xC004
48
+ PARAM_ADAPTATION_LAYER_INDICATION = 0xC006
49
+
50
+ def initialize
51
+ super
52
+
53
+ @src_port = 0
54
+ @dst_port = 0
55
+ @verify_tag = 0
56
+ @checksum = 0
57
+ @payload = []
58
+ end
59
+
60
+ def flow_id
61
+ return [:sctp, @src_port, @dst_port, @verify_tag]
62
+ end
63
+
64
+ def reverse_flow_id
65
+ return [:sctp, @dst_port, @src_port, @checksum]
66
+ end
67
+
68
+ # Creates SCTP packet from the payload
69
+ def self.from_bytes bytes
70
+ # Basic packet validation
71
+ Pcap.assert(bytes.length >= 12,
72
+ "Truncated SCTP header: 12 > #{bytes.length}")
73
+ Pcap.assert(bytes.length >= 16,
74
+ "Truncated SCTP packet: got only #{bytes.length} bytes")
75
+
76
+ # Read SCTP header
77
+ sport, dport, vtag, cksum = bytes.unpack('nnNN')
78
+
79
+ # Create SCTP packet and populate SCTP header fields
80
+ sctp = SCTP.new
81
+ sctp.src_port = sport
82
+ sctp.dst_port = dport
83
+ sctp.verify_tag = vtag
84
+ sctp.checksum = cksum
85
+
86
+ # Initialize the counter
87
+ length = 12
88
+
89
+ # Collect the chunks
90
+ while length < bytes.length
91
+ # Parse new chunk from the bytes
92
+ chunk = Chunk.from_bytes(bytes[length..-1])
93
+
94
+ # Get chunk size with padding
95
+ length += chunk.padded_size
96
+
97
+ # Add chunk to the list
98
+ sctp << chunk
99
+ end
100
+
101
+ # Sync the payload
102
+ sctp.sync_payload
103
+
104
+ # Return the result
105
+ return sctp
106
+ end
107
+
108
+ class ReorderError < StandardError ; end
109
+
110
+ # Reorders SCTP packets, if necessary
111
+ def self.reorder packets
112
+ # Initialize
113
+ tsns = {}
114
+ init_packets = {}
115
+ init_ack_packets = {}
116
+ reordered_packets = []
117
+
118
+ # Iterate over each packet
119
+ while not packets.empty?
120
+ # Get next packet
121
+ packet = packets.shift
122
+
123
+ # Do not reorder non-SCTP packets
124
+ if not sctp?(packet)
125
+ reordered_packets << packet
126
+ else
127
+ # Get SCTP portion
128
+ sctp = packet.payload.payload
129
+
130
+ # Sanity checks and packet filtering/preprocessing
131
+ if 0 == sctp.verify_tag and not sctp.init?
132
+ # Non-Init packet with 0 verify tag
133
+ raise ReorderError, "Non-Init packet with zero verify tag"
134
+ elsif sctp.init_or_ack? and 1 < sctp.chunk_count
135
+ # Init/InitAck packet with more with one chunk
136
+ raise ReorderError, "Init/Ack packet with more than 1 chunk"
137
+ elsif sctp.init?
138
+ # Use checksum to save reverse verify tag in the Init packet
139
+ sctp.checksum = sctp[0].init_tag
140
+
141
+ # Save orphaned Init packets until we find the Ack
142
+ init_packets[sctp.reverse_flow_id] = sctp
143
+
144
+ # Add packet for further processing
145
+ reordered_packets << packet
146
+ elsif sctp.init_ack?
147
+ # Lookup Init packet and construct it's flow it
148
+ init_packet = init_packets.delete(sctp.flow_id)
149
+
150
+ # Did we find anything?
151
+ if init_packet
152
+ # Set verify tag in the Init packet
153
+ init_packet.verify_tag = sctp[0].init_tag
154
+
155
+ # Set reverse verify tag in the InitAck packet
156
+ sctp.checksum = init_packet.verify_tag
157
+
158
+ # Re-insert INIT packet keyed by its flow id
159
+ init_packets[init_packet.flow_id] = init_packet
160
+ else
161
+ Pcap.warning("Orphaned SCTP INIT_ACK packet")
162
+ end
163
+
164
+ # Save InitAck packet
165
+ init_ack_packets[sctp.flow_id] = sctp
166
+
167
+ # Add packet for further processing
168
+ reordered_packets << packet
169
+ elsif sctp.has_data?
170
+ # SCTP packet with user data; lookup Init or InitAck packet
171
+ init_packet = init_packets[sctp.flow_id]
172
+ init_ack_packet = init_ack_packets[sctp.flow_id]
173
+
174
+ # It should belong to either one flow id or the other
175
+ if init_packet
176
+ # Set reverse verify tag from Init packet
177
+ sctp.checksum = init_packet.checksum
178
+ elsif init_ack_packet
179
+ # Set reverse flow id from InitAck packet
180
+ sctp.checksum = init_ack_packet.checksum
181
+ else
182
+ # Orphaned SCTP packet -- not very good
183
+ Pcap.warning("Orphaned SCTP DATA packet detected")
184
+ end
185
+
186
+ # If we have just one chunk we are done
187
+ if 1 == sctp.chunk_count and not tsns.member?(sctp[0].tsn)
188
+ # Save TSN
189
+ tsns[sctp[0].tsn] = sctp[0]
190
+
191
+ # sync the payload
192
+ sctp.sync_payload
193
+
194
+ # Add packet for further processing
195
+ reordered_packets << packet
196
+ else
197
+ # Split each data chunk in a separate SCTP packet
198
+ sctp.chunk_count.times do
199
+ # Get next chunk
200
+ chunk = sctp.shift
201
+
202
+ # Is it data?
203
+ if CHUNK_DATA == chunk.type
204
+ # Yes, check for duplicate TSNs
205
+ if not tsns.member?(chunk.tsn)
206
+ # Not a duplicate; create new SCTP packet
207
+ packet_new = packet.deepdup
208
+
209
+ # Create new SCTP payload
210
+ sctp_new = SCTP.new
211
+ sctp_new.src_port = sctp.src_port
212
+ sctp_new.dst_port = sctp.dst_port
213
+ sctp_new.verify_tag = sctp.verify_tag
214
+ sctp_new.checksum = sctp.checksum
215
+
216
+ # Add the chunk
217
+ sctp_new << chunk
218
+
219
+ # Add SCTP payload to the new packet
220
+ packet_new.payload.payload = sctp_new
221
+
222
+ # Save TSN
223
+ tsns[chunk.tsn] = chunk
224
+
225
+ # Sync the payload
226
+ sctp_new.sync_payload
227
+
228
+ # Add packet for further processing
229
+ reordered_packets << packet_new
230
+ else
231
+ Pcap.warning("Duplicate chunk: #{chunk.tsn}")
232
+ end
233
+ else
234
+ Pcap.warning("Non-data chunk: #{chunk.type}")
235
+ end
236
+ end
237
+ end
238
+ else
239
+ # Other SCTP packet; we are not interested at this time
240
+ end
241
+ end
242
+ end
243
+
244
+ # Return the result
245
+ return reordered_packets
246
+ end
247
+
248
+ def write io, ip
249
+ # Give a warning if packet size exceeds maximum allowed
250
+ if @payload_raw and @payload_raw.length + 20 > 65535
251
+ Pcap.warning("SCTP payload is too large")
252
+ end
253
+
254
+ # Calculate CRC32 checksum on the packet; temporarily removed due to a
255
+ # hack that uses checksum to link forward and reverse SCTP flow IDs.
256
+ #header = [@src_port, @dst_port, @verify_tag, 0].pack('nnNN')
257
+ #checksum = SCTP.crc32(header + @payload_raw)
258
+ header = [@src_port, @dst_port, @verify_tag, @checksum].pack('nnNN')
259
+
260
+ # Write SCTP header followed by each chunk
261
+ io.write(header)
262
+
263
+ # Write each chunks' data
264
+ @payload.each do |chunk|
265
+ chunk.write(io, ip)
266
+ end
267
+ end
268
+
269
+ def sync_payload
270
+ # Reset raw bytes
271
+ @payload_raw = ''
272
+
273
+ # Iterate over each chunk
274
+ @payload.each do |chunk|
275
+ @payload_raw << chunk.payload_raw
276
+ end
277
+
278
+ # Reset raw payload if it's empty
279
+ @payload_raw = nil if @payload_raw == ''
280
+ end
281
+
282
+ def self.crc32 bytes
283
+ r = 0xFFFFFFFF
284
+
285
+ bytes.each_byte do |b|
286
+ r ^= b
287
+
288
+ 8.times do
289
+ r = (r >> 1) ^ (0xEDB88320 * (r & 1))
290
+ end
291
+ end
292
+
293
+ return r ^ 0xFFFFFFFF
294
+ end
295
+
296
+ def self.sctp? packet
297
+ return packet.is_a?(Ethernet) &&
298
+ packet.payload.is_a?(IP) &&
299
+ packet.payload.payload.is_a?(SCTP)
300
+ end
301
+
302
+ def << chunk
303
+ @payload << chunk
304
+ end
305
+
306
+ def shift
307
+ return @payload.shift
308
+ end
309
+
310
+ def [] index
311
+ return @payload[index]
312
+ end
313
+
314
+ def chunk_count
315
+ return @payload.size
316
+ end
317
+
318
+ def has_data?
319
+ return @payload.any? do |chunk|
320
+ CHUNK_DATA == chunk.type
321
+ end
322
+ end
323
+
324
+ def to_s
325
+ return "sctp(%d, %d, %d, %s)" % [@src_port,
326
+ @dst_port,
327
+ @verify_tag,
328
+ @payload.join(", ")]
329
+ end
330
+
331
+ def == other
332
+ return super &&
333
+ self.src_port == other.src_port &&
334
+ self.dst_port == other.dst_port &&
335
+ self.verify_tag == other.verify_tag &&
336
+ self.payload.size == other.payload.size
337
+ end
338
+
339
+ def init?
340
+ if CHUNK_INIT == @payload[0].type
341
+ return true
342
+ else
343
+ return false
344
+ end
345
+ end
346
+
347
+ def init_ack?
348
+ if CHUNK_INIT_ACK == @payload[0].type
349
+ return true
350
+ else
351
+ return false
352
+ end
353
+ end
354
+
355
+ def init_or_ack?
356
+ if CHUNK_INIT == @payload[0].type or CHUNK_INIT_ACK == @payload[0].type
357
+ return true
358
+ else
359
+ return false
360
+ end
361
+ end
362
+ end # class SCTP
363
+
364
+ end # class Pcap
365
+ end # module Mu
366
+
367
+ require 'mu/pcap/sctp/chunk'