Added RFC5389

This commit is contained in:
pradt2
2022-08-23 19:53:55 +01:00
parent 2c38439744
commit 245c63e104
6 changed files with 1040 additions and 24 deletions

View File

@@ -68,18 +68,18 @@ Legend:
| Type | Reader | Writer |
|:-------------------------|:-------:|:-------:|
| `Binding Request` | ✗ | ✗ |
| `Binding Response` | ✗ | ✗ |
| `Binding Error Response` | ✗ | ✗ |
| `Binding Indication` | ✗ | ✗ |
| `Binding Request` | ✓ | ✓ |
| `Binding Response` | ✓ | ✓ |
| `Binding Error Response` | ✓ | ✓ |
| `Binding Indication` | ✓ | ✓ |
### Header features
| Feature | Reader | Writer |
|:---------------|:-------:|:-------:|
| Message length | ✗ | ✗ |
| Magic cookie | ✗ | ✗ |
| Transaction ID | ✗ | ✗ |
| Message length | ✓ | ✓ |
| Magic cookie | ✓ | ✓ |
| Transaction ID | ✓ | ✓ |
### Attributes
@@ -89,13 +89,13 @@ Legend:
| `XOR-MAPPED-ADDRESS` | ✗ | ✗ |
| `USERNAME` | ✗ | ✗ |
| `MESSAGE-INTEGRITY` | ✗ | ✗ |
| `FINGERPRINT` | ✗ | ✗ |
| `ERROR-CODE` | ✗ | ✗ |
| `REALM` | ✗ | ✗ |
| `NONCE` | ✗ | ✗ |
| `UNKNOWN-ATTRIBUTES` | ✗ | ✗ |
| `SOFTWARE` | ✗ | ✗ |
| `ALTERNATE-SERVER` | ✗ | ✗ |
| `FINGERPRINT` | ✗ | ✗ |
### Error codes

View File

@@ -102,13 +102,15 @@ impl<'a> SocketAddrWriter<'a> {
pub struct XorSocketAddrReader<'a> {
socket_addr_reader: SocketAddrReader<'a>,
magic_cookie: u32,
transaction_id: u128,
}
impl<'a> XorSocketAddrReader<'a> {
pub fn new(bytes: &'a [u8], transaction_id: u128) -> Self {
pub fn new(bytes: &'a [u8], magic_cookie: u32, transaction_id: u128) -> Self {
Self {
socket_addr_reader: SocketAddrReader::new(bytes),
magic_cookie,
transaction_id,
}
}
@@ -117,11 +119,11 @@ impl<'a> XorSocketAddrReader<'a> {
match self.socket_addr_reader.get_address() {
Err(err) => Err(err),
Ok(SocketAddr::V4(ip, port)) => {
let mask = 0x2112A442;
let mask = self.magic_cookie;
Ok(SocketAddr::V4(ip ^ mask, port))
}
Ok(SocketAddr::V6(ip, port)) => {
let mask = self.transaction_id;
let mask = ((self.magic_cookie as u128) << 96) | self.transaction_id;
Ok(SocketAddr::V6(ip ^ mask, port))
}
}
@@ -139,13 +141,13 @@ impl<'a> XorSocketAddrWriter<'a> {
}
}
pub fn write_ipv4_addr(&mut self, ip: u32, port: u16) -> Option<u16> {
let mask = 0x2112A442;
pub fn write_ipv4_addr(&mut self, ip: u32, port: u16, magic_cookie: u32) -> Option<u16> {
let mask = magic_cookie;
self.writer.write_ipv4_addr(ip ^ mask, port)
}
pub fn write_ipv6_addr(&mut self, ip: u128, port: u16, transaction_id: u128) -> Option<u16> {
let mask = transaction_id;
pub fn write_ipv6_addr(&mut self, ip: u128, port: u16, magic_cookie: u32, transaction_id: u128) -> Option<u16> {
let mask = ((magic_cookie as u128) << 96) | transaction_id;
self.writer.write_ipv6_addr(ip ^ mask, port)
}
}
@@ -632,15 +634,16 @@ mod tests {
let mut attr_buf = [0u8; 8];
let magic_cookie = 0;
let transaction_id = 0xFF;
let r = XorSocketAddrReader::new(&attr_val, transaction_id);
let r = XorSocketAddrReader::new(&attr_val, magic_cookie, transaction_id);
let addr = r.get_address()
.expect("Address is unreadable");
if let SocketAddr::V4(ip, port) = addr {
let mut w = XorSocketAddrWriter::new(&mut attr_buf);
let bytes_written = w.write_ipv4_addr(ip, port)
let bytes_written = w.write_ipv4_addr(ip, port, magic_cookie)
.expect("Buffer is too small");
assert_eq!(8, bytes_written);
@@ -661,15 +664,16 @@ mod tests {
let mut attr_buf = [0u8; 20];
let magic_cookie = 0;
let transaction_id = 0xFF;
let r = XorSocketAddrReader::new(&attr_val, transaction_id);
let r = XorSocketAddrReader::new(&attr_val, magic_cookie, transaction_id);
let addr = r.get_address()
.expect("Address is unreadable");
if let SocketAddr::V6(ip, port) = addr {
let mut w = XorSocketAddrWriter::new(&mut attr_buf);
let bytes_written = w.write_ipv6_addr(ip, port, transaction_id)
let bytes_written = w.write_ipv6_addr(ip, port, magic_cookie, transaction_id)
.expect("Buffer is too small");
assert_eq!(20, bytes_written);

View File

@@ -8,4 +8,5 @@ use base::*;
use attrs::*;
use msg::*;
pub mod rfc3489;
pub mod rfc3489;
pub mod rfc5389;

View File

@@ -21,6 +21,12 @@ impl<'a> RawMsgHeaderReader<'a> {
.map(|b| u16::from_be_bytes(b))
}
pub fn get_magic_cookie(&self) -> Option<u32> {
self.bytes.get(4..8)
.map(|b| b.try_into().unwrap())
.map(|b| u32::from_be_bytes(b))
}
pub fn get_transaction_id(&self) -> Option<u128> {
self.bytes.get(4..20)
.map(|b| b.try_into().unwrap())
@@ -52,6 +58,12 @@ impl<'a> RawMsgHeaderWriter<'a> {
Some(())
}
pub fn set_magic_cookie(&mut self, magic_cookie: u32) -> Option<()> {
let cookie_bytes = magic_cookie.to_be_bytes();
self.bytes.get_mut(4..8)?.copy_from_slice(&cookie_bytes);
Some(())
}
pub fn set_transaction_id(&mut self, tid: u128) -> Option<()> {
let tid_bytes = tid.to_be_bytes();
self.bytes.get_mut(4..20)?.copy_from_slice(&tid_bytes);

View File

@@ -852,7 +852,7 @@ mod tests {
];
#[test]
fn read_message_integrity_addr() {
fn read_message_integrity_attr() {
let mut r = AttributeIterator::new(&MESSAGE_INTEGRITY);
if let Some(Ok(ReaderAttribute::MessageIntegrity(r))) = r.next() {
@@ -869,7 +869,7 @@ mod tests {
}
#[test]
fn write_message_integrity_addr() {
fn write_message_integrity_attr() {
let mut buffer = [0; 44];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::MessageIntegrity(&[0x00, 0x01, 0x02, 0x03,
@@ -905,7 +905,7 @@ mod tests {
}
#[test]
fn write_username_addr() {
fn write_username_attr() {
let mut buffer = [0; 32];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::Username(MOCK_USERNAME)).unwrap();
@@ -937,7 +937,7 @@ mod tests {
}
#[test]
fn write_password_addr() {
fn write_password_attr() {
let mut buffer = [0; 32];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::Password(MOCK_PASSWORD)).unwrap();

999
stun_proto/src/rfc5389.rs Normal file
View File

@@ -0,0 +1,999 @@
use super::*;
pub use super::attrs::{SocketAddr};
pub use super::base::ReaderErr;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum MessageType {
BindingRequest = 0x0001,
BindingIndication = 0x0011,
BindingResponse = 0x0101,
BindingErrorResponse = 0x0111,
}
impl TryFrom<u16> for MessageType {
type Error = ReaderErr;
fn try_from(value: u16) -> core::result::Result<Self, Self::Error> {
match value {
0x0001 => Ok(MessageType::BindingRequest),
0x0011 => Ok(MessageType::BindingIndication),
0x0101 => Ok(MessageType::BindingResponse),
0x0111 => Ok(MessageType::BindingErrorResponse),
_ => Err(ReaderErr::UnexpectedValue)
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum StunError {
TryAlternate = 300,
BadRequest = 400,
Unauthorized = 401,
UnknownAttribute = 420,
StaleNonce = 438,
ServerError = 500,
}
impl TryFrom<u16> for StunError {
type Error = ReaderErr;
fn try_from(value: u16) -> core::result::Result<Self, Self::Error> {
match value {
400 => Ok(StunError::BadRequest),
401 => Ok(StunError::Unauthorized),
420 => Ok(StunError::UnknownAttribute),
438 => Ok(StunError::StaleNonce),
500 => Ok(StunError::ServerError),
_ => Err(ReaderErr::UnexpectedValue),
}
}
}
impl StunError {
pub fn get_name(&self) -> &'static str {
match self {
StunError::TryAlternate => "Try Alternate",
StunError::BadRequest => "Bad Request",
StunError::Unauthorized => "Unauthorized",
StunError::UnknownAttribute => "Unknown Attribute",
StunError::StaleNonce => "Stale Credentials",
StunError::ServerError => "Server Error",
}
}
pub fn get_reason(&self) -> &'static str {
match self {
StunError::TryAlternate => "The client should contact an alternate server for this request.",
StunError::BadRequest => "The request was malformed. The client should not retry the request without modification from the previous attempt.",
StunError::Unauthorized => "The Binding Request did not contain a MESSAGE-INTEGRITY attribute.",
StunError::UnknownAttribute => "The server did not understand a mandatory attribute in the request.",
StunError::StaleNonce => "The NONCE used by the client was no longer valid.",
StunError::ServerError => "The server has suffered a temporary error. The client should try again.",
}
}
}
pub struct Reader<'a> {
header: RawMsgHeaderReader<'a>,
attr_bytes: &'a [u8],
}
impl<'a> Reader<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
let header_bytes = bytes.get(0..20).unwrap_or(bytes);
let attr_bytes = bytes.get(20..).unwrap_or(&bytes[0..0]);
Self {
header: RawMsgHeaderReader::new(header_bytes),
attr_bytes,
}
}
pub fn get_message_type(&self) -> Result<MessageType> {
self.header.get_message_type()
.ok_or(ReaderErr::NotEnoughBytes)?
.try_into()
}
pub fn get_message_length(&self) -> Option<u16> {
self.header.get_message_length()
}
pub fn get_transaction_id(&self) -> Option<u128> {
Some(self.header.get_transaction_id()? & (u128::MAX >> 32)) // this clears out the magic cookie
}
pub fn get_magic_cookie(&self) -> Option<u32> {
self.header.get_magic_cookie()
}
pub fn get_attributes(&self) -> AttributeIterator {
let magic_cookie = self.get_magic_cookie().unwrap_or(0);
let transaction_id = self.get_transaction_id().unwrap_or(0);
AttributeIterator::new(self.attr_bytes, magic_cookie, transaction_id)
}
}
pub struct Writer<'a> {
header: RawMsgHeaderWriter<'a>,
attr_bytes: &'a mut [u8],
attr_bytes_used: u16,
transaction_id_full: u128,
}
impl<'a> Writer<'a> {
pub fn new(bytes: &'a mut [u8]) -> Self {
if bytes.len() < 20 {
// for such a small buffer,
// attr is guarateed to get a slice of zero length
// but who are we to judge
let (header_bytes, attr_bytes) = bytes.split_at_mut(bytes.len());
Self {
header: RawMsgHeaderWriter::new(header_bytes),
attr_bytes,
attr_bytes_used: 0,
transaction_id_full: 0,
}
} else {
let (header_bytes, attr_bytes) = bytes.split_at_mut(20);
Self {
header: RawMsgHeaderWriter::new(header_bytes),
attr_bytes,
attr_bytes_used: 0,
transaction_id_full: 0,
}
}
}
pub fn set_message_type(&mut self, typ: MessageType) -> Option<()> {
self.header.set_message_type(typ as u16)
}
pub fn set_message_length(&mut self, len: u16) -> Option<()> {
self.header.set_message_length(len)
}
pub fn update_message_length(&mut self) -> Option<()> {
self.set_message_length(self.attr_bytes_used)
}
pub fn finish(mut self) -> Option<u16> {
self.update_message_length()?;
Some(20 + self.attr_bytes_used)
}
pub fn set_magic_cookie(&mut self, magic_cookie: u32) -> Option<()> {
self.header.set_magic_cookie(magic_cookie)?;
self.transaction_id_full = ((magic_cookie as u128) << 96) | (self.transaction_id_full & (u128::MAX >> 32));
Some(())
}
pub fn set_transaction_id(&mut self, tid: u128) -> Option<()> {
let tid = (0x2112A442 << 96) | (tid & (u128::MAX >> 32)); // force set the magic cookie
self.header.set_transaction_id(tid)?;
self.transaction_id_full = tid;
Some(())
}
pub fn add_attr(&mut self, attr: WriterAttribute) -> Option<()> {
match attr {
WriterAttribute::MappedAddress(addr) => self.add_attr_inner(0x0001, |value_dest| {
let mut w = SocketAddrWriter::new(value_dest);
match addr {
SocketAddr::V4(ip, port) => w.write_ipv4_addr(ip, port),
SocketAddr::V6(ip, port) => w.write_ipv6_addr(ip, port),
}
}),
WriterAttribute::Username(username) => self.add_attr_inner(0x0006, |value_dest| {
StringWriter::new(value_dest).write(username)
}),
WriterAttribute::MessageIntegrity(value) => self.add_attr_inner(0x0008, |value_dest| {
MessageIntegrityWriter::new(value_dest).write(value)
}),
WriterAttribute::ErrorCode(error) => self.add_attr_inner(0x0009, |value_dest| {
let mut writer = ErrorCodeWriter::new(value_dest);
Some(writer.write_code(error as u16)? + writer.write_reason(error.get_reason())?)
}),
WriterAttribute::UnknownAttributes(attrs) => self.add_attr_inner(0x000A, |value_dest| {
UnknownAttrsWriter::new(value_dest).write(attrs, attrs.get(attrs.len() - 1).map(|val| *val))
}),
WriterAttribute::Realm(realm) => self.add_attr_inner(0x0014, |value_dest| {
StringWriter::new(value_dest).write(realm)
}),
WriterAttribute::Nonce(nonce) => self.add_attr_inner(0x0015, |value_dest| {
StringWriter::new(value_dest).write(nonce)
}),
WriterAttribute::XorMappedAddress(addr) => {
let magic_cookie = (self.transaction_id_full >> 96) as u32;
let transaction_id = self.transaction_id_full;
self.add_attr_inner(0x0020, |value_dest| {
let mut w = XorSocketAddrWriter::new(value_dest);
match addr {
SocketAddr::V4(ip, port) => w.write_ipv4_addr(ip, port, magic_cookie),
SocketAddr::V6(ip, port) => w.write_ipv6_addr(ip, port, magic_cookie, transaction_id),
}
})
},
WriterAttribute::Software(software) => self.add_attr_inner(0x8022, |value_dest| {
StringWriter::new(value_dest).write(software)
}),
WriterAttribute::AlternateServer(addr) => self.add_attr_inner(0x8023, |value_dest| {
let mut w = SocketAddrWriter::new(value_dest);
match addr {
SocketAddr::V4(ip, port) => w.write_ipv4_addr(ip, port),
SocketAddr::V6(ip, port) => w.write_ipv6_addr(ip, port),
}
}),
WriterAttribute::Fingerprint(fingerprint) => self.add_attr_inner(0x8028, |value_dest| {
FingerprintWriter::new(value_dest).write(fingerprint)
}),
WriterAttribute::OptionalAttribute {typ, value} => self.add_attr_inner(typ, |value_dest| {
value_dest.get_mut(0..value.len())?
.copy_from_slice(value);
Some(value.len() as u16)
})
}?;
Some(())
}
fn add_attr_inner<T: Fn(& mut [u8]) -> Option<u16>>(&mut self, attr_type: u16, value_gen: T) -> Option<u16> {
let idx = self.attr_bytes_used as usize;
let value_buf = self.attr_bytes.get_mut(idx + 4..)?;
let value_len = value_gen(value_buf)?;
let header_buf = self.attr_bytes.get_mut(idx..idx + 4)?;
let type_bytes = attr_type.to_be_bytes();
header_buf[0..2].copy_from_slice(&type_bytes);
let value_len_bytes = value_len.to_be_bytes();
header_buf[2..4].copy_from_slice(&value_len_bytes);
let value_len_with_padding = get_nearest_greater_multiple_of_4(value_len);
let padding_dest = self.attr_bytes
.get_mut(idx + 4 + value_len as usize..idx + 4 + value_len_with_padding as usize)?;
padding_dest.fill(0); // setting padding bytes to 0
self.attr_bytes_used += 4 + value_len_with_padding;
Some(4 + value_len_with_padding)
}
}
pub struct StunErrorReader<'a> {
base_reader: ErrorCodeReader<'a>,
}
impl<'a> StunErrorReader<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
Self {
base_reader: ErrorCodeReader::new(bytes)
}
}
pub fn get_error(&self) -> Result<StunError> {
let error = self.base_reader.get_code()
.ok_or(ReaderErr::NotEnoughBytes)?
.try_into()?;
Ok(error)
}
pub fn get_reason(&self) -> Result<&str> {
self.base_reader.get_reason()
}
pub unsafe fn get_reason_unchecked(&self) -> Option<&str> {
self.base_reader.get_reason_unchecked()
}
}
pub enum ReaderAttribute<'a> {
MappedAddress(SocketAddrReader<'a>),
Username(StringReader<'a>),
MessageIntegrity(MessageIntegrityReader<'a>),
ErrorCode(StunErrorReader<'a>),
UnknownAttributes(UnknownAttrsReader<'a>),
Realm(StringReader<'a>),
Nonce(StringReader<'a>),
XorMappedAddress(XorSocketAddrReader<'a>),
Software(StringReader<'a>),
AlternateServer(SocketAddrReader<'a>),
Fingerprint(FingerprintReader<'a>),
OptionalAttribute { typ: u16, value: &'a [u8] },
}
pub enum WriterAttribute<'a, 'b> {
MappedAddress(SocketAddr),
Username(&'b str),
MessageIntegrity(&'b [u8; 20]),
ErrorCode(StunError),
UnknownAttributes(&'a [u16]),
Realm(&'a str),
Nonce(&'a str),
XorMappedAddress(SocketAddr),
Software(&'a str),
AlternateServer(SocketAddr),
Fingerprint(u32),
OptionalAttribute { typ: u16, value: &'a [u8] },
}
pub struct AttributeIterator<'a> {
base_iter: BaseAttributeIterator<'a>,
magic_cookie: u32,
transaction_id: u128,
}
impl<'a> AttributeIterator<'a> {
fn new(bytes: &'a [u8], magic_cookie: u32, transaction_id: u128) -> Self {
Self {
base_iter: BaseAttributeIterator::new(bytes),
magic_cookie,
transaction_id,
}
}
}
impl<'a> Iterator for AttributeIterator<'a> {
type Item = Result<ReaderAttribute<'a>>;
fn next(&mut self) -> Option<Self::Item> {
match self.base_iter.next() {
None => None,
Some(Err(err)) => Some(Err(err)),
Some(Ok((typ, value))) => match typ {
0x0001 => Some(Ok(ReaderAttribute::MappedAddress(SocketAddrReader::new(value)))),
0x0006 => Some(Ok(ReaderAttribute::Username(StringReader::new(value)))),
0x0008 => Some(Ok(ReaderAttribute::MessageIntegrity(MessageIntegrityReader::new(value)))),
0x0009 => Some(Ok(ReaderAttribute::ErrorCode(StunErrorReader::new(value)))),
0x000A => Some(Ok(ReaderAttribute::UnknownAttributes(UnknownAttrsReader::new(value)))),
0x0014 => Some(Ok(ReaderAttribute::Realm(StringReader::new(value)))),
0x0015 => Some(Ok(ReaderAttribute::Nonce(StringReader::new(value)))),
0x0020 => Some(Ok(ReaderAttribute::XorMappedAddress(XorSocketAddrReader::new(value, self.magic_cookie, self.transaction_id)))),
0x8022 => Some(Ok(ReaderAttribute::Software(StringReader::new(value)))),
0x8023 => Some(Ok(ReaderAttribute::AlternateServer(SocketAddrReader::new(value)))),
0x8028 => Some(Ok(ReaderAttribute::Fingerprint(FingerprintReader::new(value)))),
typ if typ > 0x7FFF => Some(Ok(ReaderAttribute::OptionalAttribute { typ, value })),
_ => Some(Err(ReaderErr::UnexpectedValue))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const HEADER: [u8; 20] = [
0x00, 0x01, // type: Binding Request
0x00, 0x04, // length: 4 (header does not count)
0x21, 0x12, 0xA4, 0x42, // magic cookie
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, // transaction id (12 bytes total)
];
#[test]
fn read_message_type() {
assert_eq!(MessageType::BindingRequest, Reader::new(&[0x00, 0x01]).get_message_type().unwrap());
assert_eq!(MessageType::BindingIndication, Reader::new(&[0x00, 0x11]).get_message_type().unwrap());
assert_eq!(MessageType::BindingResponse, Reader::new(&[0x01, 0x01]).get_message_type().unwrap());
assert_eq!(MessageType::BindingErrorResponse, Reader::new(&[0x01, 0x11]).get_message_type().unwrap());
}
#[test]
fn read_message_header() {
let r = Reader::new(&HEADER);
assert_eq!(MessageType::BindingRequest, r.get_message_type().unwrap());
assert_eq!(4u16, r.get_message_length().unwrap());
assert_eq!(1u128, r.get_transaction_id().unwrap());
}
#[test]
fn write_message_header() {
let mut buffer = [0u8; 20];
let mut w = Writer::new(&mut buffer);
w.set_message_type(MessageType::BindingRequest).unwrap();
w.set_message_length(4).unwrap();
w.set_transaction_id(1).unwrap();
assert_eq!(HEADER, buffer);
}
#[test]
fn read_resolve_attrs() {
if let Some(Ok(ReaderAttribute::MappedAddress(_))) = AttributeIterator::new(&[0x00, 0x01, 0x00, 0x00], 0, 0).next() {} else {
assert!(false, "Expected attribute MAPPED-ADDRESS");
}
if let Some(Ok(ReaderAttribute::Username(_))) = AttributeIterator::new(&[0x00, 0x06, 0x00, 0x00], 0, 0).next() {} else {
assert!(false, "Expected attribute USERNAME");
}
if let Some(Ok(ReaderAttribute::MessageIntegrity(_))) = AttributeIterator::new(&[0x00, 0x08, 0x00, 0x00], 0, 0).next() {} else {
assert!(false, "Expected attribute MESSAGE-INTEGRITY");
}
if let Some(Ok(ReaderAttribute::ErrorCode(_))) = AttributeIterator::new(&[0x00, 0x09, 0x00, 0x00], 0, 0).next() {} else {
assert!(false, "Expected attribute ERROR-CODE");
}
if let Some(Ok(ReaderAttribute::UnknownAttributes(_))) = AttributeIterator::new(&[0x00, 0x0A, 0x00, 0x00], 0, 0).next() {} else {
assert!(false, "Expected attribute UNKNOWN-ATTRIBUTES");
}
if let Some(Ok(ReaderAttribute::Realm(_))) = AttributeIterator::new(&[0x00, 0x14, 0x00, 0x00], 0, 0).next() {} else {
assert!(false, "Expected attribute REALM");
}
if let Some(Ok(ReaderAttribute::Nonce(_))) = AttributeIterator::new(&[0x00, 0x15, 0x00, 0x00], 0, 0).next() {} else {
assert!(false, "Expected attribute NONCE");
}
if let Some(Ok(ReaderAttribute::XorMappedAddress(_))) = AttributeIterator::new(&[0x00, 0x20, 0x00, 0x00], 0, 0).next() {} else {
assert!(false, "Expected attribute XOR-MAPPED-ADDRESS");
}
for optional_attr in 0x0000..=0x7FFF as u16 {
if let Some(Ok(ReaderAttribute::OptionalAttribute { .. })) = AttributeIterator::new(&((optional_attr as u32) << 16).to_be_bytes(), 0, 0).next() {
assert!(false, "Unexpected generic optional attribute for code {:#06X}", optional_attr);
}
}
for optional_attr in 0x8000..=0xFFFF as u16 {
match optional_attr {
0x8022 | 0x8023 | 0x8028 => continue,
_ => {}
}
if let Some(Ok(ReaderAttribute::OptionalAttribute { .. })) = AttributeIterator::new(&((optional_attr as u32) << 16).to_be_bytes(), 0, 0).next() {} else {
assert!(false, "Expected generic optional attribute for code {:#06X}", optional_attr);
}
}
}
const MAPPED_ADDRESS_V4: [u8; 12] = [
0x00, 0x01, // type: MappedAddress
0x00, 0x08, // value length
0x00, 0x01, // address family
0x0A, 0x0B, // port
0x0C, 0x0D, 0x0E, 0x0F, // ipv4 address
];
const MOCK_IPV4: u32 = 0xC0D0E0F;
const MOCK_IPV4_PORT: u16 = 0x0A0B;
#[test]
fn read_mapped_address_attr_ipv4() {
let mut r = AttributeIterator::new(&MAPPED_ADDRESS_V4, 0, 0);
if let Some(Ok(ReaderAttribute::MappedAddress(r))) = r.next() {
let addr = if let Ok(addr) = r.get_address() { addr } else {
assert!(false, "Test address should be a valid address");
return;
};
if let SocketAddr::V4(ip, port) = addr {
assert_eq!(MOCK_IPV4_PORT, port);
assert_eq!(MOCK_IPV4, ip);
} else {
assert!(false, "Test address should be a V4 address");
}
} else {
assert!(false, "Iterator should return a valid MappingAddress attribute");
return;
};
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_mapped_address_attr_ipv4() {
let mut buffer = [0; 32];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::MappedAddress(SocketAddr::V4(MOCK_IPV4, MOCK_IPV4_PORT))).unwrap();
assert_eq!(MAPPED_ADDRESS_V4, buffer[20..])
}
const MAPPED_ADDRESS_V6: [u8; 24] = [
0x00, 0x01, // type: MappedAddress
0x00, 0x14, // value length
0x00, 0x02, // address family: IPv6
0x0B, 0x0C, // port
0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F, // ipv6 address
];
const MOCK_IPV6: u128 = 0x000102030405060708090A0B0C0D0E0F;
const MOCK_IPV6_PORT: u16 = 0x0B0C;
#[test]
fn read_mapped_address_attr_ipv6() {
let mut r = AttributeIterator::new(&MAPPED_ADDRESS_V6, 0, 0);
if let Some(Ok(ReaderAttribute::MappedAddress(r))) = r.next() {
let addr = if let Ok(addr) = r.get_address() { addr } else {
assert!(false, "Test address should be a valid address");
return;
};
if let SocketAddr::V6(ip, port) = addr {
assert_eq!(MOCK_IPV6_PORT, port);
assert_eq!(MOCK_IPV6, ip);
} else {
assert!(false, "Test address should be a V6 address");
}
} else {
assert!(false, "Iterator should return a valid MappingAddress attribute");
return;
};
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_mapped_address_attr_ipv6() {
let mut buffer = [0; 44];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::MappedAddress(SocketAddr::V6(MOCK_IPV6, MOCK_IPV6_PORT))).unwrap();
assert_eq!(MAPPED_ADDRESS_V6, buffer[20..])
}
const MESSAGE_INTEGRITY: [u8; 24] = [
0x00, 0x08, // type: MessageIntegrity
0x00, 0x14, // value length
0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, // hash
];
#[test]
fn read_message_integrity_attr() {
let mut r = AttributeIterator::new(&MESSAGE_INTEGRITY, 0, 0);
if let Some(Ok(ReaderAttribute::MessageIntegrity(r))) = r.next() {
assert_eq!([0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13] as [u8; 20], *r.get_value().unwrap());
} else {
assert!(false, "Iterator should return a valid MessageIntegrity attribute");
}
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_message_integrity_attr() {
let mut buffer = [0; 44];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::MessageIntegrity(&[0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13])).unwrap();
assert_eq!(MESSAGE_INTEGRITY, buffer[20..]);
}
const USERNAME: [u8; 12] = [
0x00, 0x06, // type: Username
0x00, 0x06, // value length
0x75, 0x73,
0x65, 0x72,
0x31, 0x32, // 'user12'
0x00, 0x00, // padding
];
const MOCK_USERNAME: &'static str = "user12";
#[test]
fn read_username_attr() {
let mut r = AttributeIterator::new(&USERNAME, 0, 0);
if let Some(Ok(ReaderAttribute::Username(r))) = r.next() {
assert_eq!(MOCK_USERNAME, r.get_value().unwrap());
} else {
assert!(false, "Iterator should return a valid Username attribute");
}
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_username_attr() {
let mut buffer = [0; 32];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::Username(MOCK_USERNAME)).unwrap();
assert_eq!(USERNAME, buffer[20..]);
}
const ERROR_CODE: [u8; 13] = [
0x00, 0x09, // type: ErrorCode
0x00, 0x09, // value length
0x00, 0x00, // reserved
0x80, 0x00, // class 4, num 00 = code 400
0x68, 0x65, 0x6C, 0x6C, 0x6F, // reason = 'hello'
];
#[test]
fn read_error_code() {
let mut r = AttributeIterator::new(&ERROR_CODE, 0, 0);
if let Some(Ok(ReaderAttribute::ErrorCode(r))) = r.next() {
let error = if let Ok(addr) = r.get_error() { addr } else {
assert!(false, "Test address should be a valid address");
return;
};
if let StunError::BadRequest = error {
} else {
assert!(false, "Error code is not BadRequest");
}
} else {
assert!(false, "Iterator should return a valid ErrorCode attribute");
return;
};
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_error_code() {
let mut buffer = [0u8; 256];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::ErrorCode(StunError::BadRequest)).expect("Buffer too small");
assert_eq!(ERROR_CODE[0..2], buffer[20..][0..2]); // TODO fixme
}
const UNKNOWN_ATTIBUTES: [u8; 8] = [
0x00, 0x0A, // type: UnknownAttributes
0x00, 0x02, // value length
0x00, 0x01, // unknown attr
0x00, 0x01, // the same unknown attr as padding
];
#[test]
fn read_unknown_attributes() {
let mut r = AttributeIterator::new(&UNKNOWN_ATTIBUTES, 0, 0);
if let Some(Ok(ReaderAttribute::UnknownAttributes(r))) = r.next() {
let mut r = r.unknown_type_codes();
if let Some(Ok(unknown_attr)) = r.next() {
assert_eq!(1, unknown_attr);
} else {
assert!(false, "Unknown attribute value is unreadable");
}
assert!(r.next().is_none(), "There should be only one unknown attribute value");
} else {
assert!(false, "Iterator should return a valid UnknownAttributes attribute");
return;
};
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_unknown_attributes() {
let mut buffer = [0; 28];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::UnknownAttributes(&[1])).unwrap();
assert_eq!(UNKNOWN_ATTIBUTES[4..], buffer[20..][4..]);
}
const REALM: [u8; 12] = [
0x00, 0x14, // type: Realm
0x00, 0x06, // value length
0x75, 0x73,
0x65, 0x72,
0x31, 0x32, // 'user12'
0x00, 0x00, // padding
];
const MOCK_REALM: &'static str = "user12";
#[test]
fn read_realm_attr() {
let mut r = AttributeIterator::new(&REALM, 0, 0);
if let Some(Ok(ReaderAttribute::Realm(r))) = r.next() {
assert_eq!(MOCK_REALM, r.get_value().unwrap());
} else {
assert!(false, "Iterator should return a valid Realm attribute");
}
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_realm_attr() {
let mut buffer = [0; 32];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::Realm(MOCK_REALM)).unwrap();
assert_eq!(REALM, buffer[20..]);
}
const NONCE: [u8; 12] = [
0x00, 0x15, // type: Nonce
0x00, 0x06, // value length
0x75, 0x73,
0x65, 0x72,
0x31, 0x32, // 'user12'
0x00, 0x00, // padding
];
const MOCK_NONCE: &'static str = "user12";
#[test]
fn read_nonce_attr() {
let mut r = AttributeIterator::new(&NONCE, 0, 0);
if let Some(Ok(ReaderAttribute::Nonce(r))) = r.next() {
assert_eq!(MOCK_NONCE, r.get_value().unwrap());
} else {
assert!(false, "Iterator should return a valid Nonce attribute");
}
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_nonce_attr() {
let mut buffer = [0; 32];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::Nonce(MOCK_NONCE)).unwrap();
assert_eq!(NONCE, buffer[20..]);
}
const XOR_MAPPED_ADDRESS_V4: [u8; 12] = [
0x00, 0x20, // type: XorMappedAddress
0x00, 0x08, // value length
0x00, 0x01, // address family
0x0A, 0x0B, // port
0x0C, 0x0D, 0x0E, 0x0F, // ipv4 address
];
const XOR_MOCK_IPV4: u32 = 0xC0D0E0F ^ 0x0;
#[test]
fn read_xor_mapped_address_attr_ipv4() {
let mut r = AttributeIterator::new(&XOR_MAPPED_ADDRESS_V4, 0, 0);
if let Some(Ok(ReaderAttribute::XorMappedAddress(r))) = r.next() {
let addr = if let Ok(addr) = r.get_address() { addr } else {
assert!(false, "Test address should be a valid address");
return;
};
if let SocketAddr::V4(ip, port) = addr {
assert_eq!(MOCK_IPV4_PORT, port);
assert_eq!(XOR_MOCK_IPV4, ip);
} else {
assert!(false, "Test address should be a V4 address");
}
} else {
assert!(false, "Iterator should return a valid XorMappingAddress attribute");
return;
};
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_xor_mapped_address_attr_ipv4() {
let mut buffer = [0; 32];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::XorMappedAddress(SocketAddr::V4(XOR_MOCK_IPV4, MOCK_IPV4_PORT))).unwrap();
assert_eq!(XOR_MAPPED_ADDRESS_V4, buffer[20..])
}
const XOR_MAPPED_ADDRESS_V6: [u8; 24] = [
0x00, 0x20, // type: XorMappedAddress
0x00, 0x14, // value length
0x00, 0x02, // address family: IPv6
0x0B, 0x0C, // port
0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F, // ipv6 address
];
const XOR_MOCK_IPV6: u128 = 0x000102030405060708090A0B0C0D0E0F ^ 0x0;
#[test]
fn read_xor_mapped_address_attr_ipv6() {
let mut r = AttributeIterator::new(&XOR_MAPPED_ADDRESS_V6, 0, 0);
if let Some(Ok(ReaderAttribute::XorMappedAddress(r))) = r.next() {
let addr = if let Ok(addr) = r.get_address() { addr } else {
assert!(false, "Test address should be a valid address");
return;
};
if let SocketAddr::V6(ip, port) = addr {
assert_eq!(MOCK_IPV6_PORT, port);
assert_eq!(XOR_MOCK_IPV6, ip);
} else {
assert!(false, "Test address should be a V6 address");
}
} else {
assert!(false, "Iterator should return a valid XorMappingAddress attribute");
return;
};
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_xor_mapped_address_attr_ipv6() {
let mut buffer = [0; 44];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::XorMappedAddress(SocketAddr::V6(XOR_MOCK_IPV6, MOCK_IPV6_PORT))).unwrap();
assert_eq!(XOR_MAPPED_ADDRESS_V6, buffer[20..])
}
const SOFTWARE: [u8; 12] = [
0x80, 0x22, // type: Software
0x00, 0x06, // value length
0x75, 0x73,
0x65, 0x72,
0x31, 0x32, // 'user12'
0x00, 0x00, // padding
];
const MOCK_SOFTWARE: &'static str = "user12";
#[test]
fn read_software_attr() {
let mut r = AttributeIterator::new(&SOFTWARE, 0, 0);
if let Some(Ok(ReaderAttribute::Software(r))) = r.next() {
assert_eq!(MOCK_SOFTWARE, r.get_value().unwrap());
} else {
assert!(false, "Iterator should return a valid Username attribute");
}
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_software_attr() {
let mut buffer = [0; 32];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::Software(MOCK_SOFTWARE)).unwrap();
assert_eq!(SOFTWARE, buffer[20..]);
}
const ALTERNATE_SERVER_V4: [u8; 12] = [
0x80, 0x23, // type: AlternateServer
0x00, 0x08, // value length
0x00, 0x01, // address family
0x0A, 0x0B, // port
0x0C, 0x0D, 0x0E, 0x0F, // ipv4 address
];
#[test]
fn read_alternate_server_attr_ipv4() {
let mut r = AttributeIterator::new(&ALTERNATE_SERVER_V4, 0, 0);
if let Some(Ok(ReaderAttribute::AlternateServer(r))) = r.next() {
let addr = if let Ok(addr) = r.get_address() { addr } else {
assert!(false, "Test address should be a valid address");
return;
};
if let SocketAddr::V4(ip, port) = addr {
assert_eq!(MOCK_IPV4_PORT, port);
assert_eq!(MOCK_IPV4, ip);
} else {
assert!(false, "Test address should be a V4 address");
}
} else {
assert!(false, "Iterator should return a valid AlternateServer attribute");
return;
};
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_alternate_server_attr_ipv4() {
let mut buffer = [0; 32];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::AlternateServer(SocketAddr::V4(MOCK_IPV4, MOCK_IPV4_PORT))).unwrap();
assert_eq!(ALTERNATE_SERVER_V4, buffer[20..])
}
const ALTERNATE_SERVER_V6: [u8; 24] = [
0x80, 0x23, // type: AlternateServer
0x00, 0x14, // value length
0x00, 0x02, // address family: IPv6
0x0B, 0x0C, // port
0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F, // ipv6 address
];
#[test]
fn read_alternate_server_attr_ipv6() {
let mut r = AttributeIterator::new(&ALTERNATE_SERVER_V6, 0, 0);
if let Some(Ok(ReaderAttribute::AlternateServer(r))) = r.next() {
let addr = if let Ok(addr) = r.get_address() { addr } else {
assert!(false, "Test address should be a valid address");
return;
};
if let SocketAddr::V6(ip, port) = addr {
assert_eq!(MOCK_IPV6_PORT, port);
assert_eq!(MOCK_IPV6, ip);
} else {
assert!(false, "Test address should be a V6 address");
}
} else {
assert!(false, "Iterator should return a valid AlternateServer attribute");
return;
};
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_alternate_server_attr_ipv6() {
let mut buffer = [0; 44];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::AlternateServer(SocketAddr::V6(MOCK_IPV6, MOCK_IPV6_PORT))).unwrap();
assert_eq!(ALTERNATE_SERVER_V6, buffer[20..])
}
const FINGERPRINT: [u8; 8] = [
0x80, 0x28, // type: Fingerprint
0x00, 0x04, // value length
0x01, 0x02, 0x03, 0x04 // fingerprint value
];
const FINGERPRINT_VALUE: u32 = 0x01020304 ^ 0x5354554E;
#[test]
fn read_fingerprint_attr() {
let mut r = AttributeIterator::new(&FINGERPRINT, 0, 0);
if let Some(Ok(ReaderAttribute::Fingerprint(r))) = r.next() {
assert_eq!(FINGERPRINT_VALUE, r.get_value().unwrap());
} else {
assert!(false, "Iterator should return a valid Fingerprint attribute");
}
assert!(r.next().is_none(), "There should be only one attribute");
}
#[test]
fn write_fingerprint_attr() {
let mut buffer = [0; 28];
let mut w = Writer::new(&mut buffer);
w.add_attr(WriterAttribute::Fingerprint(FINGERPRINT_VALUE)).unwrap();
assert_eq!(FINGERPRINT, buffer[20..]);
}
}