support for checking fingerprint, misc
This commit is contained in:
parent
6985ed6614
commit
a66a6a263e
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));
|
||||
|
21
src/main.rs
21
src/main.rs
@ -42,7 +42,7 @@ impl OutputFormat {
|
||||
#[command(about = "Test a Tailscale derp node's stun service")]
|
||||
struct Cli {
|
||||
host: String,
|
||||
#[clap(short, long, default_value = "3478")]
|
||||
#[clap(default_value = "3478")]
|
||||
port: u16,
|
||||
#[clap(short = '4', conflicts_with = "v6_only", default_value = "false")]
|
||||
v4_only: bool,
|
||||
@ -100,22 +100,27 @@ fn main() {
|
||||
|
||||
let mut buf = [0u8; 1500];
|
||||
|
||||
if let Ok(received) = socket.recv(&mut buf) {
|
||||
debug!("Received response: {:?}", &buf[..received]);
|
||||
match socket.recv(&mut buf) {
|
||||
Ok(received) => {
|
||||
let buf = &buf[..received];
|
||||
debug!("Received response: {:?}", buf);
|
||||
|
||||
let msg = StunMessage::parse(&buf).unwrap();
|
||||
let msg = StunMessage::parse(buf).unwrap();
|
||||
info!("Parsed message from {}:", socket.peer_addr().unwrap());
|
||||
if cli.address_only {
|
||||
if let Some(addr) = msg.attributes.mapped_address() {
|
||||
println!("{}", cli.format.format_address(addr));
|
||||
} else {
|
||||
match msg.attributes.mapped_address() {
|
||||
Some(addr) => println!("{}", cli.format.format_address(addr)),
|
||||
None => {
|
||||
// No mapped address
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("{}", cli.format.format_stun(&msg));
|
||||
}
|
||||
} else if let Err(e) = socket.recv(&mut buf) {
|
||||
}
|
||||
Err(e) => {
|
||||
println!("recv function failed: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user