From a3553b6baa2eb89d7ad407ee92284e477dea5429 Mon Sep 17 00:00:00 2001 From: pradt2 Date: Tue, 23 Aug 2022 20:52:59 +0100 Subject: [PATCH] Added more examples --- examples/{read.rs => simple_read.rs} | 0 examples/{write.rs => simple_write.rs} | 0 examples/stun_client_tcp.rs | 54 ++++++++++++++++++++++++++ examples/stun_client_udp.rs | 50 ++++++++++++++++++++++++ 4 files changed, 104 insertions(+) rename examples/{read.rs => simple_read.rs} (100%) rename examples/{write.rs => simple_write.rs} (100%) create mode 100644 examples/stun_client_tcp.rs create mode 100644 examples/stun_client_udp.rs diff --git a/examples/read.rs b/examples/simple_read.rs similarity index 100% rename from examples/read.rs rename to examples/simple_read.rs diff --git a/examples/write.rs b/examples/simple_write.rs similarity index 100% rename from examples/write.rs rename to examples/simple_write.rs diff --git a/examples/stun_client_tcp.rs b/examples/stun_client_tcp.rs new file mode 100644 index 000000000..dc6dab13f --- /dev/null +++ b/examples/stun_client_tcp.rs @@ -0,0 +1,54 @@ +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") + } +} diff --git a/examples/stun_client_udp.rs b/examples/stun_client_udp.rs new file mode 100644 index 000000000..7793b77c9 --- /dev/null +++ b/examples/stun_client_udp.rs @@ -0,0 +1,50 @@ +use stun_proto::rfc5389::*; + +/** + In this example, we are calling a UDP 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 socket = std::net::UdpSocket::bind("0.0.0.0:0").unwrap(); + socket.send_to(&buf[0..bytes_written as usize], "stun.stunprotocol.org:3478").unwrap(); + + socket.set_read_timeout(Some(std::time::Duration::from_millis(1000))).unwrap(); + let bytes_read = socket.recv(&mut buf).unwrap(); + + 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") + } +}