use std::convert::TryFrom;
use std::convert::TryInto;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use crate::message::{TransactionId, MAGIC_COOKIE, StunParseError, StunWriteError};
use byteorder::{BigEndian, ByteOrder};
use tracing::error;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct AttributeType(u16);
impl std::fmt::Display for AttributeType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
}
}
impl AttributeType {
pub const fn new(val: u16) -> Self {
Self(val)
}
pub fn value(&self) -> u16 {
self.0
}
pub fn name(self) -> &'static str {
match self {
AttributeType(0x0001) => "MAPPED-ADDRESS",
Username::TYPE => "USERNAME",
MessageIntegrity::TYPE => "MESSAGE-INTEGRITY",
ErrorCode::TYPE => "ERROR-CODE",
UnknownAttributes::TYPE => "UNKNOWN-ATTRIBUTES",
Realm::TYPE => "REALM",
Nonce::TYPE => "NONCE",
MessageIntegritySha256::TYPE => "MESSAGE-INTEGRITY-SHA256",
PasswordAlgorithm::TYPE => "PASSWORD-ALGORITHM",
Userhash::TYPE => "USERHASH",
XorMappedAddress::TYPE => "XOR-MAPPED-ADDRESS",
PasswordAlgorithms::TYPE => "PASSWORD_ALGORITHMS",
AlternateDomain::TYPE => "ALTERNATE-DOMAIN",
Software::TYPE => "SOFTWARE",
AlternateServer::TYPE => "ALTERNATE-SERVER",
Fingerprint::TYPE => "FINGERPRINT",
Priority::TYPE => "PRIORITY",
UseCandidate::TYPE => "USE-CANDIDATE",
IceControlled::TYPE => "ICE-CONTROLLED",
IceControlling::TYPE => "ICE-CONTROLLING",
_ => "unknown",
}
}
pub fn comprehension_required(self) -> bool {
self.0 < 0x8000
}
}
impl From<u16> for AttributeType {
fn from(f: u16) -> Self {
Self::new(f)
}
}
impl From<AttributeType> for u16 {
fn from(f: AttributeType) -> Self {
f.0
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AttributeHeader {
atype: AttributeType,
length: u16,
}
impl AttributeHeader {
fn parse(data: &[u8]) -> Result<Self, StunParseError> {
if data.len() < 4 {
return Err(StunParseError::NotEnoughData);
}
let ret = Self {
atype: BigEndian::read_u16(&data[0..2]).into(),
length: BigEndian::read_u16(&data[2..4]),
};
Ok(ret)
}
fn to_bytes(self) -> Vec<u8> {
let mut ret = vec![0; 4];
BigEndian::write_u16(&mut ret[0..2], self.atype.into());
BigEndian::write_u16(&mut ret[2..4], self.length);
ret
}
pub fn get_type(&self) -> AttributeType {
self.atype
}
pub fn length(&self) -> u16 {
self.length
}
}
impl From<AttributeHeader> for Vec<u8> {
fn from(f: AttributeHeader) -> Self {
f.to_bytes()
}
}
impl TryFrom<&[u8]> for AttributeHeader {
type Error = StunParseError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
AttributeHeader::parse(value)
}
}
pub trait Attribute: std::fmt::Debug {
const TYPE: AttributeType;
fn length(&self) -> u16;
}
pub trait AttributeToRaw: Attribute + Into<RawAttribute>
where
RawAttribute: for<'a> From<&'a Self>,
{
fn to_raw(&self) -> RawAttribute;
}
impl<T: Attribute + Into<RawAttribute>> AttributeToRaw for T
where
RawAttribute: for<'a> From<&'a Self>,
{
fn to_raw(&self) -> RawAttribute
where
RawAttribute: for<'a> From<&'a Self>,
{
self.into()
}
}
pub trait AttributeFromRaw<E>: Attribute + for<'a> TryFrom<&'a RawAttribute, Error = E> {
fn from_raw(raw: &RawAttribute) -> Result<Self, E>
where
Self: Sized;
}
impl<E, T: Attribute + for<'a> TryFrom<&'a RawAttribute, Error = E>> AttributeFromRaw<E> for T {
fn from_raw(raw: &RawAttribute) -> Result<T, E> {
Self::try_from(raw)
}
}
fn padded_attr_len(len: usize) -> usize {
if len % 4 == 0 {
len
} else {
len + 4 - len % 4
}
}
pub(crate) fn padded_attr_size(attr: &RawAttribute) -> usize {
4 + padded_attr_len(attr.length() as usize)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RawAttribute {
pub header: AttributeHeader,
pub value: Vec<u8>,
}
macro_rules! display_attr {
($this:ident, $CamelType:ty, $default:ident) => {{
if let Ok(attr) = <$CamelType>::from_raw($this) {
format!("{}", attr)
} else {
$default
}
}};
}
impl std::fmt::Display for RawAttribute {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let malformed_str = format!(
"{}(Malformed): len: {}, data: {:?})",
self.get_type(),
self.header.length,
self.value
);
let display_str = match self.get_type() {
Username::TYPE => display_attr!(self, Username, malformed_str),
MessageIntegrity::TYPE => display_attr!(self, MessageIntegrity, malformed_str),
ErrorCode::TYPE => display_attr!(self, ErrorCode, malformed_str),
UnknownAttributes::TYPE => display_attr!(self, UnknownAttributes, malformed_str),
Realm::TYPE => display_attr!(self, Realm, malformed_str),
Nonce::TYPE => display_attr!(self, Nonce, malformed_str),
MessageIntegritySha256::TYPE => display_attr!(self, MessageIntegritySha256, malformed_str),
PasswordAlgorithm::TYPE => display_attr!(self, PasswordAlgorithm, malformed_str),
XorMappedAddress::TYPE => display_attr!(self, XorMappedAddress, malformed_str),
PasswordAlgorithms::TYPE => display_attr!(self, PasswordAlgorithms, malformed_str),
AlternateDomain::TYPE => display_attr!(self, AlternateDomain, malformed_str),
Software::TYPE => display_attr!(self, Software, malformed_str),
AlternateServer::TYPE => display_attr!(self, AlternateServer, malformed_str),
Fingerprint::TYPE => display_attr!(self, Fingerprint, malformed_str),
Priority::TYPE => display_attr!(self, Priority, malformed_str),
UseCandidate::TYPE => display_attr!(self, UseCandidate, malformed_str),
IceControlled::TYPE => display_attr!(self, IceControlled, malformed_str),
IceControlling::TYPE => display_attr!(self, IceControlling, malformed_str),
_ => format!(
"RawAttribute (type: {:?}, len: {}, data: {:?})",
self.header.atype, self.header.length, &self.value
),
};
write!(f, "{}", display_str)
}
}
impl RawAttribute {
pub fn new(atype: AttributeType, data: &[u8]) -> Self {
Self {
header: AttributeHeader {
atype,
length: data.len() as u16,
},
value: data.to_vec(),
}
}
pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
let header = AttributeHeader::parse(data)?;
if header.length > (data.len() - 4) as u16 {
return Err(StunParseError::NotEnoughData);
}
let mut data = data[4..].to_vec();
data.truncate(header.length as usize);
Ok(Self {
header,
value: data,
})
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut ret: Vec<u8> = self.header.into();
ret.extend(&self.value);
let len = ret.len();
if len % 4 != 0 {
ret.resize(len + 4 - (len % 4), 0);
}
ret
}
pub fn get_type(&self) -> AttributeType {
self.header.atype
}
pub fn length(&self) -> u16 {
self.value.len() as u16
}
}
impl From<RawAttribute> for Vec<u8> {
fn from(f: RawAttribute) -> Self {
f.to_bytes()
}
}
impl TryFrom<&[u8]> for RawAttribute {
type Error = StunParseError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
RawAttribute::from_bytes(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Username {
user: String,
}
impl Attribute for Username {
const TYPE: AttributeType = AttributeType(0x0006);
fn length(&self) -> u16 {
self.user.len() as u16
}
}
impl From<Username> for RawAttribute {
fn from(value: Username) -> RawAttribute {
RawAttribute::new(Username::TYPE, value.user.as_bytes())
}
}
impl TryFrom<&RawAttribute> for Username {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() > 513 {
return Err(StunParseError::TooBig);
}
Ok(Self {
user: std::str::from_utf8(&raw.value)
.map_err(|_| StunParseError::InvalidData)?
.to_owned(),
})
}
}
impl Username {
pub fn new(user: &str) -> Result<Self, StunWriteError> {
if user.len() > 513 {
return Err(StunWriteError::TooBig);
}
Ok(Self {
user: user.to_owned(),
})
}
pub fn username(&self) -> &str {
&self.user
}
}
impl std::fmt::Display for Username {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: '{}'", Self::TYPE, self.user)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ErrorCode {
code: u16,
reason: String,
}
impl Attribute for ErrorCode {
const TYPE: AttributeType = AttributeType(0x0009);
fn length(&self) -> u16 {
self.reason.len() as u16 + 4
}
}
impl From<ErrorCode> for RawAttribute {
fn from(value: ErrorCode) -> RawAttribute {
let mut data = Vec::with_capacity(value.length() as usize);
data.push(0u8);
data.push(0u8);
data.push((value.code / 100) as u8);
data.push((value.code % 100) as u8);
data.extend(value.reason.as_bytes());
RawAttribute::new(ErrorCode::TYPE, &data)
}
}
impl TryFrom<&RawAttribute> for ErrorCode {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 4 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 763 + 4 {
return Err(StunParseError::TooBig);
}
let code_h = (raw.value[2] & 0x7) as u16;
let code_tens = raw.value[3] as u16;
if !(3..7).contains(&code_h) || code_tens > 99 {
return Err(StunParseError::OutOfRange);
}
let code = code_h * 100 + code_tens;
Ok(Self {
code,
reason: std::str::from_utf8(&raw.value[4..])
.map_err(|_| StunParseError::InvalidData)?
.to_owned(),
})
}
}
pub struct ErrorCodeBuilder<'reason> {
code: u16,
reason: Option<&'reason str>,
}
impl<'reason> ErrorCodeBuilder<'reason> {
fn new(code: u16) -> Self {
Self { code, reason: None }
}
pub fn reason(mut self, reason: &'reason str) -> Self {
self.reason = Some(reason);
self
}
pub fn build(self) -> Result<ErrorCode, StunParseError> {
if !(300..700).contains(&self.code) {
return Err(StunParseError::OutOfRange);
}
let reason = self
.reason
.unwrap_or_else(|| ErrorCode::default_reason_for_code(self.code))
.to_owned();
Ok(ErrorCode {
code: self.code,
reason,
})
}
}
impl ErrorCode {
pub const TRY_ALTERNATE: u16 = 301;
pub const BAD_REQUEST: u16 = 400;
pub const UNAUTHORIZED: u16 = 401;
pub const FORBIDDEN: u16 = 403;
pub const UNKNOWN_ATRIBUTE: u16 = 420;
pub const ALLOCATION_MISMATCH: u16 = 437;
pub const STALE_NONCE: u16 = 438;
pub const ADDRESS_FAMILY_NOT_SUPPORTED: u16 = 440;
pub const WRONG_CREDENTIALS: u16 = 441;
pub const UNSUPPORTED_TRANSPORT_PROTOCOL: u16 = 442;
pub const PEER_ADDRESS_FAMILY_MISMATCH: u16 = 443;
pub const ALLOCATION_QUOTA_REACHED: u16 = 486;
pub const ROLE_CONFLICT: u16 = 487;
pub const SERVER_ERROR: u16 = 500;
pub const INSUFFICIENT_CAPACITY: u16 = 508;
pub fn builder<'reason>(code: u16) -> ErrorCodeBuilder<'reason> {
ErrorCodeBuilder::new(code)
}
pub fn new(code: u16, reason: &str) -> Result<Self, StunParseError> {
if !(300..700).contains(&code) {
return Err(StunParseError::OutOfRange);
}
Ok(Self {
code,
reason: reason.to_owned(),
})
}
pub fn code(&self) -> u16 {
self.code
}
pub fn reason(&self) -> &str {
&self.reason
}
pub fn default_reason_for_code(code: u16) -> &'static str {
match code {
Self::TRY_ALTERNATE => "Try Alternate",
Self::BAD_REQUEST => "Bad Request",
Self::UNAUTHORIZED => "Unauthorized",
Self::FORBIDDEN => "Forbidden",
Self::UNKNOWN_ATRIBUTE => "Unknown Attribute",
Self::ALLOCATION_MISMATCH => "Allocation Mismatch",
Self::STALE_NONCE => "Stale Nonce",
Self::ADDRESS_FAMILY_NOT_SUPPORTED => "Address Family Not Supported",
Self::WRONG_CREDENTIALS => "Wrong Credentials",
Self::UNSUPPORTED_TRANSPORT_PROTOCOL => "Unsupported Transport Protocol",
Self::PEER_ADDRESS_FAMILY_MISMATCH => "Peer Address Family Mismatch",
Self::ALLOCATION_QUOTA_REACHED => "Allocation Quota Reached",
Self::ROLE_CONFLICT => "Role Conflict",
Self::SERVER_ERROR => "Server Error",
Self::INSUFFICIENT_CAPACITY => "Insufficient Capacity",
_ => "Unknown",
}
}
}
impl std::fmt::Display for ErrorCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {} '{}'", Self::TYPE, self.code, self.reason)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnknownAttributes {
attributes: Vec<AttributeType>,
}
impl Attribute for UnknownAttributes {
const TYPE: AttributeType = AttributeType(0x000A);
fn length(&self) -> u16 {
(self.attributes.len() as u16) * 2
}
}
impl From<UnknownAttributes> for RawAttribute {
fn from(value: UnknownAttributes) -> RawAttribute {
let mut data = Vec::with_capacity(value.length() as usize);
for attr in &value.attributes {
let mut encoded = vec![0; 2];
BigEndian::write_u16(&mut encoded, (*attr).into());
data.extend(encoded);
}
RawAttribute::new(UnknownAttributes::TYPE, &data)
}
}
impl TryFrom<&RawAttribute> for UnknownAttributes {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() % 2 != 0 {
return Err(StunParseError::InvalidData);
}
let mut attrs = vec![];
for attr in raw.value.chunks_exact(2) {
attrs.push(BigEndian::read_u16(attr).into());
}
Ok(Self { attributes: attrs })
}
}
impl UnknownAttributes {
pub fn new(attrs: &[AttributeType]) -> Self {
Self {
attributes: attrs.to_vec(),
}
}
pub fn add_attribute(&mut self, attr: AttributeType) {
if !self.has_attribute(attr) {
self.attributes.push(attr);
}
}
pub fn has_attribute(&self, attr: AttributeType) -> bool {
self.attributes.iter().any(|&a| a == attr)
}
}
impl std::fmt::Display for UnknownAttributes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {:?}", Self::TYPE, self.attributes)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Software {
software: String,
}
impl Attribute for Software {
const TYPE: AttributeType = AttributeType(0x8022);
fn length(&self) -> u16 {
self.software.len() as u16
}
}
impl From<Software> for RawAttribute {
fn from(value: Software) -> RawAttribute {
RawAttribute::new(Software::TYPE, value.software.as_bytes())
}
}
impl TryFrom<&RawAttribute> for Software {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() > 763 {
return Err(StunParseError::TooBig);
}
Ok(Self {
software: std::str::from_utf8(&raw.value)
.map_err(|_| StunParseError::InvalidData)?
.to_owned(),
})
}
}
impl Software {
pub fn new(software: &str) -> Result<Self, StunParseError> {
if software.len() > 768 {
return Err(StunParseError::TooBig);
}
Ok(Self {
software: software.to_owned(),
})
}
pub fn software(&self) -> &str {
&self.software
}
}
impl std::fmt::Display for Software {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: '{}'", Software::TYPE, self.software)
}
}
macro_rules! bytewise_xor {
($size:literal, $a:expr, $b:expr, $default:literal) => {{
let mut arr = [$default; $size];
for (i, item) in arr.iter_mut().enumerate() {
*item = $a[i] ^ $b[i];
}
arr
}};
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct MappedSocketAddr {
pub(crate) addr: SocketAddr,
}
impl MappedSocketAddr {
pub(crate) fn new(addr: SocketAddr) -> Self {
Self { addr }
}
pub(crate) fn length(&self) -> u16 {
match self.addr {
SocketAddr::V4(_) => 8,
SocketAddr::V6(_) => 20,
}
}
pub(crate) fn to_raw(&self, atype: AttributeType) -> RawAttribute {
match self.addr {
SocketAddr::V4(addr) => {
let mut buf = [0; 8];
buf[1] = AddressFamily::IPV4.to_byte();
BigEndian::write_u16(&mut buf[2..4], addr.port());
let octets = u32::from(*addr.ip());
BigEndian::write_u32(&mut buf[4..8], octets);
RawAttribute::new(atype, &buf)
}
SocketAddr::V6(addr) => {
let mut buf = [0; 20];
buf[1] = AddressFamily::IPV6.to_byte();
BigEndian::write_u16(&mut buf[2..4], addr.port());
let octets = u128::from(*addr.ip());
BigEndian::write_u128(&mut buf[4..20], octets);
RawAttribute::new(atype, &buf)
}
}
}
pub(crate) fn from_raw(raw: &RawAttribute) -> Result<Self, StunParseError> {
if raw.value.len() < 4 {
return Err(StunParseError::NotEnoughData);
}
let port = BigEndian::read_u16(&raw.value[2..4]);
let family = AddressFamily::from_byte(raw.value[1])?;
let addr = match family {
AddressFamily::IPV4 => {
if raw.value.len() < 8 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 8 {
return Err(StunParseError::TooBig);
}
IpAddr::V4(Ipv4Addr::from(BigEndian::read_u32(&raw.value[4..8])))
}
AddressFamily::IPV6 => {
if raw.value.len() < 20 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 20 {
return Err(StunParseError::TooBig);
}
let mut octets = [0; 16];
octets.clone_from_slice(&raw.value[4..]);
IpAddr::V6(Ipv6Addr::from(octets))
}
};
Ok(Self {
addr: SocketAddr::new(addr, port),
})
}
}
impl std::fmt::Display for MappedSocketAddr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.addr {
SocketAddr::V4(addr) => write!(f, "{:?}", addr),
SocketAddr::V6(addr) => write!(f, "{:?}", addr),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct XorSocketAddr {
pub(crate) addr: MappedSocketAddr,
}
impl XorSocketAddr {
pub(crate) fn new(addr: SocketAddr, transaction: TransactionId) -> Self {
Self {
addr: MappedSocketAddr::new(XorSocketAddr::xor_addr(addr, transaction)),
}
}
pub(crate) fn length(&self) -> u16 {
self.addr.length()
}
pub(crate) fn to_raw(&self, atype: AttributeType) -> RawAttribute {
self.addr.to_raw(atype)
}
pub(crate) fn from_raw(raw: &RawAttribute) -> Result<Self, StunParseError> {
let addr = MappedSocketAddr::from_raw(raw)?;
Ok(Self { addr })
}
pub(crate) fn xor_addr(addr: SocketAddr, transaction: TransactionId) -> SocketAddr {
match addr {
SocketAddr::V4(addr) => {
let port = addr.port() ^ (MAGIC_COOKIE >> 16) as u16;
let const_octets = MAGIC_COOKIE.to_be_bytes();
let addr_octets = addr.ip().octets();
let octets = bytewise_xor!(4, const_octets, addr_octets, 0);
SocketAddr::new(IpAddr::V4(Ipv4Addr::from(octets)), port)
}
SocketAddr::V6(addr) => {
let port = addr.port() ^ (MAGIC_COOKIE >> 16) as u16;
let transaction: u128 = transaction.into();
let const_octets = ((MAGIC_COOKIE as u128) << 96
| (transaction & 0x0000_0000_ffff_ffff_ffff_ffff_ffff_ffff))
.to_be_bytes();
let addr_octets = addr.ip().octets();
let octets = bytewise_xor!(16, const_octets, addr_octets, 0);
SocketAddr::new(IpAddr::V6(Ipv6Addr::from(octets)), port)
}
}
}
pub(crate) fn addr(&self, transaction: TransactionId) -> SocketAddr {
XorSocketAddr::xor_addr(self.addr.addr, transaction)
}
}
impl std::fmt::Display for XorSocketAddr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.addr.addr {
SocketAddr::V4(_) => write!(f, "{:?}", self.addr(0x0.into())),
SocketAddr::V6(addr) => write!(f, "XOR({:?})", addr),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct XorMappedAddress {
addr: XorSocketAddr,
}
impl Attribute for XorMappedAddress {
const TYPE: AttributeType = AttributeType(0x0020);
fn length(&self) -> u16 {
self.addr.length()
}
}
impl From<XorMappedAddress> for RawAttribute {
fn from(value: XorMappedAddress) -> RawAttribute {
value.addr.to_raw(XorMappedAddress::TYPE)
}
}
impl TryFrom<&RawAttribute> for XorMappedAddress {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
Ok(Self {
addr: XorSocketAddr::from_raw(raw)?,
})
}
}
impl XorMappedAddress {
pub fn new(addr: SocketAddr, transaction: TransactionId) -> Self {
Self {
addr: XorSocketAddr::new(addr, transaction),
}
}
pub fn addr(&self, transaction: TransactionId) -> SocketAddr {
self.addr.addr(transaction)
}
}
impl std::fmt::Display for XorMappedAddress {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", Self::TYPE, self.addr)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Priority {
priority: u32,
}
impl Attribute for Priority {
const TYPE: AttributeType = AttributeType(0x0024);
fn length(&self) -> u16 {
4
}
}
impl From<Priority> for RawAttribute {
fn from(value: Priority) -> RawAttribute {
let mut buf = [0; 4];
BigEndian::write_u32(&mut buf[0..4], value.priority);
RawAttribute::new(Priority::TYPE, &buf)
}
}
impl TryFrom<&RawAttribute> for Priority {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 4 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 4 {
return Err(StunParseError::TooBig);
}
Ok(Self {
priority: BigEndian::read_u32(&raw.value[..4]),
})
}
}
impl Priority {
pub fn new(priority: u32) -> Self {
Self { priority }
}
pub fn priority(&self) -> u32 {
self.priority
}
}
impl std::fmt::Display for Priority {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", Self::TYPE, self.priority)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UseCandidate {}
impl Attribute for UseCandidate {
const TYPE: AttributeType = AttributeType(0x0025);
fn length(&self) -> u16 {
0
}
}
impl From<UseCandidate> for RawAttribute {
fn from(_value: UseCandidate) -> RawAttribute {
let buf = [0; 0];
RawAttribute::new(UseCandidate::TYPE, &buf)
}
}
impl TryFrom<&RawAttribute> for UseCandidate {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if !raw.value.is_empty() {
return Err(StunParseError::TooBig);
}
Ok(Self {})
}
}
impl Default for UseCandidate {
fn default() -> Self {
UseCandidate::new()
}
}
impl UseCandidate {
pub fn new() -> Self {
Self {}
}
}
impl std::fmt::Display for UseCandidate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::TYPE)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IceControlled {
tie_breaker: u64,
}
impl Attribute for IceControlled {
const TYPE: AttributeType = AttributeType(0x8029);
fn length(&self) -> u16 {
8
}
}
impl From<IceControlled> for RawAttribute {
fn from(value: IceControlled) -> RawAttribute {
let mut buf = [0; 8];
BigEndian::write_u64(&mut buf[..8], value.tie_breaker);
RawAttribute::new(IceControlled::TYPE, &buf)
}
}
impl TryFrom<&RawAttribute> for IceControlled {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 8 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 8 {
return Err(StunParseError::TooBig);
}
Ok(Self {
tie_breaker: BigEndian::read_u64(&raw.value),
})
}
}
impl IceControlled {
pub fn new(tie_breaker: u64) -> Self {
Self { tie_breaker }
}
pub fn tie_breaker(&self) -> u64 {
self.tie_breaker
}
}
impl std::fmt::Display for IceControlled {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::TYPE)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IceControlling {
tie_breaker: u64,
}
impl Attribute for IceControlling {
const TYPE: AttributeType = AttributeType(0x802A);
fn length(&self) -> u16 {
8
}
}
impl From<IceControlling> for RawAttribute {
fn from(value: IceControlling) -> RawAttribute {
let mut buf = [0; 8];
BigEndian::write_u64(&mut buf[..8], value.tie_breaker);
RawAttribute::new(IceControlling::TYPE, &buf)
}
}
impl TryFrom<&RawAttribute> for IceControlling {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 8 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 8 {
return Err(StunParseError::TooBig);
}
Ok(Self {
tie_breaker: BigEndian::read_u64(&raw.value),
})
}
}
impl IceControlling {
pub fn new(tie_breaker: u64) -> Self {
Self { tie_breaker }
}
pub fn tie_breaker(&self) -> u64 {
self.tie_breaker
}
}
impl std::fmt::Display for IceControlling {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Self::TYPE)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MessageIntegrity {
hmac: [u8; 20],
}
impl Attribute for MessageIntegrity {
const TYPE: AttributeType = AttributeType(0x0008);
fn length(&self) -> u16 {
20
}
}
impl From<MessageIntegrity> for RawAttribute {
fn from(value: MessageIntegrity) -> RawAttribute {
RawAttribute::new(MessageIntegrity::TYPE, &value.hmac)
}
}
impl TryFrom<&RawAttribute> for MessageIntegrity {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 20 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 20 {
return Err(StunParseError::TooBig);
}
let boxed: Box<[u8; 20]> = raw.value.clone().into_boxed_slice().try_into().unwrap();
Ok(Self { hmac: *boxed })
}
}
impl MessageIntegrity {
pub fn new(hmac: [u8; 20]) -> Self {
Self { hmac }
}
pub fn hmac(&self) -> &[u8; 20] {
&self.hmac
}
#[tracing::instrument(
name = "MessageIntegrity::compute",
level = "trace",
err,
ret,
skip(data, key)
)]
pub fn compute(data: &[u8], key: &[u8]) -> Result<[u8; 20], StunParseError> {
use hmac::{Hmac, Mac};
let mut hmac = Hmac::<sha1::Sha1>::new_from_slice(key)
.map_err(|_| StunParseError::InvalidData)?;
hmac.update(data);
Ok(hmac.finalize().into_bytes().into())
}
#[tracing::instrument(
name = "MessageIntegrity::verify",
level = "debug",
skip(data, key, expected)
)]
pub fn verify(data: &[u8], key: &[u8], expected: &[u8; 20]) -> Result<(), StunParseError> {
use hmac::{Hmac, Mac};
let mut hmac = Hmac::<sha1::Sha1>::new_from_slice(key).map_err(|_| {
error!("failed to create hmac from key data");
StunParseError::InvalidData
})?;
hmac.update(data);
hmac.verify_slice(expected).map_err(|_| {
error!("integrity check failed");
StunParseError::IntegrityCheckFailed
})
}
}
impl std::fmt::Display for MessageIntegrity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: 0x", Self::TYPE)?;
for val in self.hmac.iter() {
write!(f, "{:02x}", val)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Fingerprint {
fingerprint: [u8; 4],
}
impl Attribute for Fingerprint {
const TYPE: AttributeType = AttributeType(0x8028);
fn length(&self) -> u16 {
4
}
}
impl From<Fingerprint> for RawAttribute {
fn from(value: Fingerprint) -> RawAttribute {
let buf = bytewise_xor!(4, value.fingerprint, Fingerprint::XOR_CONSTANT, 0);
RawAttribute::new(Fingerprint::TYPE, &buf)
}
}
impl TryFrom<&RawAttribute> for Fingerprint {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 4 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 4 {
return Err(StunParseError::TooBig);
}
let boxed: Box<[u8; 4]> = raw.value.clone().into_boxed_slice().try_into().unwrap();
let fingerprint = bytewise_xor!(4, *boxed, Fingerprint::XOR_CONSTANT, 0);
Ok(Self { fingerprint })
}
}
impl Fingerprint {
const XOR_CONSTANT: [u8; 4] = [0x53, 0x54, 0x55, 0x4E];
pub fn new(fingerprint: [u8; 4]) -> Self {
Self { fingerprint }
}
pub fn fingerprint(&self) -> &[u8; 4] {
&self.fingerprint
}
pub fn compute(data: &[u8]) -> [u8; 4] {
use crc::{Crc, CRC_32_ISO_HDLC};
const CRC_ALGO: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
CRC_ALGO.checksum(data).to_be_bytes()
}
}
impl std::fmt::Display for Fingerprint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: 0x", Self::TYPE)?;
for val in self.fingerprint.iter() {
write!(f, "{:02x}", val)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Userhash {
hash: [u8; 32],
}
impl Attribute for Userhash {
const TYPE: AttributeType = AttributeType(0x001E);
fn length(&self) -> u16 {
32
}
}
impl From<Userhash> for RawAttribute {
fn from(value: Userhash) -> RawAttribute {
RawAttribute::new(Userhash::TYPE, &value.hash)
}
}
impl TryFrom<&RawAttribute> for Userhash {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 32 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 32 {
return Err(StunParseError::TooBig);
}
let hash: [u8; 32] = raw.value[..32].try_into().unwrap();
Ok(Self { hash })
}
}
impl Userhash {
pub fn new(hash: [u8; 32]) -> Self {
Self { hash }
}
pub fn hash(&self) -> &[u8; 32] {
&self.hash
}
pub fn compute(user: &str, realm: &str) -> [u8; 32] {
let data = user.to_string() + ":" + realm;
use sha2::{Digest, Sha256};
let ret = Sha256::digest(data);
ret.as_slice().try_into().unwrap()
}
}
impl std::fmt::Display for Userhash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: 0x", Self::TYPE)?;
for val in self.hash.iter() {
write!(f, "{:02x}", val)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MessageIntegritySha256 {
hmac: Vec<u8>,
}
impl Attribute for MessageIntegritySha256 {
const TYPE: AttributeType = AttributeType(0x001C);
fn length(&self) -> u16 {
self.hmac.len() as u16
}
}
impl From<MessageIntegritySha256> for RawAttribute {
fn from(value: MessageIntegritySha256) -> RawAttribute {
RawAttribute::new(MessageIntegritySha256::TYPE, &value.hmac)
}
}
impl TryFrom<&RawAttribute> for MessageIntegritySha256 {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 16 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() > 32 {
return Err(StunParseError::TooBig);
}
if raw.value.len() % 4 != 0 {
return Err(StunParseError::InvalidData);
}
Ok(Self {
hmac: raw.value.to_vec(),
})
}
}
impl MessageIntegritySha256 {
pub fn new(hmac: &[u8]) -> Result<Self, StunWriteError> {
if hmac.len() < 16 {
return Err(StunWriteError::NotEnoughData);
}
if hmac.len() > 32 {
return Err(StunWriteError::TooBig);
}
if hmac.len() % 4 != 0 {
return Err(StunWriteError::WrongPaddedSize);
}
Ok(Self {
hmac: hmac.to_vec(),
})
}
pub fn hmac(&self) -> &[u8] {
&self.hmac
}
#[tracing::instrument(
name = "MessageIntegritySha256::compute",
level = "trace",
err,
ret,
skip(data, key)
)]
pub fn compute(data: &[u8], key: &[u8]) -> Result<[u8; 32], StunParseError> {
use hmac::{Hmac, Mac};
let mut hmac = Hmac::<sha2::Sha256>::new_from_slice(key)
.map_err(|_| StunParseError::InvalidData)?;
hmac.update(data);
let ret = hmac.finalize().into_bytes();
Ok(ret.into())
}
#[tracing::instrument(
name = "MessageIntegrity::verify",
level = "debug",
skip(data, key, expected)
)]
pub fn verify(data: &[u8], key: &[u8], expected: &[u8]) -> Result<(), StunParseError> {
use hmac::{Hmac, Mac};
let mut hmac = Hmac::<sha2::Sha256>::new_from_slice(key).map_err(|_| {
error!("failed to create hmac from key data");
StunParseError::InvalidData
})?;
hmac.update(data);
hmac.verify_truncated_left(expected).map_err(|_| {
error!("integrity check failed");
StunParseError::IntegrityCheckFailed
})
}
}
impl std::fmt::Display for MessageIntegritySha256 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: 0x", Self::TYPE)?;
for val in self.hmac.iter() {
write!(f, "{:02x}", val)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Realm {
realm: String,
}
impl Attribute for Realm {
const TYPE: AttributeType = AttributeType(0x0014);
fn length(&self) -> u16 {
self.realm.len() as u16
}
}
impl From<Realm> for RawAttribute {
fn from(value: Realm) -> RawAttribute {
RawAttribute::new(Realm::TYPE, value.realm.as_bytes())
}
}
impl TryFrom<&RawAttribute> for Realm {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() > 763 {
return Err(StunParseError::TooBig);
}
Ok(Self {
realm: std::str::from_utf8(&raw.value)
.map_err(|_| StunParseError::InvalidData)?
.to_owned(),
})
}
}
impl Realm {
pub fn new(realm: &str) -> Result<Self, StunParseError> {
if realm.len() > 763 {
return Err(StunParseError::TooBig);
}
Ok(Self {
realm: realm.to_string(),
})
}
pub fn realm(&self) -> &str {
&self.realm
}
}
impl std::fmt::Display for Realm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", Self::TYPE, self.realm)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Nonce {
nonce: String,
}
impl Attribute for Nonce {
const TYPE: AttributeType = AttributeType(0x0015);
fn length(&self) -> u16 {
self.nonce.len() as u16
}
}
impl From<Nonce> for RawAttribute {
fn from(value: Nonce) -> RawAttribute {
RawAttribute::new(Nonce::TYPE, value.nonce.as_bytes())
}
}
impl TryFrom<&RawAttribute> for Nonce {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() > 763 {
return Err(StunParseError::TooBig);
}
Ok(Self {
nonce: std::str::from_utf8(&raw.value)
.map_err(|_| StunParseError::InvalidData)?
.to_owned(),
})
}
}
impl Nonce {
pub fn new(nonce: &str) -> Result<Self, StunParseError> {
if nonce.len() > 763 {
return Err(StunParseError::TooBig);
}
Ok(Self {
nonce: nonce.to_string(),
})
}
pub fn nonce(&self) -> &str {
&self.nonce
}
}
impl std::fmt::Display for Nonce {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", Self::TYPE, self.nonce)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PasswordAlgorithmValue {
MD5,
SHA256,
}
impl PasswordAlgorithmValue {
fn len(&self) -> u16 {
0
}
fn write(&self, data: &mut [u8]) {
let ty = match self {
Self::MD5 => 0x1,
Self::SHA256 => 0x2,
};
BigEndian::write_u16(&mut data[..2], ty);
BigEndian::write_u16(&mut data[2..4], self.len());
}
fn read(data: &[u8]) -> Result<Self, StunParseError> {
let ty = BigEndian::read_u16(&data[..2]);
let len = BigEndian::read_u16(&data[2..4]);
if len != 0 {
return Err(StunParseError::TooBig);
}
Ok(match ty {
0x1 => Self::MD5,
0x2 => Self::SHA256,
_ => return Err(StunParseError::OutOfRange),
})
}
}
impl std::fmt::Display for PasswordAlgorithmValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::MD5 => write!(f, "MD5"),
Self::SHA256 => write!(f, "SHA256"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PasswordAlgorithms {
algorithms: Vec<PasswordAlgorithmValue>,
}
impl Attribute for PasswordAlgorithms {
const TYPE: AttributeType = AttributeType(0x8002);
fn length(&self) -> u16 {
let mut len = 0;
for algo in self.algorithms.iter() {
len += 4 + padded_attr_len(algo.len() as usize);
}
len as u16
}
}
impl From<PasswordAlgorithms> for RawAttribute {
fn from(value: PasswordAlgorithms) -> RawAttribute {
let len = value.length() as usize;
let mut data = vec![0; len];
let mut i = 0;
for algo in value.algorithms.iter() {
algo.write(&mut data[i..]);
i += 4 + padded_attr_len(algo.len() as usize);
}
RawAttribute::new(PasswordAlgorithms::TYPE, &data)
}
}
impl TryFrom<&RawAttribute> for PasswordAlgorithms {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 4 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() % 4 != 0 {
return Err(StunParseError::InvalidData);
}
let mut i = 0;
let mut algorithms = vec![];
while i < raw.value.len() {
let algo = PasswordAlgorithmValue::read(&raw.value[i..])?;
i += 4 + padded_attr_len(algo.len() as usize);
algorithms.push(algo);
}
Ok(Self { algorithms })
}
}
impl PasswordAlgorithms {
pub fn new(algorithms: &[PasswordAlgorithmValue]) -> Self {
Self {
algorithms: algorithms.to_vec(),
}
}
pub fn algorithms(&self) -> &[PasswordAlgorithmValue] {
&self.algorithms
}
}
impl std::fmt::Display for PasswordAlgorithms {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: [", Self::TYPE)?;
for (i, algo) in self.algorithms.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", algo)?;
}
write!(f, "]")?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PasswordAlgorithm {
algorithm: PasswordAlgorithmValue,
}
impl Attribute for PasswordAlgorithm {
const TYPE: AttributeType = AttributeType(0x001D);
fn length(&self) -> u16 {
4 + padded_attr_len(self.algorithm.len() as usize) as u16
}
}
impl From<PasswordAlgorithm> for RawAttribute {
fn from(value: PasswordAlgorithm) -> RawAttribute {
let len = value.length() as usize;
let mut data = vec![0; len];
value.algorithm.write(&mut data);
RawAttribute::new(PasswordAlgorithm::TYPE, &data)
}
}
impl TryFrom<&RawAttribute> for PasswordAlgorithm {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
if raw.value.len() < 4 {
return Err(StunParseError::NotEnoughData);
}
if raw.value.len() % 4 != 0 {
return Err(StunParseError::InvalidData);
}
let algorithm = PasswordAlgorithmValue::read(&raw.value)?;
Ok(Self { algorithm })
}
}
impl PasswordAlgorithm {
pub fn new(algorithm: PasswordAlgorithmValue) -> Self {
Self { algorithm }
}
pub fn algorithm(&self) -> PasswordAlgorithmValue {
self.algorithm
}
}
impl std::fmt::Display for PasswordAlgorithm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", Self::TYPE, self.algorithm)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AddressFamily {
IPV4,
IPV6,
}
impl AddressFamily {
pub(crate) fn to_byte(self) -> u8 {
match self {
AddressFamily::IPV4 => 0x1,
AddressFamily::IPV6 => 0x2,
}
}
pub(crate) fn from_byte(byte: u8) -> Result<AddressFamily, StunParseError> {
match byte {
0x1 => Ok(AddressFamily::IPV4),
0x2 => Ok(AddressFamily::IPV6),
_ => Err(StunParseError::InvalidData),
}
}
}
impl std::fmt::Display for AddressFamily {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AddressFamily::IPV4 => write!(f, "IPV4"),
AddressFamily::IPV6 => write!(f, "IPV6"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AlternateServer {
addr: MappedSocketAddr,
}
impl Attribute for AlternateServer {
const TYPE: AttributeType = AttributeType(0x8023);
fn length(&self) -> u16 {
self.addr.length()
}
}
impl From<AlternateServer> for RawAttribute {
fn from(value: AlternateServer) -> RawAttribute {
value.addr.to_raw(AlternateServer::TYPE)
}
}
impl TryFrom<&RawAttribute> for AlternateServer {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
let addr = MappedSocketAddr::from_raw(raw)?;
Ok(Self { addr })
}
}
impl AlternateServer {
pub fn new(addr: SocketAddr) -> Self {
Self {
addr: MappedSocketAddr::new(addr),
}
}
pub fn server(&self) -> SocketAddr {
self.addr.addr
}
}
impl std::fmt::Display for AlternateServer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", AlternateServer::TYPE, self.addr)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AlternateDomain {
domain: String,
}
impl Attribute for AlternateDomain {
const TYPE: AttributeType = AttributeType(0x8003);
fn length(&self) -> u16 {
self.domain.len() as u16
}
}
impl TryFrom<&RawAttribute> for AlternateDomain {
type Error = StunParseError;
fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
if raw.header.atype != Self::TYPE {
return Err(StunParseError::WrongImplementation);
}
Ok(Self {
domain: std::str::from_utf8(&raw.value)
.map_err(|_| StunParseError::InvalidData)?
.to_owned(),
})
}
}
impl From<AlternateDomain> for RawAttribute {
fn from(value: AlternateDomain) -> RawAttribute {
RawAttribute::new(AlternateDomain::TYPE, value.domain.as_bytes())
}
}
impl AlternateDomain {
pub fn new(domain: &str) -> Self {
Self {
domain: domain.to_string(),
}
}
pub fn domain(&self) -> &str {
&self.domain
}
}
impl std::fmt::Display for AlternateDomain {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", AlternateDomain::TYPE, self.domain)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn init() {
crate::tests::test_init_log();
}
#[test]
fn attribute_type() {
init();
let atype = ErrorCode::TYPE;
let anum: u16 = atype.into();
assert_eq!(atype, anum.into());
}
#[test]
fn short_attribute_header() {
init();
let data = [0; 1];
let res: Result<AttributeHeader, _> = data.as_ref().try_into();
assert!(res.is_err());
}
#[test]
fn raw_attribute_construct() {
init();
let a = RawAttribute::new(1.into(), &[80, 160]);
assert_eq!(a.get_type(), 1.into());
let bytes: Vec<_> = a.into();
assert_eq!(bytes, &[0, 1, 0, 2, 80, 160, 0, 0]);
let b = RawAttribute::from_bytes(bytes.as_ref()).unwrap();
assert_eq!(b.get_type(), 1.into());
}
#[test]
fn raw_attribute_encoding() {
init();
let orig = RawAttribute::new(1.into(), &[80, 160]);
assert_eq!(orig.get_type(), 1.into());
let mut data: Vec<_> = orig.into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 + 1);
assert!(matches!(
RawAttribute::from_bytes(data.as_ref()),
Err(StunParseError::NotEnoughData)
));
}
#[test]
fn username() {
init();
let s = "woohoo!";
let user = Username::new(s).unwrap();
assert_eq!(user.username(), s);
assert_eq!(user.length() as usize, s.len());
let raw: RawAttribute = user.into();
assert_eq!(raw.get_type(), Username::TYPE);
let user2 = Username::try_from(&raw).unwrap();
assert_eq!(user2.username(), s);
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
Username::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn error_code() {
init();
let codes = [300, 401, 699];
for code in codes.iter().copied() {
let reason = ErrorCode::default_reason_for_code(code);
let err = ErrorCode::new(code, reason).unwrap();
assert_eq!(err.code(), code);
assert_eq!(err.reason(), reason);
let raw: RawAttribute = err.into();
assert_eq!(raw.get_type(), ErrorCode::TYPE);
let err2 = ErrorCode::try_from(&raw).unwrap();
assert_eq!(err2.code(), code);
assert_eq!(err2.reason(), reason);
}
let code = codes[0];
let reason = ErrorCode::default_reason_for_code(code);
let err = ErrorCode::new(code, reason).unwrap();
let raw: RawAttribute = err.into();
let mut data: Vec<_> = raw.clone().into();
let len = 0;
BigEndian::write_u16(&mut data[2..4], len as u16);
assert!(matches!(
ErrorCode::try_from(&RawAttribute::from_bytes(data[..len + 4].as_ref()).unwrap()),
Err(StunParseError::NotEnoughData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
ErrorCode::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn unknown_attributes() {
init();
let mut unknown = UnknownAttributes::new(&[Realm::TYPE]);
unknown.add_attribute(AlternateServer::TYPE);
unknown.add_attribute(AlternateServer::TYPE);
assert!(unknown.has_attribute(Realm::TYPE));
assert!(unknown.has_attribute(AlternateServer::TYPE));
assert!(!unknown.has_attribute(Nonce::TYPE));
let raw: RawAttribute = unknown.into();
assert_eq!(raw.get_type(), UnknownAttributes::TYPE);
let unknown2 = UnknownAttributes::try_from(&raw).unwrap();
assert!(unknown2.has_attribute(Realm::TYPE));
assert!(unknown2.has_attribute(AlternateServer::TYPE));
assert!(!unknown2.has_attribute(Nonce::TYPE));
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
UnknownAttributes::try_from(
&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()
),
Err(StunParseError::InvalidData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
UnknownAttributes::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn software() {
init();
let software = Software::new("software").unwrap();
assert_eq!(software.software(), "software");
let raw: RawAttribute = software.into();
assert_eq!(raw.get_type(), Software::TYPE);
let software2 = Software::try_from(&raw).unwrap();
assert_eq!(software2.software(), "software");
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
Software::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn xor_mapped_address() {
init();
let transaction_id = 0x9876_5432_1098_7654_3210_9876.into();
let addrs = &[
"192.168.0.1:40000".parse().unwrap(),
"[fd12:3456:789a:1::1]:41000".parse().unwrap(),
];
for addr in addrs {
let mapped = XorMappedAddress::new(*addr, transaction_id);
assert_eq!(mapped.addr(transaction_id), *addr);
let raw: RawAttribute = mapped.into();
assert_eq!(raw.get_type(), XorMappedAddress::TYPE);
let mapped2 = XorMappedAddress::try_from(&raw).unwrap();
assert_eq!(mapped2.addr(transaction_id), *addr);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
XorMappedAddress::try_from(
&RawAttribute::try_from(data[..len - 1].as_ref()).unwrap()
),
Err(StunParseError::NotEnoughData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
XorMappedAddress::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
}
#[test]
fn priority() {
init();
let val = 100;
let priority = Priority::new(val);
assert_eq!(priority.priority(), val);
let raw: RawAttribute = priority.into();
assert_eq!(raw.get_type(), Priority::TYPE);
let mapped2 = Priority::try_from(&raw).unwrap();
assert_eq!(mapped2.priority(), val);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
Priority::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
Err(StunParseError::NotEnoughData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
Priority::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn use_candidate() {
init();
let use_candidate = UseCandidate::new();
assert_eq!(use_candidate.length(), 0);
let raw: RawAttribute = use_candidate.into();
assert_eq!(raw.get_type(), UseCandidate::TYPE);
let _mapped2 = UseCandidate::try_from(&raw).unwrap();
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
UseCandidate::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn ice_controlling() {
init();
let tb = 100;
let attr = IceControlling::new(tb);
assert_eq!(attr.tie_breaker(), tb);
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), IceControlling::TYPE);
let mapped2 = IceControlling::try_from(&raw).unwrap();
assert_eq!(mapped2.tie_breaker(), tb);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
IceControlling::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
Err(StunParseError::NotEnoughData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
IceControlling::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn ice_controlled() {
init();
let tb = 100;
let attr = IceControlled::new(tb);
assert_eq!(attr.tie_breaker(), tb);
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), IceControlled::TYPE);
let mapped2 = IceControlled::try_from(&raw).unwrap();
assert_eq!(mapped2.tie_breaker(), tb);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
IceControlled::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
Err(StunParseError::NotEnoughData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
IceControlled::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn fingerprint() {
init();
let val = [1; 4];
let attr = Fingerprint::new(val);
assert_eq!(attr.fingerprint(), &val);
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), Fingerprint::TYPE);
let mapped2 = Fingerprint::try_from(&raw).unwrap();
assert_eq!(mapped2.fingerprint(), &val);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
Fingerprint::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
Err(StunParseError::NotEnoughData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
Fingerprint::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn message_integrity() {
init();
let val = [1; 20];
let attr = MessageIntegrity::new(val);
assert_eq!(attr.hmac(), &val);
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), MessageIntegrity::TYPE);
let mapped2 = MessageIntegrity::try_from(&raw).unwrap();
assert_eq!(mapped2.hmac(), &val);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
MessageIntegrity::try_from(
&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()
),
Err(StunParseError::NotEnoughData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
MessageIntegrity::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn userhash() {
init();
let hash = Userhash::compute("username", "realm1");
let attr = Userhash::new(hash);
assert_eq!(attr.hash(), &hash);
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), Userhash::TYPE);
let mapped2 = Userhash::try_from(&raw).unwrap();
assert_eq!(mapped2.hash(), &hash);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
Userhash::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
Err(StunParseError::NotEnoughData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
Userhash::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn message_integrity_sha256() {
init();
let val = [1; 32];
let attr = MessageIntegritySha256::new(&val).unwrap();
assert_eq!(attr.hmac(), &val);
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), MessageIntegritySha256::TYPE);
let mapped2 = MessageIntegritySha256::try_from(&raw).unwrap();
assert_eq!(mapped2.hmac(), &val);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
MessageIntegritySha256::try_from(
&RawAttribute::try_from(data[..len - 1].as_ref()).unwrap()
),
Err(StunParseError::InvalidData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
MessageIntegritySha256::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn realm() {
init();
let attr = Realm::new("realm").unwrap();
assert_eq!(attr.realm(), "realm");
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), Realm::TYPE);
let mapped2 = Realm::try_from(&raw).unwrap();
assert_eq!(mapped2.realm(), "realm");
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
Realm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn nonce() {
init();
let attr = Nonce::new("nonce").unwrap();
assert_eq!(attr.nonce(), "nonce");
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), Nonce::TYPE);
let mapped2 = Nonce::try_from(&raw).unwrap();
assert_eq!(mapped2.nonce(), "nonce");
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
Nonce::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn password_algorithms() {
init();
let vals = [PasswordAlgorithmValue::MD5, PasswordAlgorithmValue::SHA256];
let attr = PasswordAlgorithms::new(&vals);
assert_eq!(attr.algorithms(), &vals);
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), PasswordAlgorithms::TYPE);
let mapped2 = PasswordAlgorithms::try_from(&raw).unwrap();
assert_eq!(mapped2.algorithms(), &vals);
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
PasswordAlgorithms::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn password_algorithm() {
init();
let val = PasswordAlgorithmValue::SHA256;
let attr = PasswordAlgorithm::new(val);
assert_eq!(attr.algorithm(), val);
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), PasswordAlgorithm::TYPE);
let mapped2 = PasswordAlgorithm::try_from(&raw).unwrap();
assert_eq!(mapped2.algorithm(), val);
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
PasswordAlgorithm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
#[test]
fn alternate_server() {
init();
let addrs = &[
"192.168.0.1:40000".parse().unwrap(),
"[fd12:3456:789a:1::1]:41000".parse().unwrap(),
];
for addr in addrs {
let mapped = AlternateServer::new(*addr);
assert_eq!(mapped.server(), *addr);
let raw: RawAttribute = mapped.into();
assert_eq!(raw.get_type(), AlternateServer::TYPE);
let mapped2 = AlternateServer::try_from(&raw).unwrap();
assert_eq!(mapped2.server(), *addr);
let mut data: Vec<_> = raw.clone().into();
let len = data.len();
BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
assert!(matches!(
AlternateServer::try_from(
&RawAttribute::try_from(data[..len - 1].as_ref()).unwrap()
),
Err(StunParseError::NotEnoughData)
));
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
AlternateServer::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
}
#[test]
fn alternative_domain() {
init();
let dns = "example.com";
let attr = AlternateDomain::new(dns);
assert_eq!(attr.domain(), dns);
let raw: RawAttribute = attr.into();
assert_eq!(raw.get_type(), AlternateDomain::TYPE);
let mapped2 = AlternateDomain::try_from(&raw).unwrap();
assert_eq!(mapped2.domain(), dns);
let mut data: Vec<_> = raw.into();
BigEndian::write_u16(&mut data[0..2], 0);
assert!(matches!(
AlternateDomain::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
Err(StunParseError::WrongImplementation)
));
}
}