Files
always-online-stun/examples/stun_client_tcp.rs
2022-08-23 20:52:59 +01:00

55 lines
2.0 KiB
Rust

use std::io::{Read, Write};
use stun_proto::rfc5389::*;
/**
In this example, we are calling a TCP stun server
To get our external IP and port
*/
fn main() {
let mut buf = [0u8; 32];
let mut writer = Writer::new(&mut buf);
writer.set_message_type(MessageType::BindingRequest).unwrap();
writer.set_transaction_id(1).unwrap();
let bytes_written = writer.finish().unwrap();
let mut socket = std::net::TcpStream::connect("stun.stunprotocol.org:3478").unwrap();
socket.write_all(&buf[0..bytes_written as usize]).unwrap();
socket.set_read_timeout(Some(std::time::Duration::from_millis(1000))).unwrap();
let bytes_read = socket.read(&mut buf).unwrap();
// we assume that the entire message has been read in one go
// a more robust client would look at the message length and keep reading if necessary
let reader = Reader::new(&buf[0..bytes_read]);
if let MessageType::BindingResponse = reader.get_message_type().unwrap() {
assert_eq!(1u128, reader.get_transaction_id().unwrap());
let external_addr = reader.get_attributes()
.map(|attr| {
match attr {
Ok(ReaderAttribute::MappedAddress(addr)) => Some(addr.get_address().unwrap()),
Ok(ReaderAttribute::XorMappedAddress(addr)) => Some(addr.get_address().unwrap()),
_ => None,
}
})
.filter(|opt| opt.is_some())
.map(|opt| opt.unwrap())
.next()
.unwrap();
let std_external_addr = match external_addr {
SocketAddr::V4(ip, port) => {
std::net::SocketAddr::new(std::net::IpAddr::from(ip.to_be_bytes()), port)
},
SocketAddr::V6(ip, port) => {
std::net::SocketAddr::new(std::net::IpAddr::from(ip.to_be_bytes()), port)
},
};
println!("NAT mapping {} -> {}", socket.local_addr().unwrap(), std_external_addr);
} else {
assert!(false, "Response is not a BindingResponse")
}
}