WIP towards Geo information

This commit is contained in:
pradt2
2022-04-21 20:36:00 +01:00
parent 612c8a40ba
commit f059e0402e
34 changed files with 1531 additions and 1812 deletions

39
Cargo.lock generated
View File

@@ -15,7 +15,6 @@ dependencies = [
name = "always-online-stun" name = "always-online-stun"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitwise",
"futures", "futures",
"log", "log",
"pretty_env_logger", "pretty_env_logger",
@@ -56,20 +55,6 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 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]] [[package]]
name = "build_const" name = "build_const"
version = "0.2.2" version = "0.2.2"
@@ -695,15 +680,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.20.4" version = "0.20.4"
@@ -741,21 +717,6 @@ dependencies = [
"untrusted", "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]] [[package]]
name = "serde" name = "serde"
version = "1.0.136" version = "1.0.136"

View File

@@ -6,7 +6,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bitwise = { path = "../bitwise", default-features = false }
futures = { version = "0.3.17" } futures = { version = "0.3.17" }
log = { version = "0.4.16" } log = { version = "0.4.16" }
pretty_env_logger = { version = "0.4.0" } pretty_env_logger = { version = "0.4.0" }

View File

@@ -51,12 +51,10 @@ impl IpGeolocationIoClient {
.map_err(|err| io::Error::new(ErrorKind::Other, err))?; .map_err(|err| io::Error::new(ErrorKind::Other, err))?;
let lat = response.get("latitude") let lat = response.get("latitude")
.cloned()
.map(|lat_str| lat_str.parse().unwrap()) .map(|lat_str| lat_str.parse().unwrap())
.unwrap_or(0 as f32); .unwrap_or(0 as f32);
let lon = response.get("longitude") let lon = response.get("longitude")
.cloned()
.map(|lon_str| lon_str.parse().unwrap()) .map(|lon_str| lon_str.parse().unwrap())
.unwrap_or(0 as f32); .unwrap_or(0 as f32);

View File

@@ -12,7 +12,7 @@ use crate::utils::join_all_with_semaphore;
use crate::outputs::{ValidHosts, ValidIpV4s, ValidIpV6s}; use crate::outputs::{ValidHosts, ValidIpV4s, ValidIpV6s};
use crate::servers::StunServer; use crate::servers::StunServer;
use crate::stun::{StunServerTestResult, StunSocketResponse}; use crate::stun::{StunServerTestResult, StunSocketResponse};
use crate::stun_client_2::{Attribute, GenericAttrReader, NonParsableAttribute}; use crate::stun_codec::{Attribute, NonParsableAttribute};
extern crate pretty_env_logger; extern crate pretty_env_logger;
#[macro_use] extern crate log; #[macro_use] extern crate log;
@@ -23,8 +23,7 @@ mod utils;
mod outputs; mod outputs;
mod geoip; mod geoip;
mod git; mod git;
mod stun_client; mod stun_codec;
mod stun_client_2;
const CONCURRENT_SOCKETS_USED_LIMIT: usize = 64; 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 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()); info!("Method {:?} , Class {:?}", r.get_method().unwrap(), r.get_class());
r.get_attrs().for_each(|attr| { r.get_attrs().for_each(|attr| {
match &attr { match &attr {

View File

@@ -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;
}
}
}

File diff suppressed because it is too large Load Diff

View 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
}
}

View 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]
}
}
}
}

View File

@@ -0,0 +1,7 @@
mod malformed;
mod unknown;
mod shared;
pub use malformed::*;
pub use unknown::*;
pub use shared::*;

View 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;
}

View 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)) }
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
View 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(),
}
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
View 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
View 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
View File

@@ -0,0 +1,7 @@
mod enums;
mod attrs;
mod message;
pub use attrs::*;
pub use enums::*;
pub use message::*;