For context, my group and I are attempting to build a simple p2p messaging application in Rust with minimal library use. (We DID attempt using libp2p early on, but unfortunately it's incompatible with the key exchange algorithm we're using.)
The users on each end are required to send one another a public key through a third party messaging service before connecting, and we are able to encode the public IP address and the listening port of the program within this public key. (Meaning that the public IP and listening port of the other party will be known by the program at runtime.)
Since we are able to communicate the router's public IP address and the listening port of the program, would it be possible to establish a p2p connection without the need for an external server or port forwarding? If so, is there a simple solution we're not seeing using only the standard library? Currently we're attempting to check for incoming connections using TcpListener (see test code below) and are able to detect connections to localhost on the specified port, but have no access over the network.
We're all college students who are new to networking, so any explanation for what technology we're looking for would be greatly appreciated. We've tried researching hole punching, but to our understanding that requires a third server with a known open port. We were hoping that by broadcasting the IP and listening port directly we could bypass this. We're operating on the school's network, so UPnP is disabled.
use std::net::{TcpListener, TcpStream};
// Simple test script for TcpListener - attempting to listen over the network instead of locally.
// Handle new connections - test program just prints info and allows the connection to close.
fn handle_connection(stream: TcpStream) {
println!("New Client: {}", stream.peer_addr().unwrap());
}
fn main() -> std::io::Result<()> {
// Listen on any IP and let the OS choose a port - works with localhost and local address
// shown from "ipconfig". Does not work with public IP shown in web browsers.
// (This is expected - no open port or specialized incoming communication yet.)
let listener = TcpListener::bind("0.0.0.0:0").unwrap();
// Show listening port for testing purposes.
println!("Listening on: {}", listener.local_addr().unwrap());
// Attempt to connect to all incoming streams.
for stream in listener.incoming() {
match stream {
Ok(stream) => {
handle_connection(stream);
}
Err(_) => {
eprintln!("Connection Error");
}
}
}
Ok(())
}