mirror of
https://github.com/pradt2/always-online-stun.git
synced 2025-09-26 19:41:34 +08:00
WIP towards Geo information
This commit is contained in:
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -15,7 +15,6 @@ dependencies = [
|
||||
name = "always-online-stun"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitwise",
|
||||
"futures",
|
||||
"log",
|
||||
"pretty_env_logger",
|
||||
@@ -56,20 +55,6 @@ version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bitintr"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ba5a5c4df8ac8673f22698f443ef1ce3853d7f22d5a15ebf66b9a7553b173dd"
|
||||
|
||||
[[package]]
|
||||
name = "bitwise"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"bitintr",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "build_const"
|
||||
version = "0.2.2"
|
||||
@@ -695,15 +680,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.20.4"
|
||||
@@ -741,21 +717,6 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.136"
|
||||
|
@@ -6,7 +6,6 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bitwise = { path = "../bitwise", default-features = false }
|
||||
futures = { version = "0.3.17" }
|
||||
log = { version = "0.4.16" }
|
||||
pretty_env_logger = { version = "0.4.0" }
|
||||
|
@@ -51,12 +51,10 @@ impl IpGeolocationIoClient {
|
||||
.map_err(|err| io::Error::new(ErrorKind::Other, err))?;
|
||||
|
||||
let lat = response.get("latitude")
|
||||
.cloned()
|
||||
.map(|lat_str| lat_str.parse().unwrap())
|
||||
.unwrap_or(0 as f32);
|
||||
|
||||
let lon = response.get("longitude")
|
||||
.cloned()
|
||||
.map(|lon_str| lon_str.parse().unwrap())
|
||||
.unwrap_or(0 as f32);
|
||||
|
||||
|
@@ -12,7 +12,7 @@ use crate::utils::join_all_with_semaphore;
|
||||
use crate::outputs::{ValidHosts, ValidIpV4s, ValidIpV6s};
|
||||
use crate::servers::StunServer;
|
||||
use crate::stun::{StunServerTestResult, StunSocketResponse};
|
||||
use crate::stun_client_2::{Attribute, GenericAttrReader, NonParsableAttribute};
|
||||
use crate::stun_codec::{Attribute, NonParsableAttribute};
|
||||
|
||||
extern crate pretty_env_logger;
|
||||
#[macro_use] extern crate log;
|
||||
@@ -23,8 +23,7 @@ mod utils;
|
||||
mod outputs;
|
||||
mod geoip;
|
||||
mod git;
|
||||
mod stun_client;
|
||||
mod stun_client_2;
|
||||
mod stun_codec;
|
||||
|
||||
const CONCURRENT_SOCKETS_USED_LIMIT: usize = 64;
|
||||
|
||||
@@ -45,7 +44,7 @@ async fn get_stun_response(addr: &str) -> io::Result<()> {
|
||||
|
||||
let bytes_read = bytes_read.unwrap();
|
||||
|
||||
let r = stun_client_2::StunMessageReader { bytes: buf[0..bytes_read].as_ref() };
|
||||
let r = stun_codec::StunMessageReader { bytes: buf[0..bytes_read].as_ref() };
|
||||
info!("Method {:?} , Class {:?}", r.get_method().unwrap(), r.get_class());
|
||||
r.get_attrs().for_each(|attr| {
|
||||
match &attr {
|
||||
|
@@ -1,492 +0,0 @@
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::format;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum MessageClass {
|
||||
Request,
|
||||
Indirection,
|
||||
SuccessResponse,
|
||||
ErrorResponse
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Method {
|
||||
Binding
|
||||
}
|
||||
|
||||
struct StunHeaderReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum StunReaderError {
|
||||
NotEnoughBytes {
|
||||
expected: usize,
|
||||
actual: usize,
|
||||
},
|
||||
UnknownMethod {
|
||||
code: u16
|
||||
},
|
||||
UnknownAddressFamily {
|
||||
code: u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum AddressFamily {
|
||||
Ipv4,
|
||||
Ipv6,
|
||||
}
|
||||
|
||||
type StunReaderResult<T> = Result<T, StunReaderError>;
|
||||
|
||||
impl StunHeaderReader<'_> {
|
||||
const HEADER_SIZE: usize = 20;
|
||||
|
||||
fn new(bytes: &[u8]) -> StunReaderResult<StunHeaderReader> {
|
||||
if bytes.len() < StunHeaderReader::HEADER_SIZE {
|
||||
Err(StunReaderError::NotEnoughBytes {
|
||||
expected: StunHeaderReader::HEADER_SIZE,
|
||||
actual: bytes.len(),
|
||||
})
|
||||
} else {
|
||||
Ok(StunHeaderReader { bytes: &bytes[0..20] })
|
||||
}
|
||||
}
|
||||
|
||||
fn get_message_type(&self) -> u16 {
|
||||
let msg_type: u16 = u16::from_be_bytes(self.bytes[0..2].try_into().unwrap() );
|
||||
msg_type
|
||||
}
|
||||
|
||||
fn get_class(&self) -> MessageClass {
|
||||
let msg_type = self.get_message_type();
|
||||
let mut class: u16 = 0;
|
||||
class = bitwise::copy_bit(msg_type, 4u8, class, 0u8);
|
||||
class = bitwise::copy_bit(msg_type, 8u8, class, 1u8);
|
||||
match class {
|
||||
0 => MessageClass::Request,
|
||||
1 => MessageClass::Indirection,
|
||||
2 => MessageClass::SuccessResponse,
|
||||
3 => MessageClass::ErrorResponse,
|
||||
_ => panic!("Impossible message class")
|
||||
}
|
||||
}
|
||||
|
||||
fn get_method(&self) -> StunReaderResult<Method> {
|
||||
let msg_type = self.get_message_type();
|
||||
let method_code: u16 = bitwise::extract_bits(msg_type, 0u8, 4u8)
|
||||
| bitwise::extract_bits(msg_type, 4u8, 3u8)
|
||||
| bitwise::extract_bits(msg_type, 9u8, 5u8);
|
||||
match method_code {
|
||||
1 => Ok(Method::Binding),
|
||||
_ => Err(StunReaderError::UnknownMethod { code: method_code })
|
||||
}
|
||||
}
|
||||
|
||||
fn get_length(&self) -> u16 {
|
||||
let length: u16 = u16::from_be_bytes(self.bytes[2..4].try_into().unwrap());
|
||||
length
|
||||
}
|
||||
|
||||
fn get_cookie(&self) -> u32 {
|
||||
let cookie: u32 = u32::from_be_bytes(self.bytes[4..8].try_into().unwrap());
|
||||
cookie
|
||||
}
|
||||
|
||||
fn get_transaction_id(&self) -> (u32, u32, u32) {
|
||||
let transaction_id = (u32::from_ne_bytes(self.bytes[8..12].try_into().unwrap()),
|
||||
u32::from_ne_bytes(self.bytes[12..16].try_into().unwrap()),
|
||||
u32::from_ne_bytes(self.bytes[16..20].try_into().unwrap()));
|
||||
transaction_id
|
||||
}
|
||||
|
||||
fn get_used_bytes(&self) -> u16 {
|
||||
20
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!("Method: {:?} , Class {:?}\n", self.get_method(), self.get_class())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_attr_length(bytes: &[u8]) -> u16 {
|
||||
let length = u16::from_be_bytes(bytes[2..4].try_into().unwrap());
|
||||
length
|
||||
}
|
||||
|
||||
fn get_attr_length_padded(bytes: &[u8]) -> u16 {
|
||||
let length_padded = (get_attr_length(bytes) + 4 - 1) & (-4i16 as u16); // bring attr length to the nearest multiple of 4 to account for padding
|
||||
length_padded
|
||||
}
|
||||
|
||||
fn get_attr_type(bytes: &[u8]) -> u16 {
|
||||
let typ = u16::from_be_bytes(bytes[0..2].try_into().unwrap());
|
||||
typ
|
||||
}
|
||||
|
||||
struct MappedAddressReader<'a> {
|
||||
bytes: &'a [u8]
|
||||
}
|
||||
|
||||
impl MappedAddressReader<'_> {
|
||||
fn supports(bytes: &[u8]) -> bool {
|
||||
let supports = if bytes.len() < 2 { false } else { get_attr_type(bytes) == 0x0001 };
|
||||
supports
|
||||
}
|
||||
|
||||
fn new(bytes: &[u8]) -> StunReaderResult<MappedAddressReader> {
|
||||
if bytes.len() < 12 {
|
||||
Err(StunReaderError::NotEnoughBytes { expected: 12, actual: bytes.len() })
|
||||
} else {
|
||||
let reader = MappedAddressReader { bytes };
|
||||
if reader.get_family()? == AddressFamily::Ipv6 && bytes.len() < 24 {
|
||||
Err(StunReaderError::NotEnoughBytes { expected: 24, actual: bytes.len() })
|
||||
} else {
|
||||
Ok(reader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_family(&self) -> StunReaderResult<AddressFamily> {
|
||||
let family = self.bytes[5];
|
||||
match family {
|
||||
1 => Ok(AddressFamily::Ipv4),
|
||||
2 => Ok(AddressFamily::Ipv6),
|
||||
_ => Err(StunReaderError::UnknownAddressFamily { code: family })
|
||||
}
|
||||
}
|
||||
|
||||
fn get_port(&self) -> u16 {
|
||||
let port: u16 = u16::from_be_bytes(self.bytes[6..8].try_into().unwrap());
|
||||
port
|
||||
}
|
||||
|
||||
fn get_addr(&self) -> StunReaderResult<IpAddr> {
|
||||
match self.get_family()? {
|
||||
AddressFamily::Ipv4 => {
|
||||
let ip_num= u32::from_be_bytes(self.bytes[8..12].try_into().unwrap());
|
||||
Ok(IpAddr::V4(Ipv4Addr::from(ip_num)))
|
||||
},
|
||||
AddressFamily::Ipv6 => {
|
||||
let ip_num = u128::from_be_bytes(self.bytes[8..24].try_into().unwrap());
|
||||
Ok(IpAddr::V6(Ipv6Addr::from(ip_num)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_used_bytes(&self) -> u16 {
|
||||
let used_bytes = 4 + get_attr_length_padded(self.bytes);
|
||||
used_bytes
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!("MappedAddress {:?}", SocketAddr::new(self.get_addr().unwrap(), self.get_port()))
|
||||
}
|
||||
}
|
||||
|
||||
struct AnyAttributeReader<'a> {
|
||||
bytes: &'a [u8]
|
||||
}
|
||||
|
||||
impl AnyAttributeReader<'_> {
|
||||
fn supports(bytes: &[u8]) -> bool {
|
||||
let supports = if bytes.len() < 2 { false } else { true };
|
||||
supports
|
||||
}
|
||||
|
||||
fn new(bytes: &[u8]) -> StunReaderResult<AnyAttributeReader> {
|
||||
if bytes.len() < 2 {
|
||||
Err(StunReaderError::NotEnoughBytes { expected: 12, actual: bytes.len() })
|
||||
} else {
|
||||
let reader = AnyAttributeReader { bytes };
|
||||
Ok(reader)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_used_bytes(&self) -> u16 {
|
||||
let used_bytes = 4 + get_attr_length_padded(self.bytes);
|
||||
used_bytes
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!("AnyAttribute type {:04x} len {} bytes {:?}", get_attr_type(self.bytes), get_attr_length(self.bytes), &self.bytes[4..get_attr_length_padded(self.bytes) as usize] )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// RFC 5780
|
||||
struct ResponseOriginReader<'a> {
|
||||
bytes: &'a [u8]
|
||||
}
|
||||
|
||||
impl ResponseOriginReader<'_> {
|
||||
fn supports(bytes: &[u8]) -> bool {
|
||||
let supports = if bytes.len() < 2 { false } else { get_attr_type(bytes) == 0x802b };
|
||||
supports
|
||||
}
|
||||
|
||||
fn new(bytes: &[u8]) -> StunReaderResult<ResponseOriginReader> {
|
||||
if bytes.len() < 12 {
|
||||
Err(StunReaderError::NotEnoughBytes { expected: 12, actual: bytes.len() })
|
||||
} else {
|
||||
let reader = ResponseOriginReader { bytes };
|
||||
if reader.get_family()? == AddressFamily::Ipv6 && bytes.len() < 24 {
|
||||
Err(StunReaderError::NotEnoughBytes { expected: 24, actual: bytes.len() })
|
||||
} else {
|
||||
Ok(reader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_family(&self) -> StunReaderResult<AddressFamily> {
|
||||
let family = self.bytes[5];
|
||||
match family {
|
||||
1 => Ok(AddressFamily::Ipv4),
|
||||
2 => Ok(AddressFamily::Ipv6),
|
||||
_ => Err(StunReaderError::UnknownAddressFamily { code: family })
|
||||
}
|
||||
}
|
||||
|
||||
fn get_port(&self) -> u16 {
|
||||
let port: u16 = u16::from_be_bytes(self.bytes[6..8].try_into().unwrap());
|
||||
port
|
||||
}
|
||||
|
||||
fn get_addr(&self) -> StunReaderResult<IpAddr> {
|
||||
match self.get_family()? {
|
||||
AddressFamily::Ipv4 => {
|
||||
let octets: [u8; 4] = self.bytes[8..12].try_into().unwrap();
|
||||
Ok(IpAddr::V4(Ipv4Addr::from(octets)))
|
||||
},
|
||||
AddressFamily::Ipv6 => {
|
||||
let octets: [u8; 16] = self.bytes[8..24].try_into().unwrap();
|
||||
Ok(IpAddr::V6(Ipv6Addr::from(octets)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_used_bytes(&self) -> u16 {
|
||||
let used_bytes = 4 + get_attr_length_padded(self.bytes);
|
||||
used_bytes
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!("ResponseOrigin {:?}", SocketAddr::new(self.get_addr().unwrap(), self.get_port()))
|
||||
}
|
||||
}
|
||||
|
||||
struct XorMappedAddressReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
transaction_id: &'a (u32, u32, u32),
|
||||
}
|
||||
|
||||
impl XorMappedAddressReader<'_> {
|
||||
fn supports(bytes: &[u8]) -> bool {
|
||||
let supports = if bytes.len() < 2 { false } else { get_attr_type(bytes) == 0x0020 };
|
||||
supports
|
||||
}
|
||||
|
||||
fn new<'a>(bytes: &'a [u8], transaction_id: &'a (u32, u32, u32)) -> StunReaderResult<XorMappedAddressReader<'a>> {
|
||||
if bytes.len() < 12 {
|
||||
Err(StunReaderError::NotEnoughBytes { expected: 12, actual: bytes.len() })
|
||||
} else {
|
||||
let reader = XorMappedAddressReader { bytes , transaction_id };
|
||||
if reader.get_family()? == AddressFamily::Ipv6 && bytes.len() < 24 {
|
||||
Err(StunReaderError::NotEnoughBytes { expected: 24, actual: bytes.len() })
|
||||
} else {
|
||||
Ok(reader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_family(&self) -> StunReaderResult<AddressFamily> {
|
||||
let family = self.bytes[5];
|
||||
match family {
|
||||
1 => Ok(AddressFamily::Ipv4),
|
||||
2 => Ok(AddressFamily::Ipv6),
|
||||
_ => Err(StunReaderError::UnknownAddressFamily { code: family })
|
||||
}
|
||||
}
|
||||
|
||||
fn get_port(&self) -> u16 {
|
||||
let port: u16 = u16::from_be_bytes(self.bytes[6..8].try_into().unwrap()) ^ 0x2112; // xor with top half of magic cookie
|
||||
port
|
||||
}
|
||||
|
||||
fn get_addr(&self) -> StunReaderResult<IpAddr> {
|
||||
match self.get_family()? {
|
||||
AddressFamily::Ipv4 => {
|
||||
let ip_num = u32::from_be_bytes(self.bytes[8..12].try_into().unwrap()) ^ 0x2112A442; // xor with magic cookie
|
||||
Ok(IpAddr::V4(Ipv4Addr::from(ip_num)))
|
||||
},
|
||||
AddressFamily::Ipv6 => {
|
||||
let t_id = self.transaction_id;
|
||||
let ip_num = u128::from_be_bytes(self.bytes[8..24].try_into().unwrap()) ^ (0x2112A442_u128 << 92 | (t_id.2 as u128) << 64 | (t_id.1 as u128) << 32 | t_id.0 as u128);
|
||||
Ok(IpAddr::V6(Ipv6Addr::from(ip_num)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_used_bytes(&self) -> u16 {
|
||||
let used_bytes = 4 + get_attr_length_padded(self.bytes);
|
||||
used_bytes
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!("XorMappedAddress {:?}", SocketAddr::new(self.get_addr().unwrap(), self.get_port()))
|
||||
}
|
||||
}
|
||||
|
||||
struct ComprehensionOptionalXorMappedAddressReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
transaction_id: &'a (u32, u32, u32),
|
||||
}
|
||||
|
||||
impl ComprehensionOptionalXorMappedAddressReader<'_> {
|
||||
fn supports(bytes: &[u8]) -> bool {
|
||||
let supports = if bytes.len() < 2 { false } else { get_attr_type(bytes) == 0x8020 };
|
||||
supports
|
||||
}
|
||||
|
||||
fn new<'a>(bytes: &'a [u8], transaction_id: &'a (u32, u32, u32)) -> StunReaderResult<ComprehensionOptionalXorMappedAddressReader<'a>> {
|
||||
if bytes.len() < 12 {
|
||||
Err(StunReaderError::NotEnoughBytes { expected: 12, actual: bytes.len() })
|
||||
} else {
|
||||
let reader = ComprehensionOptionalXorMappedAddressReader { bytes , transaction_id };
|
||||
if reader.get_family()? == AddressFamily::Ipv6 && bytes.len() < 24 {
|
||||
Err(StunReaderError::NotEnoughBytes { expected: 24, actual: bytes.len() })
|
||||
} else {
|
||||
Ok(reader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_family(&self) -> StunReaderResult<AddressFamily> {
|
||||
let family = self.bytes[5];
|
||||
match family {
|
||||
1 => Ok(AddressFamily::Ipv4),
|
||||
2 => Ok(AddressFamily::Ipv6),
|
||||
_ => Err(StunReaderError::UnknownAddressFamily { code: family })
|
||||
}
|
||||
}
|
||||
|
||||
fn get_port(&self) -> u16 {
|
||||
let port: u16 = u16::from_be_bytes(self.bytes[6..8].try_into().unwrap()) ^ 0x2112; // xor with top half of magic cookie
|
||||
port
|
||||
}
|
||||
|
||||
fn get_addr(&self) -> StunReaderResult<IpAddr> {
|
||||
match self.get_family()? {
|
||||
AddressFamily::Ipv4 => {
|
||||
let ip_num = u32::from_be_bytes(self.bytes[8..12].try_into().unwrap()) ^ 0x2112A442; // xor with magic cookie
|
||||
Ok(IpAddr::V4(Ipv4Addr::from(ip_num)))
|
||||
},
|
||||
AddressFamily::Ipv6 => {
|
||||
let t_id = self.transaction_id;
|
||||
let ip_num = u128::from_be_bytes(self.bytes[8..24].try_into().unwrap()) ^ (0x2112A442_u128 << 92 | (t_id.2 as u128) << 64 | (t_id.1 as u128) << 32 | t_id.0 as u128);
|
||||
Ok(IpAddr::V6(Ipv6Addr::from(ip_num)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_used_bytes(&self) -> u16 {
|
||||
let used_bytes = 4 + get_attr_length_padded(self.bytes);
|
||||
used_bytes
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!("ComprehensionOptionalXorMappedAddress {:?}", SocketAddr::new(self.get_addr().unwrap(), self.get_port()))
|
||||
}
|
||||
}
|
||||
|
||||
enum RfcSpec {
|
||||
Rfc3489,
|
||||
Rfc5245,
|
||||
Rfc5389,
|
||||
Rfc5766,
|
||||
Rfc5780
|
||||
}
|
||||
|
||||
enum MessageAttribute {
|
||||
Reserved0x0000,
|
||||
MappedAddress,
|
||||
ResponseAddress,
|
||||
ChangeAddress,
|
||||
SourceAddress,
|
||||
ChangedAddress,
|
||||
Username,
|
||||
Password,
|
||||
MessageIntegrity,
|
||||
ErrorCode,
|
||||
UnknownAttribute,
|
||||
ReflectedFrom,
|
||||
Realm,
|
||||
Nonce,
|
||||
XorMappedAddress,
|
||||
OptXorMappedAddress,
|
||||
Software,
|
||||
AlternateServer,
|
||||
Fingerprint
|
||||
}
|
||||
|
||||
impl MessageAttribute {
|
||||
fn get_code(&self) -> u16 {
|
||||
match self {
|
||||
MessageAttribute::Reserved0x0000 => { 0x0000 }
|
||||
MessageAttribute::MappedAddress => { 0x0001 }
|
||||
MessageAttribute::ResponseAddress => { 0x0002 }
|
||||
MessageAttribute::ChangeAddress => { 0x0003 }
|
||||
MessageAttribute::SourceAddress => { 0x0004 }
|
||||
MessageAttribute::ChangedAddress => { 0x0005 }
|
||||
MessageAttribute::Username => { 0x0006 }
|
||||
MessageAttribute::Password => { 0x0007 }
|
||||
MessageAttribute::MessageIntegrity => { 0x0008 }
|
||||
MessageAttribute::ErrorCode => { 0x0009 }
|
||||
MessageAttribute::UnknownAttribute => { 0x000A }
|
||||
MessageAttribute::ReflectedFrom => { 0x000B }
|
||||
MessageAttribute::Realm => { 0x0014 }
|
||||
MessageAttribute::Nonce => { 0x0015 }
|
||||
MessageAttribute::XorMappedAddress => { 0x0020 }
|
||||
MessageAttribute::OptXorMappedAddress => { 0x8020 }
|
||||
MessageAttribute::Software => { 0x8022 }
|
||||
MessageAttribute::AlternateServer => { 0x8023 }
|
||||
MessageAttribute::Fingerprint => { 0x8028 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_stun_message(bytes: &[u8]) {
|
||||
|
||||
let r = StunHeaderReader::new(bytes).unwrap();
|
||||
println!("{}", r.to_string());
|
||||
let mut bytes = &bytes[r.get_used_bytes() as usize ..];
|
||||
let t_id = r.get_transaction_id();
|
||||
loop {
|
||||
if MappedAddressReader::supports(bytes) {
|
||||
let r = MappedAddressReader::new(bytes).unwrap();
|
||||
println!("{}", r.to_string());
|
||||
bytes = &bytes[r.get_used_bytes() as usize ..];
|
||||
} else if XorMappedAddressReader::supports(bytes) {
|
||||
let r = XorMappedAddressReader::new(bytes, &t_id).unwrap();
|
||||
println!("{}", r.to_string());
|
||||
bytes = &bytes[r.get_used_bytes() as usize ..];
|
||||
} else if ResponseOriginReader::supports(bytes) {
|
||||
let r = ResponseOriginReader::new(bytes).unwrap();
|
||||
println!("{}", r.to_string());
|
||||
bytes = &bytes[r.get_used_bytes() as usize ..];
|
||||
} else if ComprehensionOptionalXorMappedAddressReader::supports(bytes) {
|
||||
let r = ComprehensionOptionalXorMappedAddressReader::new(bytes, &t_id).unwrap();
|
||||
println!("{}", r.to_string());
|
||||
bytes = &bytes[r.get_used_bytes() as usize ..];
|
||||
} else if AnyAttributeReader::supports(bytes) {
|
||||
let r = AnyAttributeReader::new(bytes).unwrap();
|
||||
println!("{}", r.to_string());
|
||||
bytes = &bytes[r.get_used_bytes() as usize ..];
|
||||
} else {
|
||||
println!("Bytes left {}", bytes.len());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
1274
src/stun_client_2.rs
1274
src/stun_client_2.rs
File diff suppressed because it is too large
Load Diff
50
src/stun_codec/attrs/alternate_server.rs
Normal file
50
src/stun_codec/attrs/alternate_server.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use std::net::IpAddr;
|
||||
use super::mapped_address::MappedAddressAttributeReader;
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct AlternateServerAttributeReader<'a> {
|
||||
mapped_address_reader: MappedAddressAttributeReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> AlternateServerAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
mapped_address_reader: MappedAddressAttributeReader::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
self.mapped_address_reader.get_address_family()
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.mapped_address_reader.get_address_family_raw()
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.mapped_address_reader.get_port()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
self.mapped_address_reader.get_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for AlternateServerAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.mapped_address_reader.get_bytes()
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc5389
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
38
src/stun_codec/attrs/base/malformed.rs
Normal file
38
src/stun_codec/attrs/base/malformed.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use std::cmp::min;
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub struct MalformedAttrReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> MalformedAttrReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_type_raw(&self) -> u16 {
|
||||
match self.bytes.len() {
|
||||
0 => 0,
|
||||
1 => u8::from_be(self.bytes[0]) as u16,
|
||||
_ => u16::from_be_bytes(self.bytes[0..2].try_into().unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value_length_raw(&self) -> u16 {
|
||||
match self.bytes.len() {
|
||||
0 | 1 | 2 | 3 | 4 => 0,
|
||||
_ => u16::from_be_bytes(self.bytes[2..4].try_into().unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value_raw(&self) -> &[u8] {
|
||||
match self.bytes.len() {
|
||||
0 | 1 | 2 | 3 | 4 => &self.bytes[0..0],
|
||||
_ => {
|
||||
let length_raw = self.get_value_length_raw() as usize;
|
||||
let target_value_size = min(length_raw, self.bytes.len() - 4) / 4;
|
||||
&self.bytes[5..target_value_size]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
src/stun_codec/attrs/base/mod.rs
Normal file
7
src/stun_codec/attrs/base/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
mod malformed;
|
||||
mod unknown;
|
||||
mod shared;
|
||||
|
||||
pub use malformed::*;
|
||||
pub use unknown::*;
|
||||
pub use shared::*;
|
40
src/stun_codec/attrs/base/shared.rs
Normal file
40
src/stun_codec/attrs/base/shared.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use std::convert::TryInto;
|
||||
use super::malformed::MalformedAttrReader;
|
||||
use super::unknown::UnknownAttrReader;
|
||||
use super::super::super::enums::{ComplianceError, ComprehensionCategory, RfcSpec};
|
||||
|
||||
pub enum NonParsableAttribute<'a> {
|
||||
Unknown(UnknownAttrReader<'a>),
|
||||
Malformed(MalformedAttrReader<'a>),
|
||||
}
|
||||
|
||||
pub trait GenericAttrReader {
|
||||
fn get_bytes(&self) -> &[u8];
|
||||
|
||||
fn get_value_raw(&self) -> &[u8] {
|
||||
&self.get_bytes()[4..(self.get_value_length() as usize)]
|
||||
}
|
||||
|
||||
fn get_type_raw(&self) -> u16 {
|
||||
u16::from_be_bytes(self.get_bytes()[0..2].try_into().unwrap())
|
||||
}
|
||||
|
||||
fn get_value_length(&self) -> u16 {
|
||||
u16::from_be_bytes(self.get_bytes()[2..4].try_into().unwrap())
|
||||
}
|
||||
|
||||
fn get_total_length(&self) -> u16 {
|
||||
4 + ((self.get_value_length() + 4 - 1) & (-4i16 as u16))
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec;
|
||||
|
||||
fn get_comprehension_category(&self) -> ComprehensionCategory {
|
||||
let typ = self.get_type_raw();
|
||||
if typ <= 0x7FFF { ComprehensionCategory::Required } else { ComprehensionCategory::Optional }
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError>;
|
||||
|
||||
fn is_deprecated(&self) -> bool;
|
||||
}
|
31
src/stun_codec/attrs/base/unknown.rs
Normal file
31
src/stun_codec/attrs/base/unknown.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use std::convert::TryInto;
|
||||
use super::super::super::enums::ComprehensionCategory;
|
||||
|
||||
pub struct UnknownAttrReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> UnknownAttrReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_value_raw(&self) -> &[u8] {
|
||||
&self.bytes[4..(self.get_value_length() as usize)]
|
||||
}
|
||||
|
||||
pub fn get_type_raw(&self) -> u16 {
|
||||
u16::from_be_bytes(self.bytes[0..2].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn get_comprehension_category(&self) -> ComprehensionCategory {
|
||||
let typ = self.get_type_raw();
|
||||
if typ <= 0x7FFF { ComprehensionCategory::Required } else { ComprehensionCategory::Optional }
|
||||
}
|
||||
|
||||
pub fn get_value_length(&self) -> u16 {
|
||||
u16::from_be_bytes(self.bytes[2..4].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn get_total_length(&self) -> u16 { 4 + ((self.get_value_length() + 4 - 1) & (-4i16 as u16)) }
|
||||
}
|
51
src/stun_codec/attrs/change_address.rs
Normal file
51
src/stun_codec/attrs/change_address.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use std::net::IpAddr;
|
||||
|
||||
use super::base::GenericAttrReader;
|
||||
use super::mapped_address::MappedAddressAttributeReader;
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
|
||||
pub struct ChangeAddressAttributeReader<'a> {
|
||||
mapped_address_reader: MappedAddressAttributeReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ChangeAddressAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
mapped_address_reader: MappedAddressAttributeReader::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
self.mapped_address_reader.get_address_family()
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.mapped_address_reader.get_address_family_raw()
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.mapped_address_reader.get_port()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
self.mapped_address_reader.get_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for ChangeAddressAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.mapped_address_reader.get_bytes()
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
50
src/stun_codec/attrs/changed_address.rs
Normal file
50
src/stun_codec/attrs/changed_address.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use std::net::IpAddr;
|
||||
use super::mapped_address::MappedAddressAttributeReader;
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct ChangedAddressAttributeReader<'a> {
|
||||
mapped_address_reader: MappedAddressAttributeReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ChangedAddressAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
mapped_address_reader: MappedAddressAttributeReader::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
self.mapped_address_reader.get_address_family()
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.mapped_address_reader.get_address_family_raw()
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.mapped_address_reader.get_port()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
self.mapped_address_reader.get_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for ChangedAddressAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.mapped_address_reader.get_bytes()
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
62
src/stun_codec/attrs/error_code.rs
Normal file
62
src/stun_codec/attrs/error_code.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
use std::str;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use super::super::enums::{ComplianceError, ErrorCode, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct ErrorCodeAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> ErrorCodeAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_error(&self) -> Result<ErrorCode, u16> {
|
||||
let error_code = self.get_error_code_raw();
|
||||
match error_code {
|
||||
300 => Ok(ErrorCode::TryAlternate),
|
||||
400 => Ok(ErrorCode::BadRequest),
|
||||
401 => Ok(ErrorCode::Unauthorized),
|
||||
420 => Ok(ErrorCode::UnknownAttribute),
|
||||
438 => Ok(ErrorCode::StaleNonce),
|
||||
500 => Ok(ErrorCode::InternalServerError),
|
||||
_ => Err(error_code)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_reason(&self) -> Result<&str, Utf8Error> {
|
||||
str::from_utf8(&self.bytes[4..(4 + self.get_value_length() - 2) as usize])
|
||||
}
|
||||
|
||||
pub fn get_error_code_raw(&self) -> u16 {
|
||||
self.get_class() as u16 * 100 + self.get_number() as u16
|
||||
}
|
||||
|
||||
pub fn get_class(&self) -> u8 {
|
||||
self.bytes[5] >> 5
|
||||
}
|
||||
|
||||
pub fn get_number(&self) -> u8 {
|
||||
self.bytes[6]
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for ErrorCodeAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc5389
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
35
src/stun_codec/attrs/fingerprint.rs
Normal file
35
src/stun_codec/attrs/fingerprint.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use std::convert::TryInto;
|
||||
use super::super::enums::{ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct FingerprintAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> FingerprintAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_checksum(&self) -> u32 {
|
||||
u32::from_be_bytes(self.bytes[2..2 + self.get_value_length() as usize].try_into().unwrap()) ^ 0x5354554E
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for FingerprintAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc5389
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
62
src/stun_codec/attrs/mapped_address.rs
Normal file
62
src/stun_codec/attrs/mapped_address.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
use std::convert::TryInto;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct MappedAddressAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> MappedAddressAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
let family_code = self.get_address_family_raw();
|
||||
match family_code {
|
||||
1 => Ok(AddressFamily::V4),
|
||||
2 => Ok(AddressFamily::V6),
|
||||
_ => Err(family_code)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.bytes[5]
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
u16::from_be_bytes(self.bytes[6..8].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
match self.get_address_family()? {
|
||||
AddressFamily::V4 => {
|
||||
let ip_num = u32::from_be_bytes(self.bytes[8..12].try_into().unwrap());
|
||||
Ok(IpAddr::V4(Ipv4Addr::from(ip_num)))
|
||||
}
|
||||
AddressFamily::V6 => {
|
||||
let ip_num = u128::from_be_bytes(self.bytes[8..24].try_into().unwrap());
|
||||
Ok(IpAddr::V6(Ipv6Addr::from(ip_num)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for MappedAddressAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
35
src/stun_codec/attrs/message_integrity.rs
Normal file
35
src/stun_codec/attrs/message_integrity.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use std::convert::TryInto;
|
||||
use super::super::enums::{ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct MessageIntegrityAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> MessageIntegrityAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_digest(&self) -> &[u8; 20] {
|
||||
self.bytes[2..2 + self.get_value_length() as usize].try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for MessageIntegrityAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc5389
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
270
src/stun_codec/attrs/mod.rs
Normal file
270
src/stun_codec/attrs/mod.rs
Normal file
@@ -0,0 +1,270 @@
|
||||
mod base;
|
||||
mod response_origin;
|
||||
mod alternate_server;
|
||||
mod other_address;
|
||||
mod xor_mapped_address;
|
||||
mod opt_xor_mapped_address;
|
||||
mod mapped_address;
|
||||
mod response_address;
|
||||
mod change_address;
|
||||
mod source_address;
|
||||
mod changed_address;
|
||||
mod reflected_from;
|
||||
mod username;
|
||||
mod password;
|
||||
mod realm;
|
||||
mod nonce;
|
||||
mod unknown_attributes;
|
||||
mod message_integrity;
|
||||
mod fingerprint;
|
||||
mod error_code;
|
||||
mod software;
|
||||
|
||||
pub use alternate_server::AlternateServerAttributeReader;
|
||||
pub use change_address::ChangeAddressAttributeReader;
|
||||
pub use changed_address::ChangedAddressAttributeReader;
|
||||
pub use error_code::ErrorCodeAttributeReader;
|
||||
pub use fingerprint::FingerprintAttributeReader;
|
||||
pub use mapped_address::MappedAddressAttributeReader;
|
||||
pub use message_integrity::MessageIntegrityAttributeReader;
|
||||
pub use nonce::NonceAttributeReader;
|
||||
pub use opt_xor_mapped_address::OptXorMappedAddressAttributeReader;
|
||||
pub use other_address::OtherAddressAttributeReader;
|
||||
pub use password::PasswordAttributeReader;
|
||||
pub use realm::RealmAttributeReader;
|
||||
pub use reflected_from::ReflectedFromAttributeReader;
|
||||
pub use response_address::ResponseAddressAttributeReader;
|
||||
pub use response_origin::ResponseOriginAttributeReader;
|
||||
pub use software::SoftwareAttributeReader;
|
||||
pub use source_address::SourceAddressAttributeReader;
|
||||
pub use unknown_attributes::UnknownAttributesAttributeReader;
|
||||
pub use username::UsernameAttributeReader;
|
||||
pub use xor_mapped_address::XorMappedAddressAttributeReader;
|
||||
pub use base::*;
|
||||
|
||||
use crate::stun_codec::enums::{ComplianceError, RfcSpec};
|
||||
|
||||
pub enum Attribute<'a> {
|
||||
MappedAddress(MappedAddressAttributeReader<'a>),
|
||||
ReflectedFrom(ReflectedFromAttributeReader<'a>),
|
||||
ResponseAddress(ResponseAddressAttributeReader<'a>),
|
||||
ChangeAddress(ChangeAddressAttributeReader<'a>),
|
||||
SourceAddress(SourceAddressAttributeReader<'a>),
|
||||
ChangedAddress(ChangedAddressAttributeReader<'a>),
|
||||
XorMappedAddress(XorMappedAddressAttributeReader<'a>),
|
||||
OptXorMappedAddress(OptXorMappedAddressAttributeReader<'a>),
|
||||
OtherAddress(OtherAddressAttributeReader<'a>),
|
||||
ResponseOrigin(ResponseOriginAttributeReader<'a>),
|
||||
Username(UsernameAttributeReader<'a>),
|
||||
Password(PasswordAttributeReader<'a>),
|
||||
MessageIntegrity(MessageIntegrityAttributeReader<'a>),
|
||||
Fingerprint(FingerprintAttributeReader<'a>),
|
||||
ErrorCode(ErrorCodeAttributeReader<'a>),
|
||||
Realm(RealmAttributeReader<'a>),
|
||||
Nonce(NonceAttributeReader<'a>),
|
||||
UnknownAttributes(UnknownAttributesAttributeReader<'a>),
|
||||
Software(SoftwareAttributeReader<'a>),
|
||||
AlternateServer(AlternateServerAttributeReader<'a>),
|
||||
}
|
||||
|
||||
impl GenericAttrReader for Attribute<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
match self {
|
||||
Attribute::MappedAddress(r) => r.get_bytes(),
|
||||
Attribute::ResponseAddress(r) => r.get_bytes(),
|
||||
Attribute::ChangeAddress(r) => r.get_bytes(),
|
||||
Attribute::SourceAddress(r) => r.get_bytes(),
|
||||
Attribute::ChangedAddress(r) => r.get_bytes(),
|
||||
Attribute::XorMappedAddress(r) => r.get_bytes(),
|
||||
Attribute::OptXorMappedAddress(r) => r.get_bytes(),
|
||||
Attribute::OtherAddress(r) => r.get_bytes(),
|
||||
Attribute::ResponseOrigin(r) => r.get_bytes(),
|
||||
Attribute::Username(r) => r.get_bytes(),
|
||||
Attribute::Password(r) => r.get_bytes(),
|
||||
Attribute::MessageIntegrity(r) => r.get_bytes(),
|
||||
Attribute::Fingerprint(r) => r.get_bytes(),
|
||||
Attribute::ErrorCode(r) => r.get_bytes(),
|
||||
Attribute::Realm(r) => r.get_bytes(),
|
||||
Attribute::Nonce(r) => r.get_bytes(),
|
||||
Attribute::UnknownAttributes(r) => r.get_bytes(),
|
||||
Attribute::ReflectedFrom(r) => r.get_bytes(),
|
||||
Attribute::Software(r) => r.get_bytes(),
|
||||
Attribute::AlternateServer(r) => r.get_bytes(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_value_raw(&self) -> &[u8] {
|
||||
match self {
|
||||
Attribute::MappedAddress(r) => r.get_value_raw(),
|
||||
Attribute::ResponseAddress(r) => r.get_value_raw(),
|
||||
Attribute::ChangeAddress(r) => r.get_value_raw(),
|
||||
Attribute::SourceAddress(r) => r.get_value_raw(),
|
||||
Attribute::ChangedAddress(r) => r.get_value_raw(),
|
||||
Attribute::XorMappedAddress(r) => r.get_value_raw(),
|
||||
Attribute::OptXorMappedAddress(r) => r.get_value_raw(),
|
||||
Attribute::OtherAddress(r) => r.get_value_raw(),
|
||||
Attribute::ResponseOrigin(r) => r.get_value_raw(),
|
||||
Attribute::Username(r) => r.get_value_raw(),
|
||||
Attribute::Password(r) => r.get_value_raw(),
|
||||
Attribute::MessageIntegrity(r) => r.get_value_raw(),
|
||||
Attribute::Fingerprint(r) => r.get_value_raw(),
|
||||
Attribute::ErrorCode(r) => r.get_value_raw(),
|
||||
Attribute::Realm(r) => r.get_value_raw(),
|
||||
Attribute::Nonce(r) => r.get_value_raw(),
|
||||
Attribute::UnknownAttributes(r) => r.get_value_raw(),
|
||||
Attribute::ReflectedFrom(r) => r.get_value_raw(),
|
||||
Attribute::Software(r) => r.get_value_raw(),
|
||||
Attribute::AlternateServer(r) => r.get_value_raw(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type_raw(&self) -> u16 {
|
||||
match self {
|
||||
Attribute::MappedAddress(r) => r.get_type_raw(),
|
||||
Attribute::ResponseAddress(r) => r.get_type_raw(),
|
||||
Attribute::ChangeAddress(r) => r.get_type_raw(),
|
||||
Attribute::SourceAddress(r) => r.get_type_raw(),
|
||||
Attribute::ChangedAddress(r) => r.get_type_raw(),
|
||||
Attribute::XorMappedAddress(r) => r.get_type_raw(),
|
||||
Attribute::OptXorMappedAddress(r) => r.get_type_raw(),
|
||||
Attribute::OtherAddress(r) => r.get_type_raw(),
|
||||
Attribute::ResponseOrigin(r) => r.get_type_raw(),
|
||||
Attribute::Username(r) => r.get_type_raw(),
|
||||
Attribute::Password(r) => r.get_type_raw(),
|
||||
Attribute::MessageIntegrity(r) => r.get_type_raw(),
|
||||
Attribute::Fingerprint(r) => r.get_type_raw(),
|
||||
Attribute::ErrorCode(r) => r.get_type_raw(),
|
||||
Attribute::Realm(r) => r.get_type_raw(),
|
||||
Attribute::Nonce(r) => r.get_type_raw(),
|
||||
Attribute::UnknownAttributes(r) => r.get_type_raw(),
|
||||
Attribute::ReflectedFrom(r) => r.get_type_raw(),
|
||||
Attribute::Software(r) => r.get_type_raw(),
|
||||
Attribute::AlternateServer(r) => r.get_type_raw(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_value_length(&self) -> u16 {
|
||||
match self {
|
||||
Attribute::MappedAddress(r) => r.get_value_length(),
|
||||
Attribute::ResponseAddress(r) => r.get_value_length(),
|
||||
Attribute::ChangeAddress(r) => r.get_value_length(),
|
||||
Attribute::SourceAddress(r) => r.get_value_length(),
|
||||
Attribute::ChangedAddress(r) => r.get_value_length(),
|
||||
Attribute::XorMappedAddress(r) => r.get_value_length(),
|
||||
Attribute::OptXorMappedAddress(r) => r.get_value_length(),
|
||||
Attribute::OtherAddress(r) => r.get_value_length(),
|
||||
Attribute::ResponseOrigin(r) => r.get_value_length(),
|
||||
Attribute::Username(r) => r.get_value_length(),
|
||||
Attribute::Password(r) => r.get_value_length(),
|
||||
Attribute::MessageIntegrity(r) => r.get_value_length(),
|
||||
Attribute::Fingerprint(r) => r.get_value_length(),
|
||||
Attribute::ErrorCode(r) => r.get_value_length(),
|
||||
Attribute::Realm(r) => r.get_value_length(),
|
||||
Attribute::Nonce(r) => r.get_value_length(),
|
||||
Attribute::UnknownAttributes(r) => r.get_value_length(),
|
||||
Attribute::ReflectedFrom(r) => r.get_value_length(),
|
||||
Attribute::Software(r) => r.get_value_length(),
|
||||
Attribute::AlternateServer(r) => r.get_value_length(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_total_length(&self) -> u16 {
|
||||
match self {
|
||||
Attribute::MappedAddress(r) => r.get_total_length(),
|
||||
Attribute::ResponseAddress(r) => r.get_total_length(),
|
||||
Attribute::ChangeAddress(r) => r.get_total_length(),
|
||||
Attribute::SourceAddress(r) => r.get_total_length(),
|
||||
Attribute::ChangedAddress(r) => r.get_total_length(),
|
||||
Attribute::XorMappedAddress(r) => r.get_total_length(),
|
||||
Attribute::OptXorMappedAddress(r) => r.get_total_length(),
|
||||
Attribute::OtherAddress(r) => r.get_total_length(),
|
||||
Attribute::ResponseOrigin(r) => r.get_total_length(),
|
||||
Attribute::Username(r) => r.get_total_length(),
|
||||
Attribute::Password(r) => r.get_total_length(),
|
||||
Attribute::MessageIntegrity(r) => r.get_total_length(),
|
||||
Attribute::Fingerprint(r) => r.get_total_length(),
|
||||
Attribute::ErrorCode(r) => r.get_total_length(),
|
||||
Attribute::Realm(r) => r.get_total_length(),
|
||||
Attribute::Nonce(r) => r.get_total_length(),
|
||||
Attribute::UnknownAttributes(r) => r.get_total_length(),
|
||||
Attribute::ReflectedFrom(r) => r.get_total_length(),
|
||||
Attribute::Software(r) => r.get_total_length(),
|
||||
Attribute::AlternateServer(r) => r.get_total_length(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
match self {
|
||||
Attribute::MappedAddress(r) => r.get_rfc_spec(),
|
||||
Attribute::ResponseAddress(r) => r.get_rfc_spec(),
|
||||
Attribute::ChangeAddress(r) => r.get_rfc_spec(),
|
||||
Attribute::SourceAddress(r) => r.get_rfc_spec(),
|
||||
Attribute::ChangedAddress(r) => r.get_rfc_spec(),
|
||||
Attribute::XorMappedAddress(r) => r.get_rfc_spec(),
|
||||
Attribute::OptXorMappedAddress(r) => r.get_rfc_spec(),
|
||||
Attribute::OtherAddress(r) => r.get_rfc_spec(),
|
||||
Attribute::ResponseOrigin(r) => r.get_rfc_spec(),
|
||||
Attribute::Username(r) => r.get_rfc_spec(),
|
||||
Attribute::Password(r) => r.get_rfc_spec(),
|
||||
Attribute::MessageIntegrity(r) => r.get_rfc_spec(),
|
||||
Attribute::Fingerprint(r) => r.get_rfc_spec(),
|
||||
Attribute::ErrorCode(r) => r.get_rfc_spec(),
|
||||
Attribute::Realm(r) => r.get_rfc_spec(),
|
||||
Attribute::Nonce(r) => r.get_rfc_spec(),
|
||||
Attribute::UnknownAttributes(r) => r.get_rfc_spec(),
|
||||
Attribute::ReflectedFrom(r) => r.get_rfc_spec(),
|
||||
Attribute::Software(r) => r.get_rfc_spec(),
|
||||
Attribute::AlternateServer(r) => r.get_rfc_spec(),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
match self {
|
||||
Attribute::MappedAddress(r) => r.check_compliance(),
|
||||
Attribute::ResponseAddress(r) => r.check_compliance(),
|
||||
Attribute::ChangeAddress(r) => r.check_compliance(),
|
||||
Attribute::SourceAddress(r) => r.check_compliance(),
|
||||
Attribute::ChangedAddress(r) => r.check_compliance(),
|
||||
Attribute::XorMappedAddress(r) => r.check_compliance(),
|
||||
Attribute::OptXorMappedAddress(r) => r.check_compliance(),
|
||||
Attribute::OtherAddress(r) => r.check_compliance(),
|
||||
Attribute::ResponseOrigin(r) => r.check_compliance(),
|
||||
Attribute::Username(r) => r.check_compliance(),
|
||||
Attribute::Password(r) => r.check_compliance(),
|
||||
Attribute::MessageIntegrity(r) => r.check_compliance(),
|
||||
Attribute::Fingerprint(r) => r.check_compliance(),
|
||||
Attribute::ErrorCode(r) => r.check_compliance(),
|
||||
Attribute::Realm(r) => r.check_compliance(),
|
||||
Attribute::Nonce(r) => r.check_compliance(),
|
||||
Attribute::UnknownAttributes(r) => r.check_compliance(),
|
||||
Attribute::ReflectedFrom(r) => r.check_compliance(),
|
||||
Attribute::Software(r) => r.check_compliance(),
|
||||
Attribute::AlternateServer(r) => r.check_compliance(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
match self {
|
||||
Attribute::MappedAddress(r) => r.is_deprecated(),
|
||||
Attribute::ResponseAddress(r) => r.is_deprecated(),
|
||||
Attribute::ChangeAddress(r) => r.is_deprecated(),
|
||||
Attribute::SourceAddress(r) => r.is_deprecated(),
|
||||
Attribute::ChangedAddress(r) => r.is_deprecated(),
|
||||
Attribute::XorMappedAddress(r) => r.is_deprecated(),
|
||||
Attribute::OptXorMappedAddress(r) => r.is_deprecated(),
|
||||
Attribute::OtherAddress(r) => r.is_deprecated(),
|
||||
Attribute::ResponseOrigin(r) => r.is_deprecated(),
|
||||
Attribute::Username(r) => r.is_deprecated(),
|
||||
Attribute::Password(r) => r.is_deprecated(),
|
||||
Attribute::MessageIntegrity(r) => r.is_deprecated(),
|
||||
Attribute::Fingerprint(r) => r.is_deprecated(),
|
||||
Attribute::ErrorCode(r) => r.is_deprecated(),
|
||||
Attribute::Realm(r) => r.is_deprecated(),
|
||||
Attribute::Nonce(r) => r.is_deprecated(),
|
||||
Attribute::UnknownAttributes(r) => r.is_deprecated(),
|
||||
Attribute::ReflectedFrom(r) => r.is_deprecated(),
|
||||
Attribute::Software(r) => r.is_deprecated(),
|
||||
Attribute::AlternateServer(r) => r.is_deprecated(),
|
||||
}
|
||||
}
|
||||
}
|
37
src/stun_codec/attrs/nonce.rs
Normal file
37
src/stun_codec/attrs/nonce.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use std::str;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use super::super::enums::{ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct NonceAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> NonceAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_nonce(&self) -> Result<&str, Utf8Error> {
|
||||
str::from_utf8(&self.bytes[2..2 + self.get_value_length() as usize])
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for NonceAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
50
src/stun_codec/attrs/opt_xor_mapped_address.rs
Normal file
50
src/stun_codec/attrs/opt_xor_mapped_address.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use std::net::IpAddr;
|
||||
use super::xor_mapped_address::XorMappedAddressAttributeReader;
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct OptXorMappedAddressAttributeReader<'a> {
|
||||
xor_mapped_address_reader: XorMappedAddressAttributeReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> OptXorMappedAddressAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8], transaction_id: &'a [u8; 12]) -> Self {
|
||||
Self {
|
||||
xor_mapped_address_reader: XorMappedAddressAttributeReader::new(bytes, transaction_id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
self.xor_mapped_address_reader.get_address_family()
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.xor_mapped_address_reader.get_address_family_raw()
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.xor_mapped_address_reader.get_port()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
self.xor_mapped_address_reader.get_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for OptXorMappedAddressAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.xor_mapped_address_reader.get_bytes()
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
50
src/stun_codec/attrs/other_address.rs
Normal file
50
src/stun_codec/attrs/other_address.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use std::net::IpAddr;
|
||||
use super::mapped_address::MappedAddressAttributeReader;
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct OtherAddressAttributeReader<'a> {
|
||||
mapped_address_reader: MappedAddressAttributeReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> OtherAddressAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
mapped_address_reader: MappedAddressAttributeReader::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
self.mapped_address_reader.get_address_family()
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.mapped_address_reader.get_address_family_raw()
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.mapped_address_reader.get_port()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
self.mapped_address_reader.get_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for OtherAddressAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.mapped_address_reader.get_bytes()
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc5389
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
37
src/stun_codec/attrs/password.rs
Normal file
37
src/stun_codec/attrs/password.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use std::str;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use super::super::enums::{ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct PasswordAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> PasswordAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_password(&self) -> Result<&str, Utf8Error> {
|
||||
str::from_utf8(&self.bytes[2..2 + self.get_value_length() as usize])
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for PasswordAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
37
src/stun_codec/attrs/realm.rs
Normal file
37
src/stun_codec/attrs/realm.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use std::str;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use super::base::GenericAttrReader;
|
||||
use super::super::enums::{ComplianceError, RfcSpec};
|
||||
|
||||
pub struct RealmAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> RealmAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_realm(&self) -> Result<&str, Utf8Error> {
|
||||
str::from_utf8(&self.bytes[2..2 + self.get_value_length() as usize])
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for RealmAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
50
src/stun_codec/attrs/reflected_from.rs
Normal file
50
src/stun_codec/attrs/reflected_from.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use std::net::IpAddr;
|
||||
use super::mapped_address::MappedAddressAttributeReader;
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct ReflectedFromAttributeReader<'a> {
|
||||
mapped_address_reader: MappedAddressAttributeReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ReflectedFromAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
mapped_address_reader: MappedAddressAttributeReader::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
self.mapped_address_reader.get_address_family()
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.mapped_address_reader.get_address_family_raw()
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.mapped_address_reader.get_port()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
self.mapped_address_reader.get_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for ReflectedFromAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.mapped_address_reader.get_bytes()
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
50
src/stun_codec/attrs/response_address.rs
Normal file
50
src/stun_codec/attrs/response_address.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use std::net::IpAddr;
|
||||
use super::mapped_address::MappedAddressAttributeReader;
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct ResponseAddressAttributeReader<'a> {
|
||||
mapped_address_reader: MappedAddressAttributeReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ResponseAddressAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
mapped_address_reader: MappedAddressAttributeReader::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
self.mapped_address_reader.get_address_family()
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.mapped_address_reader.get_address_family_raw()
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.mapped_address_reader.get_port()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
self.mapped_address_reader.get_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for ResponseAddressAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.mapped_address_reader.get_bytes()
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
50
src/stun_codec/attrs/response_origin.rs
Normal file
50
src/stun_codec/attrs/response_origin.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use std::net::IpAddr;
|
||||
use super::mapped_address::MappedAddressAttributeReader;
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct ResponseOriginAttributeReader<'a> {
|
||||
mapped_address_reader: MappedAddressAttributeReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ResponseOriginAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
mapped_address_reader: MappedAddressAttributeReader::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
self.mapped_address_reader.get_address_family()
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.mapped_address_reader.get_address_family_raw()
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.mapped_address_reader.get_port()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
self.mapped_address_reader.get_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for ResponseOriginAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.mapped_address_reader.get_bytes()
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc5389
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
37
src/stun_codec/attrs/software.rs
Normal file
37
src/stun_codec/attrs/software.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use std::str;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use super::super::enums::{ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct SoftwareAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> SoftwareAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_software(&self) -> Result<&str, Utf8Error> {
|
||||
str::from_utf8(&self.bytes[2..2 + self.get_value_length() as usize])
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for SoftwareAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc5389
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
50
src/stun_codec/attrs/source_address.rs
Normal file
50
src/stun_codec/attrs/source_address.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use std::net::IpAddr;
|
||||
use super::mapped_address::MappedAddressAttributeReader;
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct SourceAddressAttributeReader<'a> {
|
||||
mapped_address_reader: MappedAddressAttributeReader<'a>,
|
||||
}
|
||||
|
||||
impl<'a> SourceAddressAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
mapped_address_reader: MappedAddressAttributeReader::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
self.mapped_address_reader.get_address_family()
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.mapped_address_reader.get_address_family_raw()
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.mapped_address_reader.get_port()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
self.mapped_address_reader.get_address()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for SourceAddressAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.mapped_address_reader.get_bytes()
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
58
src/stun_codec/attrs/unknown_attributes.rs
Normal file
58
src/stun_codec/attrs/unknown_attributes.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use super::base::GenericAttrReader;
|
||||
use super::super::enums::{ComplianceError, RfcSpec};
|
||||
|
||||
pub struct UnknownAttributesAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
pub struct UnknownAttrIter<'a> {
|
||||
bytes: &'a [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl Iterator for UnknownAttrIter<'_> {
|
||||
type Item = u16;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.offset == self.bytes.len() {
|
||||
None
|
||||
} else {
|
||||
let attr = u16::from_be_bytes(self.bytes[self.offset..self.offset + 2].try_into().unwrap());
|
||||
self.offset += 2;
|
||||
Some(attr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UnknownAttributesAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_attr_codes(&self) -> UnknownAttrIter {
|
||||
UnknownAttrIter {
|
||||
bytes: &self.bytes[2..2+self.get_value_length() as usize],
|
||||
offset: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for UnknownAttributesAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
37
src/stun_codec/attrs/username.rs
Normal file
37
src/stun_codec/attrs/username.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use std::str;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use super::base::GenericAttrReader;
|
||||
use super::super::enums::{ComplianceError, RfcSpec};
|
||||
|
||||
pub struct UsernameAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> UsernameAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
|
||||
pub fn get_username(&self) -> Result<&str, Utf8Error> {
|
||||
str::from_utf8(&self.bytes[2..2 + self.get_value_length() as usize])
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for UsernameAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc3489
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
65
src/stun_codec/attrs/xor_mapped_address.rs
Normal file
65
src/stun_codec/attrs/xor_mapped_address.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use std::convert::TryInto;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use super::super::enums::{AddressFamily, ComplianceError, RfcSpec};
|
||||
use super::base::GenericAttrReader;
|
||||
|
||||
pub struct XorMappedAddressAttributeReader<'a> {
|
||||
bytes: &'a [u8],
|
||||
transaction_id: &'a [u8; 12],
|
||||
}
|
||||
|
||||
impl<'a> XorMappedAddressAttributeReader<'a> {
|
||||
pub fn new(bytes: &'a [u8], transaction_id: &'a [u8; 12]) -> Self {
|
||||
Self { bytes, transaction_id }
|
||||
}
|
||||
|
||||
pub fn get_address_family(&self) -> Result<AddressFamily, u8> {
|
||||
let family_code = self.get_address_family_raw();
|
||||
match family_code {
|
||||
1 => Ok(AddressFamily::V4),
|
||||
2 => Ok(AddressFamily::V6),
|
||||
_ => Err(family_code)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address_family_raw(&self) -> u8 {
|
||||
self.bytes[5]
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
u16::from_be_bytes(self.bytes[6..8].try_into().unwrap()) ^ 0x2112 // xor with top half of magic cookie
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<IpAddr, u8> {
|
||||
match self.get_address_family()? {
|
||||
AddressFamily::V4 => {
|
||||
let ip_num = u32::from_be_bytes(self.bytes[8..12].try_into().unwrap()) ^ 0x2112A442; // xor with magic cookie
|
||||
Ok(IpAddr::V4(Ipv4Addr::from(ip_num)))
|
||||
}
|
||||
AddressFamily::V6 => {
|
||||
let t_id = self.transaction_id;
|
||||
let xor_mask = 0x2112A442_u128 << 92 | u128::from(u64::from_ne_bytes(t_id[4..12].try_into().unwrap())) << 64 | u32::from_ne_bytes(t_id[0..4].try_into().unwrap()) as u128;
|
||||
let ip_num = u128::from_be_bytes(self.bytes[8..24].try_into().unwrap()) ^ xor_mask;
|
||||
Ok(IpAddr::V6(Ipv6Addr::from(ip_num)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericAttrReader for XorMappedAddressAttributeReader<'_> {
|
||||
fn get_bytes(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
fn get_rfc_spec(&self) -> RfcSpec {
|
||||
RfcSpec::Rfc5389
|
||||
}
|
||||
|
||||
fn check_compliance(&self) -> Vec<ComplianceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
46
src/stun_codec/enums.rs
Normal file
46
src/stun_codec/enums.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum MessageClass {
|
||||
Request,
|
||||
Indirection,
|
||||
SuccessResponse,
|
||||
ErrorResponse,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Method {
|
||||
Binding
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ComprehensionCategory {
|
||||
Required,
|
||||
Optional,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum RfcSpec {
|
||||
Rfc3489,
|
||||
Rfc5245,
|
||||
Rfc5389,
|
||||
Rfc5766,
|
||||
Rfc5780,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum AddressFamily {
|
||||
V4,
|
||||
V6,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ComplianceError {}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ErrorCode {
|
||||
TryAlternate,
|
||||
BadRequest,
|
||||
Unauthorized,
|
||||
UnknownAttribute,
|
||||
StaleNonce,
|
||||
InternalServerError,
|
||||
}
|
136
src/stun_codec/message.rs
Normal file
136
src/stun_codec/message.rs
Normal file
@@ -0,0 +1,136 @@
|
||||
use std::convert::TryInto;
|
||||
use super::enums::{ComplianceError, MessageClass, Method};
|
||||
use super::attrs::*;
|
||||
|
||||
pub struct StunMessageReader<'a> {
|
||||
pub(crate) bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl StunMessageReader<'_> {
|
||||
pub fn get_message_type(&self) -> u16 {
|
||||
u16::from_be_bytes(self.bytes[0..2].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn get_method(&self) -> Result<Method, u16> {
|
||||
let method_code = self.get_method_raw();
|
||||
match method_code {
|
||||
1 => Ok(Method::Binding),
|
||||
_ => Err(method_code)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_method_raw(&self) -> u16 {
|
||||
let msg_type = self.get_message_type();
|
||||
let method_code: u16 = msg_type & 0b11111011101111;
|
||||
method_code
|
||||
}
|
||||
|
||||
pub fn get_class(&self) -> MessageClass {
|
||||
let class = self.get_class_raw();
|
||||
match class {
|
||||
0b000000000 => MessageClass::Request,
|
||||
0b000010000 => MessageClass::Indirection,
|
||||
0b100000000 => MessageClass::SuccessResponse,
|
||||
0b100010000 => MessageClass::ErrorResponse,
|
||||
_ => panic!("Impossible message class")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_class_raw(&self) -> u16 {
|
||||
let msg_type = self.get_message_type();
|
||||
let class = msg_type & !0b11111011101111;
|
||||
class
|
||||
}
|
||||
|
||||
pub fn get_length(&self) -> u16 {
|
||||
u16::from_be_bytes(self.bytes[2..4].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn get_attrs(&self) -> Iter {
|
||||
Iter {
|
||||
attr_bytes: &self.bytes[20..(self.bytes.len())],
|
||||
curr_offset: 0,
|
||||
transaction_id: self.bytes[8..20].try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_header_spec_compliance(&self) -> Vec<ComplianceError> { todo!() }
|
||||
|
||||
pub fn is_compliant(&self) -> bool {
|
||||
if !self.check_header_spec_compliance().is_empty() { return false; }
|
||||
|
||||
for attr in self.get_attrs() {
|
||||
match attr {
|
||||
Ok(attr) => if !attr.check_compliance().is_empty() { return false; }
|
||||
Err(_) => return false,
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a> {
|
||||
attr_bytes: &'a [u8],
|
||||
curr_offset: usize,
|
||||
transaction_id: &'a [u8; 12],
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = Result<Attribute<'a>, NonParsableAttribute<'a>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.attr_bytes.len() - self.curr_offset == 0 { return None; }
|
||||
|
||||
let bytes = &self.attr_bytes[self.curr_offset..self.attr_bytes.len()];
|
||||
|
||||
if self.attr_bytes.len() - self.curr_offset <= 4 {
|
||||
let item = Some(
|
||||
Err(
|
||||
NonParsableAttribute::Malformed(
|
||||
MalformedAttrReader::new(bytes)
|
||||
)
|
||||
)
|
||||
);
|
||||
self.curr_offset = self.attr_bytes.len();
|
||||
return item;
|
||||
}
|
||||
|
||||
let typ = u16::from_be_bytes(bytes[0..2].try_into().unwrap());
|
||||
let transaction_id = self.transaction_id;
|
||||
|
||||
let res = match typ {
|
||||
0x0001 => Ok(Attribute::MappedAddress(MappedAddressAttributeReader::new(bytes))),
|
||||
0x0002 => Ok(Attribute::ResponseAddress(ResponseAddressAttributeReader::new(bytes))),
|
||||
0x0003 => Ok(Attribute::ChangeAddress(ChangeAddressAttributeReader::new(bytes))),
|
||||
0x0004 => Ok(Attribute::SourceAddress(SourceAddressAttributeReader::new(bytes))),
|
||||
0x0005 => Ok(Attribute::ChangedAddress(ChangedAddressAttributeReader::new(bytes))),
|
||||
0x0006 => Ok(Attribute::Username(UsernameAttributeReader::new(bytes))),
|
||||
0x0007 => Ok(Attribute::Password(PasswordAttributeReader::new(bytes))),
|
||||
0x0008 => Ok(Attribute::MessageIntegrity(MessageIntegrityAttributeReader::new(bytes))),
|
||||
0x000A => Ok(Attribute::UnknownAttributes(UnknownAttributesAttributeReader::new(bytes))),
|
||||
0x000B => Ok(Attribute::ReflectedFrom(ReflectedFromAttributeReader::new(bytes))),
|
||||
0x0009 => Ok(Attribute::ErrorCode(ErrorCodeAttributeReader::new(bytes))),
|
||||
0x0014 => Ok(Attribute::Realm(RealmAttributeReader::new(bytes))),
|
||||
0x0015 => Ok(Attribute::Nonce(NonceAttributeReader::new(bytes))),
|
||||
0x0020 => Ok(Attribute::XorMappedAddress(XorMappedAddressAttributeReader::new(bytes, transaction_id))),
|
||||
0x8020 => Ok(Attribute::OptXorMappedAddress(OptXorMappedAddressAttributeReader::new(bytes, transaction_id))),
|
||||
0x8022 => Ok(Attribute::Software(SoftwareAttributeReader::new(bytes))),
|
||||
0x8023 => Ok(Attribute::AlternateServer(AlternateServerAttributeReader::new(bytes))),
|
||||
0x802b => Ok(Attribute::ResponseOrigin(ResponseOriginAttributeReader::new(bytes))),
|
||||
0x802c => Ok(Attribute::OtherAddress(OtherAddressAttributeReader::new(bytes))),
|
||||
0x8028 => Ok(Attribute::Fingerprint(FingerprintAttributeReader::new(bytes))),
|
||||
_ => Err(NonParsableAttribute::Unknown(UnknownAttrReader::new(bytes)))
|
||||
};
|
||||
|
||||
let offset_delta = match &res {
|
||||
Ok(attr) => attr.get_total_length() as usize,
|
||||
Err(NonParsableAttribute::Unknown(reader)) => reader.get_total_length() as usize,
|
||||
Err(NonParsableAttribute::Malformed(_)) => self.attr_bytes.len() - self.curr_offset,
|
||||
};
|
||||
|
||||
self.curr_offset += offset_delta;
|
||||
|
||||
Some(res)
|
||||
}
|
||||
}
|
7
src/stun_codec/mod.rs
Normal file
7
src/stun_codec/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
mod enums;
|
||||
mod attrs;
|
||||
mod message;
|
||||
|
||||
pub use attrs::*;
|
||||
pub use enums::*;
|
||||
pub use message::*;
|
Reference in New Issue
Block a user