noita-proxy: socketaddr binding via --host

This allows binding to arbitrary IP addresses (`[2001:db8::1]:12345`, `203.0.113.1:12345`) while still providing compatibility to the previous behaviour of binding to a port on IPv4 only.
The only non-compatible change is that when providing neither a valid `SocketAddr` nor a valid port the code will now err out instead of defaulting to a default port to avoid silently discarding arguments or invalid configurations.
As a result `--host --exe-path` will now fail as `--exe-path` is not a valid address or port.

Minor changes:

- some practically infallible parsing (`Ipv4Addr::UNSPECIFIED`) has also been replaced by infallible typing avoiding unnecessary `unwrap()`s
- typos

Fixes #389

Signed-off-by: benaryorg <binary@benary.org>
This commit is contained in:
benaryorg 2025-06-16 12:20:01 +00:00
parent fa9be0d8b5
commit 1bc016a84f
No known key found for this signature in database
GPG key ID: E2F22C5EDF20119D
2 changed files with 22 additions and 10 deletions

View file

@ -2852,7 +2852,7 @@ fn cli_setup(
pub fn connect_cli(lobby: String, args: Args) { pub fn connect_cli(lobby: String, args: Args) {
let (state, netmaninit, kind, audio, _) = cli_setup(args); let (state, netmaninit, kind, audio, _) = cli_setup(args);
let varient = if lobby.contains(':') { let variant = if lobby.contains(':') {
let p = Peer::connect(lobby.parse().unwrap(), None).unwrap(); let p = Peer::connect(lobby.parse().unwrap(), None).unwrap();
while p.my_id().is_none() { while p.my_id().is_none() {
sleep(Duration::from_millis(100)) sleep(Duration::from_millis(100))
@ -2869,14 +2869,16 @@ pub fn connect_cli(lobby: String, args: Args) {
exit(1) exit(1)
}; };
let player_path = netmaninit.player_path.clone(); let player_path = netmaninit.player_path.clone();
let netman = net::NetManager::new(varient, netmaninit, audio); let netman = net::NetManager::new(variant, netmaninit, audio);
netman.start_inner(player_path, Some(kind)).unwrap(); netman.start_inner(player_path, Some(kind)).unwrap();
} }
pub fn host_cli(port: u16, args: Args) { /// Bind to the provided `bind_addr` with `args` with CLI output only.
///
/// The `bind_addr` is either `Some` address/port pair to bind to, or `None` to use Steam networking.
pub fn host_cli(bind_addr: Option<SocketAddr>, args: Args) {
let (state, netmaninit, kind, audio, lobbytype) = cli_setup(args); let (state, netmaninit, kind, audio, lobbytype) = cli_setup(args);
let varient = if port != 0 { let variant = if let Some(bind_addr) = bind_addr {
let bind_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), port);
let peer = Peer::host(bind_addr, None).unwrap(); let peer = Peer::host(bind_addr, None).unwrap();
PeerVariant::Tangled(peer) PeerVariant::Tangled(peer)
} else if let Some(state) = state { } else if let Some(state) = state {
@ -2895,6 +2897,6 @@ pub fn host_cli(port: u16, args: Args) {
exit(1) exit(1)
}; };
let player_path = netmaninit.player_path.clone(); let player_path = netmaninit.player_path.clone();
let netman = net::NetManager::new(varient, netmaninit, audio); let netman = net::NetManager::new(variant, netmaninit, audio);
netman.start_inner(player_path, Some(kind)).unwrap(); netman.start_inner(player_path, Some(kind)).unwrap();
} }

View file

@ -10,6 +10,11 @@ use std::{
fs::File, fs::File,
io::{self, BufWriter}, io::{self, BufWriter},
panic, panic,
net::{
SocketAddr,
SocketAddrV4,
Ipv4Addr,
},
}; };
use tracing::{error, info, level_filters::LevelFilter}; use tracing::{error, info, level_filters::LevelFilter};
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
@ -81,12 +86,17 @@ async fn main() {
info!("Launch command: {:?}", args.launch_cmd); info!("Launch command: {:?}", args.launch_cmd);
if let Some(host) = args.clone().host { if let Some(host) = args.clone().host {
let port = if host.eq_ignore_ascii_case("steam") { let bind_addr = if host.eq_ignore_ascii_case("steam") {
0 None
} else { } else {
host.parse::<u16>().unwrap_or(5123) // allows binding to both IPv6 and IPv4
host.parse::<SocketAddr>().ok()
// compatibility with providing only the port (which then proceeds to bind to IPv4 only)
.or_else(|| Some(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, host.parse().ok()?))))
.map(Some)
.expect("host argument is neither SocketAddr nor port")
}; };
host_cli(port, args) host_cli(bind_addr, args)
} else if let Some(lobby) = args.clone().lobby { } else if let Some(lobby) = args.clone().lobby {
connect_cli(lobby, args) connect_cli(lobby, args)
} else { } else {