#stun #ice #traversal #nat #codec

stun-coder

用于Rust的STUN协议编码和解码器。实现遵循《NAT穿越会话工具(STUN)》规范。也支持由《交互式连接建立(ICE)协议》指定的STUN扩展。

3个稳定版本

2.0.0 2022年5月24日
1.1.2 2022年1月19日
1.0.2 2021年8月7日

#961编码

MIT 协议

100KB
1K SLoC

STUN编码器

STUN编码器是用于Rust的STUN协议编码和解码器。实现遵循《NAT穿越会话工具(STUN)》规范。也支持由《交互式连接建立(ICE)协议》指定的STUN扩展。

用法

创建和编码STUN绑定请求的示例


 // Create a request message
 let message = stun_coder::StunMessage::create_request()
             .add_attribute(stun_coder::StunAttribute::Software {
                 description: String::from("rust-stun-coder"),
             })
             .add_message_integrity()
             .add_fingerprint();

 // Encode it into bytes
 let encoded_message = message.encode(Some("TEST_PASS")).unwrap();

 println!("{:#X?}", encoded_message);

解码具有长期认证的样本请求的示例


// Encoded message
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,
];

// Integrity key used for verification
let integrity_key = Some("VOkJxbRl1RmTxUk/WvJxBt");

// Decode the message
let decoded_msg = stun_coder::StunMessage::decode(&msg_bytes, integrity_key).unwrap();

println!("{:?}", decoded_msg);

获取所有本地接口的服务器反射地址的示例函数

use std::io::{Error, ErrorKind};
use std::net::{SocketAddr, UdpSocket};

// Fetches mapped address of a local Socket
fn get_mapped_addr(binding_addr: SocketAddr) -> Result<SocketAddr, std::io::Error> {
    // Use Google's public STUN server
    let stun_server = "stun.l.google.com:19302";

    // Create a binding message
    let binding_msg = stun_coder::StunMessage::create_request()
        .add_attribute(stun_coder::StunAttribute::Software {
            description: String::from("rust-stun-coder"),
        }) // Add software attribute
        .add_message_integrity() // Add message integrity attribute
        .add_fingerprint(); // Add fingerprint attribute

    let integrity_pass = "STUN_CODER_PASS"; // Integrity password to use

    // Encode the binding_msg
    let bytes = binding_msg.encode(Some(integrity_pass)).unwrap();

    // Open a UDP socket
    let udp_socket = UdpSocket::bind(binding_addr)?;

    // Connect to the STUN server
    udp_socket.connect(stun_server.clone())?;

    // Send the binding request message
    udp_socket.send(&bytes)?;

    // Wait for a response
    let mut response_buf = [0; 32];
    udp_socket.recv(&mut response_buf)?;

    // Decode the response
    let stun_response =
        stun_coder::StunMessage::decode(&response_buf, Some(integrity_pass)).unwrap();

    // Find the XorMappedAddress attribute in the response
    // It will contain our reflexive transport address
    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.",
    ))
}

// Fetches server reflexive addresses of local interfaces
fn get_mapped_addresses() {
    // Gather local interfaces
    let local_interfaces = get_if_addrs::get_if_addrs().unwrap();

    // Attempt to get a mapped address for each one of them
    for interface in local_interfaces.iter() {
        // Exclude loopback interfaces
        if interface.is_loopback() {
            continue;
        }

        // Form a local socket for the interface on port 2000
        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
                );
            }
        }
    }
}

作者

Ruben Harutyunyan (@Vagr9K)

依赖

~7MB
~136K SLoC