STUN Coder
STUN Coder is a STUN protocol encoder and decoder for Rust.
The implementation is done according to Session Traversal Utilities for NAT (STUN).
STUN extensions specified by the Interactive Connectivity Establishment (ICE) protocol are also supported.
Usage
An example of creating and encoding a STUN binding request:
let message = stun_coder::StunMessage::create_request()
.add_attribute(stun_coder::StunAttribute::Software {
description: String::from("rust-stun-coder"),
})
.add_message_integrity()
.add_fingerprint();
let encoded_message = message.encode(Some("TEST_PASS")).unwrap();
println!("{:#X?}", encoded_message);
An example that decodes a sample request with Long-Term Authentication
let msg_bytes: Vec<u8> = vec![
0x01, 0x01, 0x00, 0x48, 0x21, 0x12, 0xa4, 0x42, 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34,
0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae, 0x80, 0x22, 0x00, 0x0b, 0x74, 0x65, 0x73, 0x74,
0x20, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x00, 0x00, 0x20, 0x00, 0x14, 0x00, 0x02,
0xa1, 0x47, 0x01, 0x13, 0xa9, 0xfa, 0xa5, 0xd3, 0xf1, 0x79, 0xbc, 0x25, 0xf4, 0xb5,
0xbe, 0xd2, 0xb9, 0xd9, 0x00, 0x08, 0x00, 0x14, 0xBD, 0x3, 0x6D, 0x6A, 0x33, 0x17,
0x50, 0xDF, 0xE2, 0xED, 0xC5, 0x8E, 0x64, 0x34, 0x55, 0xCF, 0xF5, 0xC8, 0xE2, 0x64,
0x80, 0x28, 0x00, 0x04, 0x4F, 0x26, 0x02, 0x93,
];
let integrity_key = Some("VOkJxbRl1RmTxUk/WvJxBt");
let decoded_msg = stun_coder::StunMessage::decode(&msg_bytes, integrity_key).unwrap();
println!("{:?}", decoded_msg);
Example function that fetches the server reflexive address of all the local interfaces:
use std::io::{Error, ErrorKind};
use std::net::{SocketAddr, UdpSocket};
fn get_mapped_addr(binding_addr: SocketAddr) -> Result<SocketAddr, std::io::Error> {
let stun_server = "stun.l.google.com:19302";
let binding_msg = stun_coder::StunMessage::create_request()
.add_attribute(stun_coder::StunAttribute::Software {
description: String::from("rust-stun-coder"),
}) .add_message_integrity() .add_fingerprint();
let integrity_pass = "STUN_CODER_PASS";
let bytes = binding_msg.encode(Some(integrity_pass)).unwrap();
let udp_socket = UdpSocket::bind(binding_addr)?;
udp_socket.connect(stun_server.clone())?;
udp_socket.send(&bytes)?;
let mut response_buf = [0; 32];
udp_socket.recv(&mut response_buf)?;
let stun_response =
stun_coder::StunMessage::decode(&response_buf, Some(integrity_pass)).unwrap();
for attr in stun_response.get_attributes() {
if let stun_coder::StunAttribute::XorMappedAddress { socket_addr } = attr {
return Ok(*socket_addr);
}
}
Err(Error::new(
ErrorKind::InvalidData,
"No XorMappedAddress has been set in response.",
))
}
fn get_mapped_addresses() {
let local_interfaces = get_if_addrs::get_if_addrs().unwrap();
for interface in local_interfaces.iter() {
if interface.is_loopback() {
continue;
}
let host_addr = interface.ip();
let binding_addr = SocketAddr::new(host_addr, 2000);
match get_mapped_addr(binding_addr) {
Ok(mapped_socket_addr) => {
println!(
"Mapped host address {} to remote {}.",
binding_addr, mapped_socket_addr
);
}
Err(err) => {
println!(
"Failed to map host address {}. Error: {}.",
binding_addr, err
);
}
}
}
}
Author
Ruben Harutyunyan (@Vagr9K)