stun-coder 2.0.0

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.
Documentation
use crate::{check_for_stun_message_header, StunAttribute, StunMessage};

/// Utility function to test sample payloads
fn check_sample_integrity(sample_bytes: &[u8], integrity_key: Option<&str>) {
    // Decode the message
    // This checks the message validity, fingerprint, integrity.
    let decoded_msg = StunMessage::decode(sample_bytes, integrity_key).unwrap();

    // Re-encode the message
    let re_encoded_msg = decoded_msg.encode(integrity_key).unwrap();

    // Make sure we get the exact same initial binary representation
    assert_eq!(re_encoded_msg, sample_bytes);
}

/// Tests the existence of a partial message (only header)
#[test]
fn check_for_message() {
    let bytes = vec![
        0x00, 0x01, 0x00, 0x58, 0x21, 0x12, 0xa4, 0x42, 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6,
        0x86, 0xfa, 0x87, 0xdf, 0xae,
    ];

    let message_existence = check_for_stun_message_header(&bytes[0..20]);

    assert!(message_existence.is_some());
}

/// Tests binding message creation
#[test]
fn create_request() {
    // Set a predetermined transaction_id.
    // Otherwise a random one will be generated and the check will fail
    let transaction_id = [
        1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8, 11u8, 12u8,
    ];

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

    let encoded_message = message.encode(Some("TEST_PASS")).unwrap();

    // Prerecorded binary representation
    let encoded_match = vec![
        0x0, 0x1, 0x0, 0x34, 0x21, 0x12, 0xA4, 0x42, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
        0xA, 0xB, 0xC, 0x80, 0x22, 0x0, 0xF, 0x72, 0x75, 0x73, 0x74, 0x2D, 0x73, 0x74, 0x75, 0x6E,
        0x2D, 0x63, 0x6F, 0x64, 0x65, 0x72, 0x0, 0x0, 0x8, 0x0, 0x14, 0xC8, 0x8C, 0xFE, 0xB3, 0x58,
        0x66, 0x2D, 0x17, 0xB5, 0x64, 0xD3, 0x54, 0xF1, 0xBD, 0xAE, 0x34, 0x4E, 0x6C, 0xD4, 0xBC,
        0x80, 0x28, 0x0, 0x4, 0xC6, 0x59, 0xEF, 0x95,
    ];

    // Make sure the result matches
    assert_eq!(encoded_message, encoded_match);
}

/// Tests [Sample IPv4 request](https://tools.ietf.org/html/rfc5769#section-2.1) decoding/recoding (based on [RFC5769](https://tools.ietf.org/html/rfc5769))
#[test]
fn binding_request_message() {
    let msg_bytes: Vec<u8> = vec![
        0x00, 0x01, 0x00, 0x58, 0x21, 0x12, 0xa4, 0x42, 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6,
        0x86, 0xfa, 0x87, 0xdf, 0xae, 0x80, 0x22, 0x00, 0x10, 0x53, 0x54, 0x55, 0x4e, 0x20, 0x74,
        0x65, 0x73, 0x74, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x00, 0x24, 0x00, 0x04, 0x6e,
        0x00, 0x01, 0xff, 0x80, 0x29, 0x00, 0x08, 0x93, 0x2f, 0xf9, 0xb1, 0x51, 0x26, 0x3b, 0x36,
        0x00, 0x06, 0x00, 0x09, 0x65, 0x76, 0x74, 0x6a, 0x3a, 0x68, 0x36, 0x76, 0x59, 0x00, 0x00,
        0x00, 0x00, 0x08, 0x00, 0x14, 0x79, 0x7, 0xC2, 0xD2, 0xED, 0xBF, 0xEA, 0x48, 0xE, 0x4C,
        0x76, 0xD8, 0x29, 0x62, 0xD5, 0xC3, 0x74, 0x2A, 0xF9, 0xE3, 0x80, 0x28, 0x00, 0x04, 0xE3,
        0x52, 0x92, 0x8D,
    ];

    let integrity_key = Some("VOkJxbRl1RmTxUk/WvJxBt");

    check_sample_integrity(&msg_bytes, integrity_key);
}

/// Tests [Sample IPv4 response](https://tools.ietf.org/html/rfc5769#section-2.2) decoding/recoding (based on [RFC5769](https://tools.ietf.org/html/rfc5769))
#[test]
fn binding_request_message_with_lta() {
    let msg_bytes: Vec<u8> = vec![
        0x00, 0x01, 0x00, 0x60, 0x21, 0x12, 0xa4, 0x42, 0x78, 0xad, 0x34, 0x33, 0xc6, 0xad, 0x72,
        0xc0, 0x29, 0xda, 0x41, 0x2e, 0x00, 0x06, 0x00, 0x12, 0xe3, 0x83, 0x9e, 0xe3, 0x83, 0x88,
        0xe3, 0x83, 0xaa, 0xe3, 0x83, 0x83, 0xe3, 0x82, 0xaf, 0xe3, 0x82, 0xb9, 0x00, 0x00, 0x00,
        0x15, 0x00, 0x1c, 0x66, 0x2f, 0x2f, 0x34, 0x39, 0x39, 0x6b, 0x39, 0x35, 0x34, 0x64, 0x36,
        0x4f, 0x4c, 0x33, 0x34, 0x6f, 0x4c, 0x39, 0x46, 0x53, 0x54, 0x76, 0x79, 0x36, 0x34, 0x73,
        0x41, 0x00, 0x14, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6f, 0x72,
        0x67, 0x00, 0x00, 0x08, 0x00, 0x14, 0xf6, 0x70, 0x24, 0x65, 0x6d, 0xd6, 0x4a, 0x3e, 0x02,
        0xb8, 0xe0, 0x71, 0x2e, 0x85, 0xc9, 0xa2, 0x8c, 0xa8, 0x96, 0x66,
    ];

    let integrity_key = Some("TheMatrIX");

    check_sample_integrity(&msg_bytes, integrity_key);
}

/// Tests [Sample IPv6 response](https://tools.ietf.org/html/rfc5769#section-2.3) decoding/recoding (based on [RFC5769](https://tools.ietf.org/html/rfc5769))
#[test]
fn binding_response() {
    let msg_bytes: Vec<u8> = vec![
        0x01, 0x01, 0x00, 0x3c, 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, 0x08, 0x00, 0x01, 0xa1, 0x47, 0xe1,
        0x12, 0xa6, 0x43, 0x00, 0x08, 0x00, 0x14, 0x5D, 0x6B, 0x58, 0xBE, 0xAD, 0x94, 0xE0, 0x7E,
        0xEF, 0xD, 0xFC, 0x12, 0x82, 0xA2, 0xBD, 0x8, 0x43, 0x14, 0x10, 0x28, 0x80, 0x28, 0x00,
        0x04, 0x25, 0x16, 0x7A, 0x15,
    ];

    let integrity_key = Some("VOkJxbRl1RmTxUk/WvJxBt");

    check_sample_integrity(&msg_bytes, integrity_key);
}

/// Tests [ Sample Request with Long-Term Authentication](https://tools.ietf.org/html/rfc5769#section-2.4) decoding/recoding (based on [RFC5769](https://tools.ietf.org/html/rfc5769))
#[test]
fn binding_response_ipv6() {
    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");

    check_sample_integrity(&msg_bytes, integrity_key);
}

/// Create and test an error response
#[test]
fn error_response() {
    let response_buf = vec![
        0x1, 0x11, 0x0, 0x30, 0x21, 0x12, 0xA4, 0x42, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
        0xA, 0xB, 0xC, 0x0, 0x9, 0x0, 0x16, 0x0, 0x0, 0x4, 0x14, 0x55, 0x6E, 0x6B, 0x6E, 0x6F,
        0x77, 0x6E, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2E, 0x0, 0x0,
        0x0, 0xA, 0x0, 0x6, 0x0, 0xC, 0x0, 0xE, 0x0, 0x10, 0x0, 0x0, 0x80, 0x28, 0x0, 0x4, 0x24,
        0xE, 0xF3, 0x0,
    ];

    check_sample_integrity(&response_buf, None);
}

/// Big test that includes all the attributes
#[test]
fn big_test() {
    let msg_bytes = vec![
        0x0, 0x1, 0x0, 0xC0, 0x21, 0x12, 0xA4, 0x42, 0x6, 0xB1, 0x97, 0x6F, 0x1E, 0xF6, 0x64, 0x5D,
        0xE7, 0xC0, 0x33, 0x73, 0x0, 0x1, 0x0, 0x14, 0x0, 0x2, 0x7, 0xD0, 0x0, 0x0, 0x0, 0x0, 0x0,
        0x0, 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xC0, 0xA, 0x2, 0xFF, 0x0, 0x20, 0x0, 0x14, 0x0, 0x2,
        0x26, 0xC2, 0x21, 0x12, 0xA4, 0x42, 0x6, 0xB1, 0x97, 0x6F, 0x1E, 0xF6, 0x9B, 0xA2, 0x27,
        0xCA, 0x31, 0x8C, 0x0, 0x24, 0x0, 0x4, 0x0, 0x0, 0x7, 0xD0, 0x80, 0x22, 0x0, 0xF, 0x72,
        0x75, 0x73, 0x74, 0x2D, 0x73, 0x74, 0x75, 0x6E, 0x2D, 0x63, 0x6F, 0x64, 0x65, 0x72, 0x0,
        0x80, 0x23, 0x0, 0x14, 0x0, 0x2, 0x7, 0xD0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
        0x0, 0xFF, 0xFF, 0xC0, 0xA, 0x2, 0xFF, 0x80, 0x29, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
        0x7, 0xD0, 0x80, 0x2A, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xD0, 0x0, 0x15, 0x0,
        0x4, 0x54, 0x45, 0x53, 0x54, 0x0, 0x25, 0x0, 0x0, 0x0, 0x6, 0x0, 0x8, 0x55, 0x53, 0x45,
        0x52, 0x4E, 0x41, 0x4D, 0x45, 0x0, 0x14, 0x0, 0x5, 0x52, 0x45, 0x41, 0x4C, 0x4D, 0x0, 0x0,
        0x0, 0x0, 0x8, 0x0, 0x14, 0x7, 0x33, 0x2F, 0x0, 0x54, 0x6, 0xC1, 0x73, 0x1D, 0xA6, 0x79,
        0xA7, 0xE, 0xE8, 0xC7, 0x35, 0x25, 0x5C, 0x87, 0x1A, 0x80, 0x28, 0x0, 0x4, 0x79, 0x96,
        0x1B, 0x65,
    ];

    let integrity_key = Some("PASS");

    check_sample_integrity(&msg_bytes, integrity_key);
}