diff --git a/README.md b/README.md index 62670b4..5a2f972 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,8 @@ Agate also supports different certificates for different hostnames, see the sect If you want to serve the same content for multiple domains, you can instead disable the hostname check by not specifying `--hostname`. In this case Agate will disregard a request's hostname apart from checking that there is one. +When one or more `--hostname`s are specified, Agate will check that the hostnames and port in request URLs match the specified hostnames and the listening ports. If Agate is behind a proxy on another port and receives a request wil an URL specifying the proxy port, this port may not match one of Agate's listening ports and the request will be rejected: it is possible to disable the port check with `--skip-port-check`. + ### Certificates Agate has support for using multiple certificates with the `--certs` option. Agate will thus always require that a client uses SNI, which should not be a problem since the Gemini specification also requires SNI to be used. diff --git a/src/main.rs b/src/main.rs index 4f81dce..c067d97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -82,6 +82,7 @@ struct Args { log_ips: bool, only_tls13: bool, central_config: bool, + skip_port_check: bool, } fn args() -> Result { @@ -140,6 +141,11 @@ fn args() -> Result { "ed25519", "Generate keys using the Ed25519 signature algorithm instead of the default ECDSA.", ); + opts.optflag( + "", + "skip-port-check", + "Skip URL port check even when a hostname is specified.", + ); let matches = opts.parse(&args[1..]).map_err(|f| f.to_string())?; @@ -263,6 +269,7 @@ fn args() -> Result { log_ips: matches.opt_present("log-ip"), only_tls13: matches.opt_present("only-tls13"), central_config: matches.opt_present("central-conf"), + skip_port_check: matches.opt_present("skip-port-check"), }) } @@ -413,10 +420,13 @@ impl RequestHandle { } // correct port - if let Some(port) = url.port() { - // Validate that the port in the URL is the same as for the stream this request came in on. - if port != self.stream.get_ref().0.local_addr().unwrap().port() { - return Err((53, "proxy request refused")); + if !ARGS.skip_port_check { + if let Some(port) = url.port() { + // Validate that the port in the URL is the same as for the stream this request + // came in on. + if port != self.stream.get_ref().0.local_addr().unwrap().port() { + return Err((53, "Proxy request refused")); + } } } Ok(url) diff --git a/tests/tests.rs b/tests/tests.rs index 07efe96..7099db7 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -372,6 +372,25 @@ fn port_check() { assert_eq!(page.header.status, Status::ProxyRequestRefused); } +#[test] +/// - port is not checked if the skip option is passed. +fn port_check_skipped() { + let page = get( + &[ + "--addr", + "[::]:19720", + "--hostname", + "example.org", + "--skip-port-check", + ], + addr(19720), + "gemini://example.org:1971/", + ) + .expect("could not get page"); + + assert_eq!(page.header.status, Status::Success); +} + #[test] /// - status for paths with hidden segments is "gone" if file does not exist fn secret_nonexistent() {