aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2021-05-07 00:05:09 +0000
committerAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2021-08-30 04:00:59 +0000
commit28da05437de8f15df379041a653ee72cf136204b (patch)
tree37ee3da365dd4207e71805a647204fba45630f7c
parentFix -i 0.0.0.0 (diff)
downloadminiserve-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!
-rw-r--r--Cargo.toml1
-rw-r--r--src/main.rs27
2 files changed, 23 insertions, 5 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 4efc015..f72597a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -53,6 +53,7 @@ http = "0.2"
bytes = "1"
atty = "0.2"
rustls = { version = "0.19", optional = true }
+socket2 = "0.4"
[features]
default = ["tls"]
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;