Skip to content

Commit

Permalink
fix(stun-types): remove MessageId & remove padding "fix"
Browse files Browse the repository at this point in the history
  • Loading branch information
kbalt committed Jan 17, 2025
1 parent 0eaa257 commit d9568a0
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 84 deletions.
4 changes: 2 additions & 2 deletions crates/stun-types/src/attributes/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ impl Attribute<'_> for XorMappedAddress {
const TYPE: u16 = 0x0020;

fn decode(_: Self::Context, msg: &mut Message, attr: AttrSpan) -> Result<Self, Error> {
let xor128 = msg.id().0;
let xor128 = msg.id();
decode_addr(attr.get_value(msg.buffer()), XOR16, COOKIE, xor128).map(Self)
}

fn encode(&self, _: Self::Context, builder: &mut MessageBuilder) -> Result<(), Error> {
let xor128 = builder.id().0;
let xor128 = builder.id();
encode_addr(self.0, builder.buffer(), XOR16, COOKIE, xor128);
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion crates/stun-types/src/attributes/error_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ mod test {
#[test]
fn error_code() {
let mut builder =
MessageBuilder::new(Class::Error, Method::Binding, TransactionId::new(128));
MessageBuilder::new(Class::Error, Method::Binding, TransactionId::new([0; 12]));
builder
.add_attr(&ErrorCode {
number: 400,
Expand Down
4 changes: 2 additions & 2 deletions crates/stun-types/src/attributes/integrity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ mod test {
let password = "abc123";

let mut message =
MessageBuilder::new(Class::Request, Method::Binding, TransactionId::new(123));
MessageBuilder::new(Class::Request, Method::Binding, TransactionId::new([0; 12]));

message.add_attr(&Software::new("ezk-stun")).unwrap();
message
Expand All @@ -196,7 +196,7 @@ mod test {
let password = "abc123";

let mut message =
MessageBuilder::new(Class::Request, Method::Binding, TransactionId::new(123));
MessageBuilder::new(Class::Request, Method::Binding, TransactionId::new([0; 12]));

message.add_attr(&Software::new("ezk-stun")).unwrap();
message
Expand Down
31 changes: 19 additions & 12 deletions crates/stun-types/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::attributes::Attribute;
use crate::header::{Class, MessageHead, MessageId, Method};
use crate::{padding_u16, padding_usize, Error, TransactionId};
use crate::header::{Class, MessageHead, Method, STUN_HEADER_LENGTH};
use crate::{padding_u16, padding_usize, Error, TransactionId, COOKIE};
use bytes::BufMut;

/// Builder for a STUN message
pub struct MessageBuilder {
head: MessageHead,
id: MessageId,
transaction_id: TransactionId,

padding_in_value_len: bool,

Expand All @@ -26,14 +26,13 @@ impl MessageBuilder {
head.set_typ(typ);
buffer.put_u32(head.0);

let mut id = MessageId::new();
id.set_transaction_id(transaction_id.0);
buffer.put_u128(id.0);
buffer.put_u32(COOKIE);
buffer.put_slice(&transaction_id.0);

Self {
head,
transaction_id,
padding_in_value_len: true,
id,
buffer,
}
}
Expand All @@ -42,10 +41,6 @@ impl MessageBuilder {
self.padding_in_value_len = b;
}

pub fn id(&self) -> &MessageId {
&self.id
}

/// Set the length of the message
pub fn set_len(&mut self, len: u16) {
self.head.set_len(len);
Expand Down Expand Up @@ -90,8 +85,20 @@ impl MessageBuilder {
Ok(())
}

pub fn id(&self) -> u128 {
let cookie = COOKIE.to_be_bytes();
let tsx = self.transaction_id.0;

let mut id = [0u8; 16];

id[..4].copy_from_slice(&cookie);
id[4..].copy_from_slice(&tsx);

u128::from_be_bytes(id)
}

pub fn finish(mut self) -> Vec<u8> {
self.set_len((self.buffer.len() - 20).try_into().unwrap());
self.set_len((self.buffer.len() - STUN_HEADER_LENGTH).try_into().unwrap());
self.buffer
}

Expand Down
22 changes: 1 addition & 21 deletions crates/stun-types/src/header.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Error, COOKIE};
use crate::Error;
use bitfield::bitfield;
use std::convert::TryFrom;

Expand All @@ -18,26 +18,6 @@ bitfield! {
pub len, set_len: 15, 0;
}

bitfield! {
/// Internal bitfield representing the cookie + transaction id
#[derive(Debug, Clone, Copy)]
pub struct MessageId(u128);

u32;
pub cookie, set_cookie: 127, 96;

u128;
pub transaction_id, set_transaction_id: 95, 0;
}

impl MessageId {
pub(crate) fn new() -> Self {
let mut new = Self(0);
new.set_cookie(COOKIE);
new
}
}

/// STUN class
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum Class {
Expand Down
26 changes: 6 additions & 20 deletions crates/stun-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![warn(unreachable_pub)]

use byteorder::ReadBytesExt;
use rand::Rng;
use std::io::{self, Cursor};
use std::num::TryFromIntError;
use std::str::Utf8Error;
Expand All @@ -12,7 +11,7 @@ mod header;
mod parse;

pub use builder::MessageBuilder;
pub use header::{Class, MessageHead, MessageId, Method};
pub use header::{Class, MessageHead, Method};
pub use parse::{AttrSpan, Message};

type NE = byteorder::NetworkEndian;
Expand Down Expand Up @@ -60,29 +59,17 @@ fn padding_usize(n: usize) -> usize {

/// 96 bit STUN transaction id
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TransactionId(u128);
pub struct TransactionId([u8; 12]);

impl TransactionId {
const MAX: u128 = (1 << 96) - 1;

/// Returns the inner numeric representation of the transaction id
pub fn as_u128(self) -> u128 {
self.0
}

/// Create a new transaction id from the given value
///
/// # Panics
///
/// Panics if the given value is larger than 96 bits
pub fn new(v: u128) -> Self {
assert!(v <= Self::MAX);
pub fn new(v: [u8; 12]) -> Self {
Self(v)
}

/// Generate a new random transaction id
pub fn random() -> Self {
Self(rand::thread_rng().gen_range(0..=Self::MAX))
Self(rand::random())
}
}

Expand Down Expand Up @@ -123,10 +110,9 @@ pub fn is_stun_message(i: &[u8]) -> IsStunMessageInfo {
return IsStunMessageInfo::No;
}

let id = cursor.read_u128::<NE>().unwrap();
let id = MessageId(id);
let cookie = cursor.read_u32::<NE>().unwrap();

if id.cookie() != COOKIE {
if cookie != COOKIE {
return IsStunMessageInfo::No;
}

Expand Down
44 changes: 18 additions & 26 deletions crates/stun-types/src/parse.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::attributes::{Attribute, Fingerprint, MessageIntegrity, MessageIntegritySha256};
use crate::header::{Class, MessageHead, MessageId, Method};
use crate::header::{Class, MessageHead, Method};
use crate::{padding_usize, Error, TransactionId, COOKIE, NE};
use byteorder::ReadBytesExt;
use bytes::Buf;
use std::convert::TryFrom;
use std::io::Cursor;
use std::io::{Cursor, Read};

#[derive(Debug, Clone, Copy)]
pub struct AttrSpan {
Expand All @@ -31,7 +31,7 @@ pub struct Message {
buffer: Vec<u8>,

head: MessageHead,
id: MessageId,
id: u128,

class: Class,
method: Method,
Expand All @@ -53,6 +53,10 @@ impl Message {
self.transaction_id
}

pub(crate) fn id(&self) -> u128 {
self.id
}

pub fn parse(buffer: impl Into<Vec<u8>>) -> Result<Message, Error> {
let mut cursor = Cursor::new(buffer.into());

Expand All @@ -64,9 +68,16 @@ impl Message {
}

let id = cursor.read_u128::<NE>()?;
let id = MessageId(id);

if id.cookie() != COOKIE {
let (cookie, transaction_id) = {
let mut cursor = Cursor::new(id.to_be_bytes());
let cookie = cursor.read_u32::<NE>()?;
let mut transaction_id = [0u8; 12];
cursor.read_exact(&mut transaction_id)?;
(cookie, transaction_id)
};

if cookie != COOKIE {
return Err(Error::InvalidData("not a stun message"));
}

Expand All @@ -81,7 +92,7 @@ impl Message {
let padding = padding_usize(attr_len);

let value_begin = usize::try_from(cursor.position())?;
let mut value_end = value_begin + attr_len;
let value_end = value_begin + attr_len;
let padding_end = value_end + padding;

if padding_end > cursor.get_ref().len() {
Expand All @@ -90,20 +101,6 @@ impl Message {
));
}

// https://datatracker.ietf.org/doc/html/rfc8489#section-14
// explicitly states that the length field must contain the
// value length __prior__ to padding. Some stun agents have
// the padding included in the length anyway. This double
// checks and removes all bytes from the end of the value.
if padding == 0 {
let value = &cursor.get_ref()[value_begin..value_end];

// count all zero bytes at the end of the value
let counted_padding = value.iter().rev().take_while(|&&b| b == 0).count();

value_end -= counted_padding;
}

let attr = AttrSpan {
begin: value_begin,
end: value_end,
Expand All @@ -122,7 +119,7 @@ impl Message {
id,
class,
method,
transaction_id: TransactionId(id.transaction_id()),
transaction_id: TransactionId(transaction_id),
attributes,
})
}
Expand Down Expand Up @@ -201,9 +198,4 @@ impl Message {
pub fn head(&self) -> &MessageHead {
&self.head
}

/// ID of the STUN message (cookie + transaction)
pub fn id(&self) -> &MessageId {
&self.id
}
}

0 comments on commit d9568a0

Please sign in to comment.