~zethra/stargazer

69199eabd34a2b733f9e4876ad0f8fca82a6d002 — Ben Aaron Goldberg 18 days ago 4dc46d5
FIX 19: IPv6 listeners no longer conflict with IPv4

IPv6 listener now always have IPV6_V6ONLY set so that they don't
conflict with IPv4 listeners unexpectedly.

This change did require adding net2 as a dependency.

Signed-off-by: Ben Aaron Goldberg <ben@benaaron.dev>
5 files changed, 47 insertions(+), 9 deletions(-)

M Cargo.lock
M Cargo.toml
M doc/stargazer-ini.scd
M src/main.rs
M test_data/testing.ini
M Cargo.lock => Cargo.lock +14 -0
@@ 1,5 1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "ahash"
version = "0.4.7"


@@ 576,6 578,17 @@ dependencies = [
]

[[package]]
name = "net2"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
dependencies = [
 "cfg-if 0.1.10",
 "libc",
 "winapi",
]

[[package]]
name = "nom"
version = "6.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1001,6 1014,7 @@ dependencies = [
 "libc",
 "log",
 "mime_guess",
 "net2",
 "num_cpus",
 "once_cell",
 "percent-encoding",

M Cargo.toml => Cargo.toml +1 -0
@@ 59,6 59,7 @@ uriparse = "0.6"
users = "0.11"
cfg-if = "1.0"
libc = "0.2"
net2 = "0.2"

[dependencies.chrono]
version = "0.4"

M doc/stargazer-ini.scd => doc/stargazer-ini.scd +3 -1
@@ 25,7 25,9 @@ domains serviced by the *stargazer* daemon.
	A space-separated list of addresses that the daemon shall bind to. Each
	address shall take the format *address*:*port*. If :*port* is omitted,
	1965 (the default Gemini port) is presumed. To specify an IPv6 address,
	enclose it in *[]*, e.g. *[::]*.
	enclose it in *[]*, e.g. *[::]*. Note that IPv6 listener always have
	IPV6_V6ONLY set, so they will only listen on the IPv6 interface and not also
	IPv4. If you wish to listen on both, specify both.

*connection-logging*
	Whether or not to log connections to stdout. Disabling this may increase

M src/main.rs => src/main.rs +28 -7
@@ 28,7 28,7 @@ use crate::error::{bad_req, ErrorConv, GemError, Result};
use async_channel::{Receiver, Sender};
use async_executor::Executor;
use async_io::Timer;
use async_net::{TcpListener, TcpStream};
use async_net::{SocketAddrV6, TcpListener, TcpStream};
use async_rustls::{server::TlsStream, TlsAcceptor};
use cgi::{serve_cgi, serve_scgi};
use futures_lite::*;


@@ 37,6 37,7 @@ use log::{debug, error, info, warn};
use once_cell::sync::{Lazy, OnceCell};
use router::route;
use std::clone::Clone;
use std::convert::TryFrom;
use std::net::SocketAddr;
use std::panic::catch_unwind;
use std::sync::Arc;


@@ 134,12 135,24 @@ fn main() {
        EXEC.spawn(async move {
            // Start tcp listener
            // Program exits with an error if any fail to bind
            let listener = match TcpListener::bind(addr).await {
                Ok(l) => l,
                Err(e) => {
                    error!("{:#}", e);
                    log::logger().flush();
                    exit(1);
            let listener = match addr {
                SocketAddr::V4(addr) => match TcpListener::bind(addr).await {
                    Ok(l) => l,
                    Err(e) => {
                        error!("{:#}", e);
                        log::logger().flush();
                        exit(1);
                    }
                },
                SocketAddr::V6(addr) => {
                    match create_v6_sock(addr) {
                        Ok(l) => l,
                        Err(e) => {
                            error!("Error creating IPv6 listener: {:#}", e);
                            log::logger().flush();
                            exit(1);
                        }
                    }
                }
            };



@@ 200,6 213,14 @@ fn main() {
    });
}

fn create_v6_sock(addr: &SocketAddrV6) -> Result<TcpListener> {
    let socket_builder = net2::TcpBuilder::new_v6()?;
    socket_builder.only_v6(true)?;
    socket_builder.bind(addr)?;
    let listener = socket_builder.listen(128)?;
    Ok(TcpListener::try_from(listener)?)
}

#[cfg(unix)]
async fn exit_on_sig() -> Result<()> {
    use signal_hook::consts::{SIGINT, SIGTERM};

M test_data/testing.ini => test_data/testing.ini +1 -1
@@ 1,4 1,4 @@
listen = 0.0.0.0 [::1]
listen = 0.0.0.0 [::]

[:tls]
store = ./test_data/store