467
474
StunMessageReturn
468
475
stun_message_append_xor_addr (StunMessage *msg, StunAttribute type,
469
const struct sockaddr *addr, socklen_t addrlen)
476
const struct sockaddr_storage *addr, socklen_t addrlen)
471
478
StunMessageReturn val;
472
479
/* Must be big enough to hold any supported address: */
473
struct sockaddr_storage xor;
475
if ((size_t) addrlen > sizeof (xor))
476
addrlen = sizeof (xor);
477
memcpy (&xor, addr, addrlen);
479
val = stun_xor_address (msg, (struct sockaddr *)&xor, addrlen,
480
struct sockaddr_storage tmpaddr;
482
if ((size_t) addrlen > sizeof (tmpaddr))
483
addrlen = sizeof (tmpaddr);
484
memcpy (&tmpaddr, addr, addrlen);
486
val = stun_xor_address (msg, &tmpaddr, addrlen,
480
487
STUN_MAGIC_COOKIE);
484
return stun_message_append_addr (msg, type, (struct sockaddr *)&xor,
491
return stun_message_append_addr (msg, type, (struct sockaddr *) &tmpaddr,
488
495
StunMessageReturn
489
496
stun_message_append_xor_addr_full (StunMessage *msg, StunAttribute type,
490
const struct sockaddr *addr, socklen_t addrlen,
497
const struct sockaddr_storage *addr, socklen_t addrlen,
491
498
uint32_t magic_cookie)
493
500
StunMessageReturn val;
494
501
/* Must be big enough to hold any supported address: */
495
struct sockaddr_storage xor;
497
if ((size_t) addrlen > sizeof (xor))
498
addrlen = sizeof (xor);
499
memcpy (&xor, addr, addrlen);
501
val = stun_xor_address (msg, (struct sockaddr *)&xor, addrlen, magic_cookie);
502
struct sockaddr_storage tmpaddr;
504
if ((size_t) addrlen > sizeof (tmpaddr))
505
addrlen = sizeof (tmpaddr);
506
memcpy (&tmpaddr, addr, addrlen);
508
val = stun_xor_address (msg, &tmpaddr, addrlen, magic_cookie);
505
return stun_message_append_addr (msg, type, (struct sockaddr *)&xor,
512
return stun_message_append_addr (msg, type, (struct sockaddr *) &tmpaddr,
514
521
const char *str = stun_strerror (code);
515
522
size_t len = strlen (str);
516
div_t d = div (code, 100);
518
524
uint8_t *ptr = stun_message_append (msg, STUN_ATTRIBUTE_ERROR_CODE, 4 + len);
520
526
return STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE;
522
528
memset (ptr, 0, 2);
525
531
memcpy (ptr + 4, str, len);
526
532
return STUN_MESSAGE_RETURN_SUCCESS;
529
int stun_message_validate_buffer_length (const uint8_t *msg, size_t length,
535
/* Fast validity check for a potential STUN packet. Examines the type and
536
* length, but none of the attributes. Designed to allow vectored I/O on all
537
* incoming packets, filtering packets for closer inspection as to whether
538
* they’re STUN packets. If they look like they might be, their buffers are
539
* compacted to allow a more thorough check. */
540
ssize_t stun_message_validate_buffer_length_fast (StunInputVector *buffers,
541
unsigned int n_buffers, size_t total_length, bool has_padding)
545
if (total_length < 1 || n_buffers < 1)
537
547
stun_debug ("STUN error: No data!\n");
538
548
return STUN_MESSAGE_BUFFER_INVALID;
551
if (buffers[0].buffer[0] >> 6)
543
553
stun_debug ("STUN error: RTP or other non-protocol packet!\n");
544
554
return STUN_MESSAGE_BUFFER_INVALID; // RTP or other non-STUN packet
557
if (total_length < STUN_MESSAGE_LENGTH_POS + STUN_MESSAGE_LENGTH_LEN)
549
559
stun_debug ("STUN error: Incomplete STUN message header!\n");
550
560
return STUN_MESSAGE_BUFFER_INCOMPLETE;
553
mlen = stun_getw (msg + STUN_MESSAGE_LENGTH_POS) +
554
STUN_MESSAGE_HEADER_LENGTH;
556
if (has_padding && stun_padding (mlen))
563
if (buffers[0].size >= STUN_MESSAGE_LENGTH_POS + STUN_MESSAGE_LENGTH_LEN) {
565
mlen = stun_getw (buffers[0].buffer + STUN_MESSAGE_LENGTH_POS);
567
/* Slow path. Tiny buffers abound. */
568
size_t skip_remaining = STUN_MESSAGE_LENGTH_POS;
572
for (i = 0; i < n_buffers; i++) {
573
if (buffers[i].size <= skip_remaining)
574
skip_remaining -= buffers[i].size;
579
/* Read bytes. May be split over two buffers. We’ve already checked that
580
* @total_length is long enough, so @n_buffers should be too. */
581
if (buffers[i].size - skip_remaining > 1) {
582
mlen = stun_getw (buffers[i].buffer + skip_remaining);
584
mlen = (*(buffers[i].buffer + skip_remaining) << 8) |
585
(*(buffers[i + 1].buffer));
589
mlen += STUN_MESSAGE_HEADER_LENGTH;
591
if (has_padding && stun_padding (mlen)) {
558
592
stun_debug ("STUN error: Invalid message length: %u!\n", (unsigned)mlen);
559
593
return STUN_MESSAGE_BUFFER_INVALID; // wrong padding
596
if (total_length < mlen) {
564
597
stun_debug ("STUN error: Incomplete message: %u of %u bytes!\n",
565
(unsigned)length, (unsigned)mlen);
598
(unsigned) total_length, (unsigned) mlen);
566
599
return STUN_MESSAGE_BUFFER_INCOMPLETE; // partial message
605
int stun_message_validate_buffer_length (const uint8_t *msg, size_t length,
611
StunInputVector input_buffer = { msg, length };
613
/* Fast pre-check first. */
614
fast_retval = stun_message_validate_buffer_length_fast (&input_buffer, 1,
615
length, has_padding);
616
if (fast_retval <= 0)
621
/* Skip past the header (validated above). */
572
625
/* from then on, we know we have the entire packet in buffer */
575
size_t alen = stun_getw (msg + STUN_ATTRIBUTE_TYPE_LEN);
632
stun_debug ("STUN error: Incomplete STUN attribute header of length "
633
"%u bytes!\n", (unsigned)len);
634
return STUN_MESSAGE_BUFFER_INVALID;
637
alen = stun_getw (msg + STUN_ATTRIBUTE_TYPE_LEN);
577
639
alen = stun_align (alen);