support for checking fingerprint, misc
This commit is contained in:
76
src/lib.rs
76
src/lib.rs
@@ -1,4 +1,4 @@
|
||||
use crc32fast::hash;
|
||||
use crc32fast::{hash, Hasher};
|
||||
use log::warn;
|
||||
use nom::bytes::complete::{tag, take};
|
||||
use nom::error::ParseError;
|
||||
@@ -144,7 +144,7 @@ pub enum StunAttribute {
|
||||
ChangedAddress(AddrPort),
|
||||
Username(String),
|
||||
MessageIntegrity([u8; 20]),
|
||||
Fingerprint(u32),
|
||||
Fingerprint((u32, bool)),
|
||||
ErrorCode((u16, String)),
|
||||
Realm(String),
|
||||
Nonce(String),
|
||||
@@ -202,22 +202,27 @@ impl fmt::Display for StunAttribute {
|
||||
a.port
|
||||
)
|
||||
}
|
||||
StunAttribute::Username(username) => writeln!(f, " Username {}", username),
|
||||
StunAttribute::Username(username) => write!(f, " Username {}", username),
|
||||
StunAttribute::MessageIntegrity(msg_integrity) => {
|
||||
write!(f, " MessageIntegrity {:?}", msg_integrity)
|
||||
}
|
||||
StunAttribute::Fingerprint(fingerprint) => {
|
||||
write!(f, " Fingerprint 0x{:08x}", fingerprint)
|
||||
StunAttribute::Fingerprint((crc, ok)) => {
|
||||
write!(
|
||||
f,
|
||||
" Fingerprint 0x{:08x} ({})",
|
||||
crc,
|
||||
if *ok { "OK" } else { "FAIL" }
|
||||
)
|
||||
}
|
||||
StunAttribute::ErrorCode((err_num, error)) => {
|
||||
write!(f, " ErrorCode {} ({})", err_num, error)
|
||||
}
|
||||
StunAttribute::Realm(realm) => writeln!(f, " Realm {}", realm),
|
||||
StunAttribute::Nonce(nonce) => writeln!(f, " Nonce {}", nonce),
|
||||
StunAttribute::Realm(realm) => write!(f, " Realm {}", realm),
|
||||
StunAttribute::Nonce(nonce) => write!(f, " Nonce {}", nonce),
|
||||
StunAttribute::UnknownAttributes(unknown_attrs) => {
|
||||
write!(f, " UnknownAttributes {:?}", unknown_attrs)
|
||||
}
|
||||
StunAttribute::Software(software) => writeln!(f, " Software {}", software),
|
||||
StunAttribute::Software(software) => write!(f, " Software {}", software),
|
||||
StunAttribute::AlternateServer(a) => {
|
||||
write!(
|
||||
f,
|
||||
@@ -235,7 +240,7 @@ impl fmt::Display for StunAttribute {
|
||||
a.address,
|
||||
a.port
|
||||
)
|
||||
},
|
||||
}
|
||||
StunAttribute::OtherAddress(a) => {
|
||||
write!(
|
||||
f,
|
||||
@@ -244,7 +249,7 @@ impl fmt::Display for StunAttribute {
|
||||
a.address,
|
||||
a.port
|
||||
)
|
||||
},
|
||||
}
|
||||
StunAttribute::Unknown((attr_type, data)) => {
|
||||
write!(f, " Unknown ({:04x}) {:?}", attr_type, data)
|
||||
}
|
||||
@@ -334,16 +339,59 @@ where
|
||||
|
||||
fn parse_stun_message<'a, I, E: ParseError<I>>(input: I) -> IResult<I, StunMessage, E>
|
||||
where
|
||||
I: nom::Input<Item = u8> + nom::Compare<I> + nom::Compare<&'a [u8]> + AsBytes + Debug,
|
||||
I: nom::Input<Item = u8>
|
||||
+ nom::Compare<I>
|
||||
+ nom::Compare<&'a [u8]>
|
||||
+ nom::Offset
|
||||
+ AsBytes
|
||||
+ Debug,
|
||||
{
|
||||
let mut hasher = Some(Hasher::new());
|
||||
let input_start = input.clone();
|
||||
|
||||
let (input, h) = parse_stun_header(input)?;
|
||||
hasher
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.update(input_start.take(input_start.offset(&input)).as_bytes());
|
||||
|
||||
let (residual, input) = take(h.msg_length)(input)?;
|
||||
if residual.input_len() != 0 {
|
||||
warn!("Trailing bytes in STUN message: {:?}", residual);
|
||||
}
|
||||
|
||||
let (input, attributes) = many0(parse_stun_attribute(&h.tx_id)).parse(input)?;
|
||||
if !input.input_len() != 0 {
|
||||
let mut input = input;
|
||||
let mut attributes = Vec::new();
|
||||
|
||||
while let Ok((new_input, attr)) = parse_stun_attribute::<I, E>(&h.tx_id)(input.clone()) {
|
||||
let attr = if let Some(StunAttribute::Fingerprint(fingerprint)) = attr {
|
||||
let crc = hasher.unwrap().finalize() ^ 0x5354554e;
|
||||
hasher = None;
|
||||
if crc == fingerprint.0 {
|
||||
Some(StunAttribute::Fingerprint((crc, true)))
|
||||
} else {
|
||||
warn!(
|
||||
"Fingerprint mismatch: expected 0x{:08x}, got 0x{:08x}",
|
||||
crc, fingerprint.0
|
||||
);
|
||||
attr
|
||||
}
|
||||
} else {
|
||||
if hasher.is_some() {
|
||||
hasher
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.update(input.take(input.offset(&new_input)).as_bytes());
|
||||
} else {
|
||||
warn!("Received attributes after FINGERPRINT");
|
||||
}
|
||||
attr
|
||||
};
|
||||
|
||||
attributes.push(attr);
|
||||
input = new_input;
|
||||
}
|
||||
if input.input_len() != 0 {
|
||||
warn!("Trailing bytes in STUN message attributes: {:?}", input);
|
||||
}
|
||||
let attributes = StunAttributes(attributes.iter().filter_map(|i| i.clone()).collect());
|
||||
@@ -492,7 +540,7 @@ where
|
||||
}
|
||||
ATTR_NUM_FINGERPRINT => {
|
||||
let (_residual, fingerprint) = be_u32(attr_data)?;
|
||||
StunAttribute::Fingerprint(fingerprint)
|
||||
StunAttribute::Fingerprint((fingerprint, false))
|
||||
}
|
||||
ATTR_REALM => {
|
||||
let realm = String::from_iter(attr_data.iter_elements().map(|b| b as char));
|
||||
|
||||
Reference in New Issue
Block a user