• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <webrtc/SCTPHandler.h>
18 
19 #include "Utils.h"
20 
21 #include <https/SafeCallbackable.h>
22 #include <https/Support.h>
23 
24 #include <android-base/logging.h>
25 
SCTPHandler(std::shared_ptr<RunLoop> runLoop,std::shared_ptr<DTLS> dtls)26 SCTPHandler::SCTPHandler(
27         std::shared_ptr<RunLoop> runLoop,
28         std::shared_ptr<DTLS> dtls)
29     : mRunLoop(runLoop),
30       mDTLS(dtls),
31       mInitiateTag(0),
32       mSendingTSN(0),
33       mSentGreeting(false) {
34 }
35 
run()36 void SCTPHandler::run() {
37 }
38 
inject(uint8_t * data,size_t size)39 int SCTPHandler::inject(uint8_t *data, size_t size) {
40     LOG(INFO)
41         << "Received SCTP datagram of size " << size << ":";
42 
43     hexdump(data, size);
44 
45     if (size < 12) {
46         // Need at least the common header.
47         return -EINVAL;
48     }
49 
50     auto srcPort = U16_AT(&data[0]);
51     auto dstPort = U16_AT(&data[2]);
52 
53     if (dstPort != 5000) {
54         return -EINVAL;
55     }
56 
57     auto checkSumIn = U32_AT(&data[8]);
58     SET_U32(&data[8], 0x00000000);
59     auto checkSum = crc32c(data, size);
60 
61     if (checkSumIn != checkSum) {
62         LOG(WARNING)
63             << "SCTPHandler::inject checksum invalid."
64             << " (in: " << StringPrintf("0x%08x", checkSumIn) << ", "
65             << "computed: " << StringPrintf("0x%08x", checkSum) << ")";
66 
67         return -EINVAL;
68     }
69 
70     bool firstChunk = true;
71     size_t offset = 12;
72     while (offset < size) {
73         if (offset + 4 > size) {
74             return -EINVAL;
75         }
76 
77         size_t chunkLength = U16_AT(&data[offset + 2]);
78 
79         if (offset + chunkLength > size) {
80             return -EINVAL;
81         }
82 
83         size_t paddedChunkLength = chunkLength;
84         size_t pad = chunkLength % 4;
85         if (pad) {
86             pad = 4 - pad;
87             paddedChunkLength += pad;
88         }
89 
90         bool lastChunk =
91             (offset + chunkLength == size)
92                 || (offset + paddedChunkLength == size);
93 
94         auto err = processChunk(
95                 srcPort,
96                 &data[offset],
97                 chunkLength,
98                 firstChunk,
99                 lastChunk);
100 
101         if (err) {
102             return err;
103         }
104 
105         firstChunk = false;
106 
107         offset += chunkLength;
108 
109         if (offset == size) {
110             break;
111         }
112 
113         if (offset + pad > size) {
114             return -EINVAL;
115         }
116 
117         offset += pad;
118     }
119 
120     return 0;
121 }
122 
processChunk(uint16_t srcPort,const uint8_t * data,size_t size,bool firstChunk,bool lastChunk)123 int SCTPHandler::processChunk(
124         uint16_t srcPort,
125         const uint8_t *data,
126         size_t size,
127         bool firstChunk,
128         bool lastChunk) {
129     static constexpr uint8_t DATA = 0;
130     static constexpr uint8_t INIT = 1;
131     static constexpr uint8_t INIT_ACK = 2;
132     static constexpr uint8_t SACK = 3;
133     static constexpr uint8_t HEARTBEAT = 4;
134     static constexpr uint8_t HEARTBEAT_ACK = 5;
135     static constexpr uint8_t COOKIE_ECHO = 10;
136     static constexpr uint8_t COOKIE_ACK = 11;
137     static constexpr uint8_t SHUTDOWN_COMPLETE = 14;
138 
139     static constexpr uint64_t kCookie = 0xDABBAD00DEADBAADull;
140 
141     auto chunkType = data[0];
142     if ((!firstChunk || !lastChunk)
143             && (chunkType == INIT
144                     || chunkType == INIT_ACK
145                     || chunkType == SHUTDOWN_COMPLETE)) {
146         // These chunks must be by themselves, no other chunks must be part
147         // of the same datagram.
148 
149         return -EINVAL;
150     }
151 
152     switch (chunkType) {
153         case INIT:
154         {
155             if (size < 20) {
156                 return -EINVAL;
157             }
158 
159             mInitiateTag = U32_AT(&data[4]);
160 
161             uint8_t out[12 + 24 + sizeof(kCookie)];
162             SET_U16(&out[0], 5000);
163             SET_U16(&out[2], srcPort);
164             SET_U32(&out[4], mInitiateTag);
165             SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
166 
167             size_t offset = 12;
168             out[offset++] = INIT_ACK;
169             out[offset++] = 0x00;
170 
171             SET_U16(&out[offset], sizeof(out) - 12);
172             offset += 2;
173 
174             SET_U32(&out[offset], 0xb0b0cafe);  // initiate tag
175             offset += 4;
176 
177             SET_U32(&out[offset], 0x00020000);  // a_rwnd
178             offset += 4;
179 
180             SET_U16(&out[offset], 1);  // Number of Outbound Streams
181             offset += 2;
182 
183             SET_U16(&out[offset], 1);  // Number of Inbound Streams
184             offset += 2;
185 
186             mSendingTSN = 0x12345678;
187 
188             SET_U32(&out[offset], mSendingTSN);  // Initial TSN
189             offset += 4;
190 
191             SET_U16(&out[offset], 0x0007);  // STATE_COOKIE
192             offset += 2;
193 
194             static_assert((sizeof(kCookie) % 4) == 0);
195 
196             SET_U16(&out[offset], 4 + sizeof(kCookie));
197             offset += 2;
198 
199             memcpy(&out[offset], &kCookie, sizeof(kCookie));
200             offset += sizeof(kCookie);
201 
202             CHECK_EQ(offset, sizeof(out));
203 
204             SET_U32(&out[8], crc32c(out, sizeof(out)));
205 
206             LOG(INFO) << "Sending SCTP INIT_ACK:";
207             hexdump(out, sizeof(out));
208 
209             mDTLS->writeApplicationData(out, sizeof(out));
210             break;
211         }
212 
213         case COOKIE_ECHO:
214         {
215             if (size != (4 + sizeof(kCookie))) {
216                 return -EINVAL;
217             }
218 
219             if (memcmp(&data[4], &kCookie, sizeof(kCookie))) {
220                 return -EINVAL;
221             }
222 
223             uint8_t out[12 + 4];
224             SET_U16(&out[0], 5000);
225             SET_U16(&out[2], srcPort);
226             SET_U32(&out[4], mInitiateTag);
227             SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
228 
229             size_t offset = 12;
230             out[offset++] = COOKIE_ACK;
231             out[offset++] = 0x00;
232             SET_U16(&out[offset], sizeof(out) - 12);
233             offset += 2;
234 
235             CHECK_EQ(offset, sizeof(out));
236 
237             SET_U32(&out[8], crc32c(out, sizeof(out)));
238 
239             LOG(INFO) << "Sending SCTP COOKIE_ACK:";
240             hexdump(out, sizeof(out));
241 
242             mDTLS->writeApplicationData(out, sizeof(out));
243             break;
244         }
245 
246         case DATA:
247         {
248             if (size < 17) {
249                 // Minimal size (16 bytes header + 1 byte payload), empty
250                 // payloads are prohibited.
251                 return -EINVAL;
252             }
253 
254             auto TSN = U32_AT(&data[4]);
255 
256             uint8_t out[12 + 16];
257             SET_U16(&out[0], 5000);
258             SET_U16(&out[2], srcPort);
259             SET_U32(&out[4], mInitiateTag);
260             SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
261 
262             size_t offset = 12;
263             out[offset++] = SACK;
264             out[offset++] = 0x00;
265 
266             SET_U16(&out[offset], sizeof(out) - 12);
267             offset += 2;
268 
269             SET_U32(&out[offset], TSN);
270             offset += 4;
271 
272             SET_U32(&out[offset], 0x00020000);  // a_rwnd
273             offset += 4;
274 
275             SET_U16(&out[offset], 0);  // Number of Gap Ack Blocks
276             offset += 2;
277 
278             SET_U16(&out[offset], 0);  // Number of Duplicate TSNs
279             offset += 2;
280 
281             CHECK_EQ(offset, sizeof(out));
282 
283             SET_U32(&out[8], crc32c(out, sizeof(out)));
284 
285             LOG(INFO) << "Sending SCTP SACK:";
286             hexdump(out, sizeof(out));
287 
288             mDTLS->writeApplicationData(out, sizeof(out));
289 
290             if (!mSentGreeting) {
291                 mRunLoop->postWithDelay(
292                         std::chrono::seconds(1),
293                         makeSafeCallback(
294                             this,
295                             &SCTPHandler::onSendGreeting,
296                             srcPort,
297                             (size_t)0 /* index */));
298 
299                 mSentGreeting = true;
300             }
301             break;
302         }
303 
304         case HEARTBEAT:
305         {
306             if (size < 8) {
307                 return -EINVAL;
308             }
309 
310             if (U16_AT(&data[4]) != 1 /* Heartbeat Info Type */
311                 || size != (U16_AT(&data[6]) + 4)) {
312                 return -EINVAL;
313             }
314 
315             size_t pad = size % 4;
316             if (pad) {
317                 pad = 4 - pad;
318             }
319 
320             std::vector<uint8_t> outVec(12 + size + pad);
321 
322             uint8_t *out = outVec.data();
323             SET_U16(&out[0], 5000);
324             SET_U16(&out[2], srcPort);
325             SET_U32(&out[4], mInitiateTag);
326             SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
327 
328             size_t offset = 12;
329             out[offset++] = HEARTBEAT_ACK;
330             out[offset++] = 0x00;
331 
332             SET_U16(&out[offset], outVec.size() - 12 - pad);
333             offset += 2;
334 
335             memcpy(&out[offset], &data[4], size - 4);
336             offset += size - 4;
337 
338             memset(&out[offset], 0x00, pad);
339             offset += pad;
340 
341             CHECK_EQ(offset, outVec.size());
342 
343             SET_U32(&out[8], crc32c(out, outVec.size()));
344 
345             LOG(INFO) << "Sending SCTP HEARTBEAT_ACK:";
346             hexdump(out, outVec.size());
347 
348             mDTLS->writeApplicationData(out, outVec.size());
349             break;
350         }
351 
352         default:
353             break;
354     }
355 
356     return 0;
357 }
358 
onSendGreeting(uint16_t srcPort,size_t index)359 void SCTPHandler::onSendGreeting(uint16_t srcPort, size_t index) {
360     static constexpr uint8_t DATA = 0;
361     // static constexpr uint8_t PPID_WEBRTC_CONTROL = 0x32;
362     static constexpr uint8_t PPID_WEBRTC_STRING  = 0x33;
363 
364     std::string message;
365     if (index == 0) {
366         message = "Howdy! How's y'all doin?";
367     } else {
368         message = "But wait... There's more!";
369     }
370 
371     size_t pad = message.size() % 4;
372     if (pad) {
373         pad = 4 - pad;
374     }
375 
376     std::vector<uint8_t> outVec(12 + 16 + message.size() + pad);
377 
378     uint8_t *out = outVec.data();
379     SET_U16(&out[0], 5000);
380     SET_U16(&out[2], srcPort);
381     SET_U32(&out[4], mInitiateTag);
382     SET_U32(&out[8], 0x00000000);  // Checksum: to be filled in below.
383 
384     size_t offset = 12;
385     out[offset++] = DATA;
386     out[offset++] = 0x03;  // both Beginning and End of user message.
387 
388     SET_U16(&out[offset], outVec.size() - 12 - pad);
389     offset += 2;
390 
391     SET_U32(&out[offset], mSendingTSN);  // TSN
392     offset += 4;
393 
394     ++mSendingTSN;
395 
396     SET_U16(&out[offset], 0);  // Stream Identifier
397     offset += 2;
398 
399     SET_U16(&out[offset], index);  // Stream Sequence Number
400     offset += 2;
401 
402     SET_U32(&out[offset], PPID_WEBRTC_STRING);  // Payload Protocol Identifier
403     offset += 4;
404 
405     // https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-08#section-5.1
406     // https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-11#section-6.5
407 
408     // DATA(payload protocol=0x32 (50, WebRTC Control), sequence 0)
409     // 03 00 00 00 00 00 00 00  ........
410     // 00 0c 00 00 64 61 74 61  ....data
411     // 2d 63 68 61 6e 6e 65 6c  -channel
412 
413     // DATA(payload protocol=0x33 (51, WebRTC String), sequence 1)
414     // "Hello, world!"
415 
416     memcpy(&out[offset], message.data(), message.size());
417     offset += message.size();
418 
419     memset(&out[offset], 0x00, pad);
420     offset += pad;
421 
422     CHECK_EQ(offset, outVec.size());
423 
424     SET_U32(&out[8], crc32c(out, outVec.size()));
425 
426     LOG(INFO) << "Sending SCTP DATA:";
427     hexdump(out, outVec.size());
428 
429     mDTLS->writeApplicationData(out, outVec.size());
430 
431     if (index == 0) {
432         mRunLoop->postWithDelay(
433                 std::chrono::seconds(3),
434                 makeSafeCallback(
435                     this,
436                     &SCTPHandler::onSendGreeting,
437                     srcPort,
438                     (size_t)1 /* index */));
439     }
440 }
441 
442 static const uint32_t crc_c[256] = {
443     0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
444     0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
445     0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
446     0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
447     0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
448     0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
449     0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
450     0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
451     0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
452     0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
453     0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
454     0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
455     0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
456     0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
457     0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
458     0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
459     0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
460     0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
461     0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
462     0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
463     0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
464     0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
465     0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
466     0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
467     0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
468     0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
469     0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
470     0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
471     0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
472     0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
473     0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
474     0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
475     0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
476     0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
477     0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
478     0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
479     0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
480     0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
481     0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
482     0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
483     0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
484     0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
485     0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
486     0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
487     0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
488     0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
489     0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
490     0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
491     0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
492     0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
493     0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
494     0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
495     0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
496     0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
497     0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
498     0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
499     0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
500     0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
501     0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
502     0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
503     0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
504     0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
505     0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
506     0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
507 };
508 
509 #define CRC32C_POLY 0x1EDC6F41
510 #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
511 
swap32(uint32_t x)512 static uint32_t swap32(uint32_t x) {
513     return (x >> 24)
514         | (((x >> 16) & 0xff) << 8)
515         | (((x >> 8) & 0xff) << 16)
516         | ((x & 0xff) << 24);
517 }
518 
519 // static
crc32c(const uint8_t * data,size_t size)520 uint32_t SCTPHandler::crc32c(const uint8_t *data, size_t size) {
521     uint32_t crc32 = ~(uint32_t)0;
522 
523     for (size_t i = 0; i < size; ++i) {
524         CRC32C(crc32, data[i]);
525     }
526 
527     return ~swap32(crc32);
528 }
529 
530