faster_stun/
message.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
107
108
109
110
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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
use bytes::{BufMut, BytesMut};

use std::convert::TryFrom;

use crate::StunError;

use super::attribute::{AttrKind, MessageIntegrity, Property};
use super::{util, Method};

const ZOER_BUF: [u8; 10] = [0u8; 10];
const COOKIE: [u8; 4] = 0x2112A442u32.to_be_bytes();

/// (username, password, realm)
type Auth = [u8; 16];

pub struct MessageWriter<'a> {
    token: &'a [u8],
    raw: &'a mut BytesMut,
}

impl<'a, 'b> MessageWriter<'a> {
    pub fn new(method: Method, token: &'a [u8; 12], buf: &'a mut BytesMut) -> Self {
        unsafe { buf.set_len(0) }
        buf.put_u16(method.into());
        buf.put_u16(0);
        buf.put(&COOKIE[..]);
        buf.put(token.as_slice());
        Self { raw: buf, token }
    }

    /// rely on old message to create new message.
    ///
    /// # Unit Test
    ///
    /// ```
    /// use bytes::BytesMut;
    /// use faster_stun::*;
    /// use std::convert::TryFrom;
    ///
    /// let buffer = [
    ///     0x00u8, 0x01, 0x00, 0x00, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49,
    ///     0x42, 0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b,
    /// ];
    ///
    /// let mut attributes = Vec::new();
    /// let mut buf = BytesMut::new();
    /// let old = MessageReader::decode(&buffer[..], &mut attributes).unwrap();
    /// MessageWriter::extend(Method::Binding(Kind::Request), &old, &mut buf);
    /// assert_eq!(&buf[..], &buffer[..]);
    /// ```
    pub fn extend(method: Method, reader: &MessageReader<'a, 'b>, buf: &'a mut BytesMut) -> Self {
        unsafe { buf.set_len(0) }
        buf.put_u16(method.into());
        buf.put_u16(0);
        buf.put(&COOKIE[..]);
        buf.put(reader.token);
        Self {
            raw: buf,
            token: reader.token,
        }
    }

    /// append attribute.
    ///
    /// append attribute to message attribute list.
    ///
    /// # Unit Test
    ///
    /// ```
    /// use bytes::BytesMut;
    /// use faster_stun::attribute::UserName;
    /// use faster_stun::*;
    /// use std::convert::TryFrom;
    ///
    /// let buffer = [
    ///     0x00u8, 0x01, 0x00, 0x00, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49,
    ///     0x42, 0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b,
    /// ];
    ///
    /// let new_buf = [
    ///     0x00u8, 0x01, 0x00, 0x00, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49,
    ///     0x42, 0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b, 0x00, 0x06, 0x00,
    ///     0x05, 0x70, 0x61, 0x6e, 0x64, 0x61, 0x00, 0x00, 0x00,
    /// ];
    ///
    /// let mut buf = BytesMut::new();
    /// let mut attributes = Vec::new();
    /// let old = MessageReader::decode(&buffer[..], &mut attributes).unwrap();
    /// let mut message =
    ///     MessageWriter::extend(Method::Binding(Kind::Request), &old, &mut buf);
    /// message.append::<UserName>("panda");
    /// assert_eq!(&new_buf[..], &buf[..]);
    /// ```
    pub fn append<T: Property<'a>>(&mut self, value: T::Inner) {
        self.raw.put_u16(T::kind() as u16);

        // record the current position,
        // and then advance the internal cursor 2 bytes,
        // here is to reserve the position.
        let os = self.raw.len();
        unsafe { self.raw.advance_mut(2) }
        T::into(value, self.raw, self.token);

        // compute write index,
        // back to source index write size.
        let size = self.raw.len() - os - 2;
        let size_buf = (size as u16).to_be_bytes();
        self.raw[os] = size_buf[0];
        self.raw[os + 1] = size_buf[1];

        // if you need to padding,
        // padding in the zero bytes.
        let psize = util::pad_size(size);
        if psize > 0 {
            self.raw.put(&ZOER_BUF[0..psize]);
        }
    }

    /// try decoder bytes as message.
    ///
    /// # Unit Test
    ///
    /// ```
    /// use bytes::BytesMut;
    /// use faster_stun::*;
    /// use std::convert::TryFrom;
    ///
    /// let buffer = [
    ///     0x00u8, 0x01, 0x00, 0x00, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49,
    ///     0x42, 0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b,
    /// ];
    ///
    /// let result = [
    ///     0x00u8, 0x01, 0x00, 0x20, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49,
    ///     0x42, 0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b, 0x00, 0x08, 0x00,
    ///     0x14, 0x45, 0x0e, 0x6e, 0x44, 0x52, 0x1e, 0xe8, 0xde, 0x2c, 0xf0, 0xfa,
    ///     0xb6, 0x9c, 0x5c, 0x19, 0x17, 0x98, 0xc6, 0xd9, 0xde, 0x80, 0x28, 0x00,
    ///     0x04, 0xed, 0x41, 0xb6, 0xbe,
    /// ];
    ///
    /// let mut attributes = Vec::new();
    /// let mut buf = BytesMut::with_capacity(1280);
    /// let old = MessageReader::decode(&buffer[..], &mut attributes).unwrap();
    /// let mut message =
    ///     MessageWriter::extend(Method::Binding(Kind::Request), &old, &mut buf);
    /// message
    ///     .flush(Some(&util::long_key("panda", "panda", "raspberry")))
    ///     .unwrap();
    /// assert_eq!(&buf[..], &result);
    /// ```
    pub fn flush(&mut self, auth: Option<&Auth>) -> Result<(), StunError> {
        // write attribute list size.
        let size = (self.raw.len() - 20) as u16;
        let size_buf = size.to_be_bytes();
        self.raw[2] = size_buf[0];
        self.raw[3] = size_buf[1];

        // if need message integrity?
        if let Some(a) = auth {
            self.integrity(a)?;
        }

        Ok(())
    }

    /// append MessageIntegrity attribute.
    ///
    /// add the `MessageIntegrity` attribute to the faster_stun message
    /// and serialize the message into a buffer.
    ///
    /// # Unit Test
    ///
    /// ```
    /// use bytes::BytesMut;
    /// use faster_stun::*;
    /// use std::convert::TryFrom;
    ///
    /// let buffer = [
    ///     0x00u8, 0x01, 0x00, 0x00, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49,
    ///     0x42, 0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b,
    /// ];
    ///
    /// let result = [
    ///     0x00u8, 0x01, 0x00, 0x20, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49,
    ///     0x42, 0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b, 0x00, 0x08, 0x00,
    ///     0x14, 0x45, 0x0e, 0x6e, 0x44, 0x52, 0x1e, 0xe8, 0xde, 0x2c, 0xf0, 0xfa,
    ///     0xb6, 0x9c, 0x5c, 0x19, 0x17, 0x98, 0xc6, 0xd9, 0xde, 0x80, 0x28, 0x00,
    ///     0x04, 0xed, 0x41, 0xb6, 0xbe,
    /// ];
    ///
    /// let mut attributes = Vec::new();
    /// let mut buf = BytesMut::from(&buffer[..]);
    /// let old = MessageReader::decode(&buffer[..], &mut attributes).unwrap();
    /// let mut message =
    ///     MessageWriter::extend(Method::Binding(Kind::Request), &old, &mut buf);
    /// message
    ///     .flush(Some(&util::long_key("panda", "panda", "raspberry")))
    ///     .unwrap();
    /// assert_eq!(&buf[..], &result);
    /// ```
    fn integrity(&mut self, auth: &Auth) -> Result<(), StunError> {
        assert!(self.raw.len() >= 20);

        // compute new size,
        // new size include the MessageIntegrity attribute size.
        let mut buf_size = (self.raw.len() + 4) as u16;
        let size_buf = buf_size.to_be_bytes();

        // overwrite old size with new size.
        self.raw[2] = size_buf[0];
        self.raw[3] = size_buf[1];

        // long key,
        // digest the message buffer,
        // create the new MessageIntegrity attribute.
        let hmac_output = util::hmac_sha1(auth, vec![self.raw])?.into_bytes();
        let property_buf = hmac_output.as_slice();

        // write MessageIntegrity attribute.
        self.raw.put_u16(AttrKind::MessageIntegrity as u16);
        self.raw.put_u16(20);
        self.raw.put(property_buf);

        // compute new size,
        // new size include the Fingerprint attribute size.
        buf_size += 8;
        let size_buf = buf_size.to_be_bytes();

        // overwrite old size with new size.
        self.raw[2] = size_buf[0];
        self.raw[3] = size_buf[1];

        // CRC Fingerprint
        self.raw.put_u16(AttrKind::Fingerprint as u16);
        self.raw.put_u16(4);
        self.raw.put_u32(util::fingerprint(self.raw));

        Ok(())
    }
}

#[derive(Debug)]
pub struct MessageReader<'a, 'b> {
    /// message type.
    pub method: Method,
    /// message transaction id.
    pub token: &'a [u8],
    /// message source bytes.
    buf: &'a [u8],
    /// message valid block bytes size.
    valid_offset: u16,
    // message attribute list.
    attributes: &'b Vec<(AttrKind, &'a [u8])>,
}

impl<'a, 'b> MessageReader<'a, 'b> {
    /// get attribute.
    ///
    /// get attribute from message attribute list.
    ///
    /// # Unit Test
    ///
    /// ```
    /// use faster_stun::attribute::*;
    /// use faster_stun::*;
    /// use std::convert::TryFrom;
    ///
    /// let buffer = [
    ///     0x00u8, 0x01, 0x00, 0x00, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49,
    ///     0x42, 0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b,
    /// ];
    ///
    /// let mut attributes = Vec::new();
    /// let message = MessageReader::decode(&buffer[..], &mut attributes).unwrap();
    /// assert!(message.get::<UserName>().is_none());
    /// ```
    pub fn get<T: Property<'a>>(&self) -> Option<T::Inner> {
        let kind = T::kind();
        self.attributes
            .iter()
            .find(|(k, _)| k == &kind)
            .and_then(|(_, v)| T::try_from(v, self.token).ok())
    }

    /// check MessageReaderIntegrity attribute.
    ///
    /// return whether the `MessageReaderIntegrity` attribute
    /// contained in the message can pass the check.
    ///
    /// # Unit Test
    ///
    /// ```
    /// use faster_stun::*;
    /// use std::convert::TryFrom;
    ///
    /// let buffer = [
    ///     0x00u8, 0x03, 0x00, 0x50, 0x21, 0x12, 0xa4, 0x42, 0x64, 0x4f, 0x5a,
    ///     0x78, 0x6a, 0x56, 0x33, 0x62, 0x4b, 0x52, 0x33, 0x31, 0x00, 0x19, 0x00,
    ///     0x04, 0x11, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x70, 0x61, 0x6e,
    ///     0x64, 0x61, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x09, 0x72, 0x61, 0x73,
    ///     0x70, 0x62, 0x65, 0x72, 0x72, 0x79, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00,
    ///     0x10, 0x31, 0x63, 0x31, 0x33, 0x64, 0x32, 0x62, 0x32, 0x34, 0x35, 0x62,
    ///     0x33, 0x61, 0x37, 0x33, 0x34, 0x00, 0x08, 0x00, 0x14, 0xd6, 0x78, 0x26,
    ///     0x99, 0x0e, 0x15, 0x56, 0x15, 0xe5, 0xf4, 0x24, 0x74, 0xe2, 0x3c, 0x26,
    ///     0xc5, 0xb1, 0x03, 0xb2, 0x6d,
    /// ];
    ///
    /// let mut attributes = Vec::new();
    /// let message = MessageReader::decode(&buffer[..], &mut attributes).unwrap();
    /// let result = message
    ///     .integrity(&util::long_key("panda", "panda", "raspberry"))
    ///     .is_ok();
    /// assert!(result);
    /// ```
    pub fn integrity(&self, auth: &Auth) -> Result<(), StunError> {
        if self.buf.is_empty() || !(self.valid_offset >= 20) {
            return Err(StunError::InvalidInput);
        }

        // unwrap MessageIntegrity attribute,
        // an error occurs if not found.
        let integrity = self
            .get::<MessageIntegrity>()
            .ok_or_else(|| StunError::NotIntegrity)?;

        // create multiple submit.
        let size_buf = (self.valid_offset + 4).to_be_bytes();
        let body = vec![
            &self.buf[0..2],
            &size_buf,
            &self.buf[4..self.valid_offset as usize],
        ];

        // digest the message buffer.
        let hmac_output = util::hmac_sha1(auth, body)?.into_bytes();
        let property_buf = hmac_output.as_slice();

        // Compare local and original attribute.
        if integrity != property_buf {
            return Err(StunError::IntegrityFailed);
        }

        Ok(())
    }

    /// # Unit Test
    ///
    /// ```
    /// use faster_stun::attribute::*;
    /// use faster_stun::*;
    /// use std::convert::TryFrom;
    ///
    /// let buffer: [u8; 20] = [
    ///     0x00, 0x01, 0x00, 0x00, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49, 0x42,
    ///     0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b,
    /// ];
    ///
    /// let mut attributes = Vec::new();
    /// let message = MessageReader::decode(&buffer[..], &mut attributes).unwrap();
    /// assert_eq!(message.method, Method::Binding(Kind::Request));
    /// assert!(message.get::<UserName>().is_none());
    /// ```
    #[rustfmt::skip]
    pub fn decode(
        buf: &'a [u8],
        attributes: &'b mut Vec<(AttrKind, &'a [u8])>,
    ) -> Result<MessageReader<'a, 'b>, StunError> {
        if !(buf.len() >= 20) {
            return Err(StunError::InvalidInput)
        }

        let mut find_integrity = false;
        let mut valid_offset = 0;
        let count_size = buf.len();

        // message type
        // message size
        // check fixed magic cookie
        // check if the message size is overflow
        let method = Method::try_from(util::as_u16(&buf[..2]))?;
        let size = util::as_u16(&buf[2..4]) as usize + 20;
        if !(buf[4..8] == COOKIE[..]) {
            return Err(StunError::NotCookie)
        }

        if !(count_size >= size) {
            return Err(StunError::InvalidInput)
        }

        // get transaction id
        let token = &buf[8..20];
        let mut offset = 20;

    // warn: loop
    loop {
        // if the buf length is not long enough to continue,
        // jump out of the loop.
        if count_size - offset < 4 {
            break;
        }

        // get attribute type
        let key = u16::from_be_bytes([buf[offset], buf[offset + 1]]);

        // whether the MessageIntegrity attribute has been found,
        // if found, record the current offset position.
        if !find_integrity {
            valid_offset = offset as u16;
        }

        // check whether the current attribute is MessageIntegrity,
        // if it is, mark this attribute has been found.
        if key == AttrKind::MessageIntegrity as u16 {
            find_integrity = true;
        }

        // get attribute size
        let size =
            u16::from_be_bytes([buf[offset + 2], buf[offset + 3]]) as usize;

        // check if the attribute length has overflowed.
        offset += 4;
        if count_size - offset < size {
            break;
        }

        // body range.
        let range = offset..(offset + size);

        // if there are padding bytes,
        // skip padding size.
        if size > 0 {
            offset += size;
            offset += util::pad_size(size);
        }

        // skip the attributes that are not supported.
        let attrkind = match AttrKind::try_from(key) {
            Err(_) => continue,
            Ok(a) => a,
        };

        // get attribute body
        // insert attribute to attributes list.
        attributes.push((attrkind, &buf[range]));
    }

        Ok(Self {
            buf,
            token,
            method,
            attributes,
            valid_offset,
        })
    }

    /// # Unit Test
    ///
    /// ```
    /// use faster_stun::*;
    ///
    /// let buffer: [u8; 20] = [
    ///     0x00, 0x01, 0x00, 0x00, 0x21, 0x12, 0xa4, 0x42, 0x72, 0x6d, 0x49, 0x42,
    ///     0x72, 0x52, 0x64, 0x48, 0x57, 0x62, 0x4b, 0x2b,
    /// ];
    ///
    /// let size = MessageReader::message_size(&buffer[..]).unwrap();
    /// assert_eq!(size, 20);
    /// ```
    pub fn message_size(buf: &[u8]) -> Result<usize, StunError> {
        if !(buf[0] >> 6 == 0) || !(buf.len() >= 20) {
            return Err(StunError::InvalidInput);
        }

        Ok((util::as_u16(&buf[2..4]) + 20) as usize)
    }
}

impl<'a> AsRef<[u8]> for MessageReader<'a, '_> {
    fn as_ref(&self) -> &'a [u8] {
        self.buf
    }
}

impl<'a> std::ops::Deref for MessageReader<'a, '_> {
    type Target = [u8];

    fn deref(&self) -> &'a Self::Target {
        self.buf
    }
}