diff options
author | Ali MJ Al-Nasrawy <alimjalnasrawy@gmail.com> | 2021-05-07 00:05:09 +0000 |
---|---|---|
committer | Ali MJ Al-Nasrawy <alimjalnasrawy@gmail.com> | 2021-08-30 04:00:59 +0000 |
commit | 28da05437de8f15df379041a653ee72cf136204b (patch) | |
tree | 37ee3da365dd4207e71805a647204fba45630f7c /src/main.rs | |
parent | Fix -i 0.0.0.0 (diff) | |
download | miniserve-28da05437de8f15df379041a653ee72cf136204b.tar.gz miniserve-28da05437de8f15df379041a653ee72cf136204b.zip |
Fix default binding behaviour
On some platforms, binding to to both "::" and "0.0.0.0" at the same
time is not allowed because "::" may already accepts ipv4 connections.
For other platforms, binding to both is necessary to support ipv4 and
ipv6.
This platform-specific behaviour is due to the variation in the
default value for the socket option "IPV6_ONLY".
Fix this by always setting the "IPv6_ONLY" sockopt to true!
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/src/main.rs b/src/main.rs index 19bd16b..d34f0aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::io; use std::io::Write; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener}; use std::thread; use std::time::Duration; @@ -200,7 +200,7 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { .interfaces .iter() .map(|&interface| SocketAddr::new(interface, miniserve_config.port)) - .collect::<Vec<SocketAddr>>(); + .collect::<Vec<_>>(); let srv = actix_web::HttpServer::new(move || { App::new() @@ -222,14 +222,18 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { }); let srv = socket_addresses.iter().try_fold(srv, |srv, addr| { + let listener = create_tcp_listener(*addr).map_err(|e| { + ContextualError::IoError(format!("Failed to bind server to {}", addr), e) + })?; + #[cfg(feature = "tls")] let srv = match &miniserve_config.tls_rustls_config { - Some(tls_config) => srv.bind_rustls(addr, tls_config.clone()), - None => srv.bind(addr), + Some(tls_config) => srv.listen_rustls(listener, tls_config.clone()), + None => srv.listen(listener), }; #[cfg(not(feature = "tls"))] - let srv = srv.bind(addr); + let srv = srv.listen(listener); srv.map_err(|e| ContextualError::IoError(format!("Failed to bind server to {}", addr), e)) })?; @@ -250,6 +254,19 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { .map_err(|e| ContextualError::IoError("".to_owned(), e)) } +/// Allows us to set low-level socket options +fn create_tcp_listener(addr: SocketAddr) -> io::Result<TcpListener> { + use socket2::{Domain, Protocol, Socket, Type}; + let socket = Socket::new(Domain::for_address(addr), Type::STREAM, Some(Protocol::TCP))?; + if addr.is_ipv6() { + socket.set_only_v6(true)?; + } + socket.set_reuse_address(true)?; + socket.bind(&addr.into())?; + socket.listen(1024 /* Default backlog */)?; + Ok(TcpListener::from(socket)) +} + fn configure_header(conf: &MiniserveConfig) -> middleware::DefaultHeaders { let headers = conf.clone().header; |