diff --git a/Cargo.lock b/Cargo.lock index 59093f03a7031b9a77b234e09a5915dc0ef6483f..e3d76404c2d3bfb83632a079ab1e8c0e4e5d2a5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -189,6 +189,23 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-server-dual-protocol" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1a8f5076b5dbfeb706bcce30fe73caf20971e6e5ca80b83a7f1d990e73e185" +dependencies = [ + "axum-server", + "bytes", + "http", + "hyper", + "pin-project", + "tokio", + "tokio-rustls", + "tokio-util", + "tower-layer", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -394,6 +411,7 @@ dependencies = [ "async-trait", "axum", "axum-server", + "axum-server-dual-protocol", "base64", "bytes", "clap", @@ -444,6 +462,7 @@ dependencies = [ "tracing-opentelemetry", "tracing-subscriber", "trust-dns-resolver", + "urlencoding", "webpage", ] diff --git a/Cargo.toml b/Cargo.toml index ce37ee71e1531cbb2861ef6362408e0581e8eac7..30e734f4df35e9994746cdc3161e2a85d031fa92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,6 +108,12 @@ rocksdb = { version = "0.22.0", default-features = true, features = ["multi-thre either = { version = "1.10.0", features = ["serde"] } +# to listen on both HTTP and HTTPS +axum-server-dual-protocol = { version = "0.5.2", optional = true } + +# to encode/decode percent URIs when conduwuit is running without a reverse proxy +urlencoding = "2.1.3" + [target.'cfg(unix)'.dependencies] nix = { version = "0.28.0", features = ["resource"] } @@ -126,6 +132,7 @@ zstd_compression = [] #compression = ["tower-http/compression-full"] sha256_media = [] io_uring = ["rocksdb/io-uring"] +axum_dual_protocol = ["axum-server-dual-protocol"] [[bin]] name = "conduit" diff --git a/complement/Dockerfile b/complement/Dockerfile index a452b09d232ac2afb95ed34ef4d43f0fb88b81d5..e168b1b8ced5961f2d6f6ccd21c221775a4ee3cb 100644 --- a/complement/Dockerfile +++ b/complement/Dockerfile @@ -8,31 +8,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY Cargo.toml Cargo.toml COPY Cargo.lock Cargo.lock COPY src src -RUN cargo build --release \ +RUN cargo build --release --features=axum_dual_protocol \ && mv target/release/conduit conduit \ && rm -rf target -# Install caddy -RUN apt-get update \ - && apt-get install -y \ - debian-keyring \ - debian-archive-keyring \ - apt-transport-https \ - curl \ - && curl -1sLf 'https://dl.cloudsmith.io/public/caddy/testing/gpg.key' \ - | gpg --dearmor -o /usr/share/keyrings/caddy-testing-archive-keyring.gpg \ - && curl -1sLf 'https://dl.cloudsmith.io/public/caddy/testing/debian.deb.txt' \ - | tee /etc/apt/sources.list.d/caddy-testing.list \ - && apt-get update \ - && apt-get install -y caddy - COPY conduwuit-example.toml conduit.toml -COPY complement/caddy.json caddy.json ENV SERVER_NAME=localhost ENV CONDUIT_CONFIG=/workdir/conduit.toml -RUN sed -i "s/port = 6167/port = 8008/g" conduit.toml +RUN sed -i "s/port = 6167/port = [8448, 8008]/g" conduit.toml RUN sed -i "s/allow_registration = false/allow_registration = true/g" conduit.toml RUN sed -i "s/registration_token/#registration_token/g" conduit.toml RUN sed -i "s/allow_guest_registration = false/allow_guest_registration = true/g" conduit.toml @@ -41,22 +26,39 @@ RUN sed -i "s/allow_public_room_directory_without_auth = false/allow_public_room RUN sed -i "s/allow_device_name_federation = false/allow_device_name_federation = true/g" conduit.toml RUN sed -i "/\"127.0.0.0/d" conduit.toml RUN sed -i "/\"10.0.0.0/d" conduit.toml +RUN sed -i "/\"172.16.0.0/d" conduit.toml RUN sed -i "/\"::1/d" conduit.toml -RUN echo "log = \"warn\"" >> conduit.toml -RUN echo 'yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse = true' >> conduit.toml -RUN echo 'allow_outgoing_presence = true' >> conduit.toml -RUN echo 'allow_incoming_presence = true' >> conduit.toml -RUN echo 'allow_local_presence = true' >> conduit.toml +RUN sed -i "s/#log = \"warn\"/log = \"debug\"/g" conduit.toml +RUN sed -i 's/#\strusted_servers\s=\s\["matrix.org"\]/trusted_servers = []/g' conduit.toml +RUN sed -i 's/# `yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse` to/yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse = true/g' conduit.toml +RUN sed -i "s/allow_outgoing_presence = false/allow_outgoing_presence = true/g" conduit.toml +RUN sed -i "s/allow_incoming_presence = false/allow_incoming_presence = true/g" conduit.toml +RUN sed -i "s/allow_local_presence = false/allow_local_presence = true/g" conduit.toml RUN sed -i "s/address = \"127.0.0.1\"/address = \"0.0.0.0\"/g" conduit.toml -RUN echo '[global.tls]' >> conduit.toml -RUN echo 'certs = "/complement/ca/ca.crt"' >> conduit.toml -RUN echo 'key = "/complement/ca/ca.key"' >> conduit.toml + +# https://stackoverflow.com/questions/76049656/unexpected-notvalidforname-with-rusts-tonic-with-tls +RUN echo "authorityKeyIdentifier=keyid,issuer" >> extensions.ext +RUN echo "basicConstraints=CA:FALSE" >> extensions.ext +RUN echo 'subjectAltName = @alt_names' >> extensions.ext +RUN echo '[alt_names]' >> extensions.ext +RUN echo "DNS.1 = servername" >> extensions.ext +RUN echo "IP.1 = ipaddress" >> extensions.ext + EXPOSE 8008 8448 CMD uname -a && \ + cp -f -v /complement/ca/ca.crt /usr/local/share/ca-certificates/complement.crt && \ + update-ca-certificates && \ + sed -i "s/servername/${SERVER_NAME}/g" extensions.ext && \ + sed -i "s/ipaddress/`hostname -i`/g" extensions.ext && \ + openssl req -newkey rsa:2048 -noenc -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=$SERVER_NAME" -keyout $SERVER_NAME.key -out $SERVER_NAME.csr && \ + openssl x509 -signkey $SERVER_NAME.key -in $SERVER_NAME.csr -req -days 2 -out $SERVER_NAME.crt && \ + openssl x509 -req -CA /complement/ca/ca.crt -CAkey /complement/ca/ca.key -in $SERVER_NAME.csr -out $SERVER_NAME.crt -days 2 -CAcreateserial -extfile extensions.ext && \ sed -i "s/#server_name = \"your.server.name\"/server_name = \"${SERVER_NAME}\"/g" conduit.toml && \ - sed -i "s/your.server.name/${SERVER_NAME}/g" caddy.json && \ - caddy start --config caddy.json > /dev/null && \ + sed -i 's/#\s\[global.tls\]/\[global.tls\]/g' conduit.toml && \ + sed -i "s/# certs = \"\/path\/to\/my\/certificate.crt\"/certs = \"${SERVER_NAME}.crt\"/g" conduit.toml && \ + sed -i "s/# key = \"\/path\/to\/my\/private_key.key\"/key = \"${SERVER_NAME}.key\"/g" conduit.toml && \ + sed -i "s/#dual_protocol = false/dual_protocol = true/g" conduit.toml && \ /workdir/conduit diff --git a/complement/caddy.json b/complement/caddy.json deleted file mode 100644 index ea52c2c98165b0cb1f733450722f1690ff470406..0000000000000000000000000000000000000000 --- a/complement/caddy.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "logging": { - "logs": { - "default": { - "level": "WARN" - } - } - }, - "apps": { - "http": { - "https_port": 8448, - "servers": { - "srv0": { - "listen": [":8448"], - "routes": [{ - "match": [{ - "host": ["your.server.name"] - }], - "handle": [{ - "handler": "subroute", - "routes": [{ - "handle": [{ - "handler": "reverse_proxy", - "upstreams": [{ - "dial": "127.0.0.1:8008" - }] - }] - }] - }], - "terminal": true - }], - "tls_connection_policies": [{ - "match": { - "sni": ["your.server.name"] - } - }] - } - } - }, - "pki": { - "certificate_authorities": { - "local": { - "name": "Complement CA", - "root": { - "certificate": "/complement/ca/ca.crt", - "private_key": "/complement/ca/ca.key" - }, - "intermediate": { - "certificate": "/complement/ca/ca.crt", - "private_key": "/complement/ca/ca.key" - } - } - } - }, - "tls": { - "automation": { - "policies": [{ - "subjects": ["your.server.name"], - "issuers": [{ - "module": "internal" - }], - "on_demand": true - }, { - "issuers": [{ - "module": "internal", - "ca": "local" - }] - }] - } - } - } -} \ No newline at end of file diff --git a/conduwuit-example.toml b/conduwuit-example.toml index c5ec97b9ea554645e35f14d5937a9a16310cd0ff..829dbffa45e236b7de53ef5297f8a9523289de1c 100644 --- a/conduwuit-example.toml +++ b/conduwuit-example.toml @@ -287,4 +287,9 @@ allow_check_for_updates = true # It is strongly recommended you use a reverse proxy instead. This is primarily relevant for test suites like complement that require a private CA setup. # [global.tls] # certs = "/path/to/my/certificate.crt" -# key = "/path/to/my/private_key.key" \ No newline at end of file +# key = "/path/to/my/private_key.key" +# +# Whether to listen and allow for HTTP and HTTPS connections (insecure!) +# This config option is only available if conduwuit was built with `axum_dual_protocol` feature (not default feature) +# Defaults to false +#dual_protocol = false \ No newline at end of file diff --git a/src/config/mod.rs b/src/config/mod.rs index b5e9002b4253e0a9a596fb2cf0858ba18a1f86de..604da5467ec78c7b76df7950c0e9ad0cf2cd8d13 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -170,6 +170,10 @@ pub struct Config { pub struct TlsConfig { pub certs: String, pub key: String, + #[serde(default)] + /// Whether to listen and allow for HTTP and HTTPS connections (insecure!) + /// Only works / does something if the `axum_dual_protocol` feature flag was built + pub dual_protocol: bool, } const DEPRECATED_KEYS: &[&str] = &["cache_capacity"]; diff --git a/src/main.rs b/src/main.rs index 8aae73346414f74c0836ce86f3d11bab0c4d7774..d9fd1682d4f6716c487e94409e1a5220c50a90fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,6 +43,9 @@ use clap::Parser; +#[cfg(feature = "axum_dual_protocol")] +use axum_server_dual_protocol::ServerExt; + pub use conduit::*; // Re-export everything from the library crate #[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))] @@ -265,9 +268,11 @@ async fn run_server() -> io::Result<()> { }; let x_requested_with = HeaderName::from_static("x-requested-with"); + let x_forwarded_for = HeaderName::from_static("x-forwarded-for"); let middlewares = ServiceBuilder::new() .sensitive_headers([header::AUTHORIZATION]) + .sensitive_request_headers([x_forwarded_for].into()) .layer(axum::middleware::from_fn(spawn_task)) .layer( TraceLayer::new_for_http() @@ -365,24 +370,50 @@ async fn run_server() -> io::Result<()> { ); info!("Note: It is strongly recommended that you use a reverse proxy instead of running conduwuit directly with TLS."); let conf = RustlsConfig::from_pem_file(&tls.certs, &tls.key).await?; - debug!("Rustlsconfig: {:?}", conf); - let mut join_set = JoinSet::new(); - for addr in &addrs { - join_set.spawn( - bind_rustls(*addr, conf.clone()) - .handle(handle.clone()) - .serve(app.clone()), + if cfg!(feature = "axum_dual_protocol") { + info!( + "conduwuit was built with axum_dual_protocol feature to listen on both HTTP and HTTPS. This will only take affect if `dual_protocol` is enabled in `[global.tls]`" ); } + let mut join_set = JoinSet::new(); + + if cfg!(feature = "axum_dual_protocol") && tls.dual_protocol { + #[cfg(feature = "axum_dual_protocol")] + for addr in &addrs { + join_set.spawn( + axum_server_dual_protocol::bind_dual_protocol(*addr, conf.clone()) + .set_upgrade(false) + .handle(handle.clone()) + .serve(app.clone()), + ); + } + } else { + for addr in &addrs { + join_set.spawn( + bind_rustls(*addr, conf.clone()) + .handle(handle.clone()) + .serve(app.clone()), + ); + } + } + #[cfg(feature = "systemd")] let _ = sd_notify::notify(true, &[sd_notify::NotifyState::Ready]); - info!( - "Listening on {:?} with TLS certificates {}", + if cfg!(feature = "axum_dual_protocol") && tls.dual_protocol { + warn!( + "Listening on {:?} with TLS certificate {} and supporting plain text (HTTP) connections too (insecure!)", addrs, &tls.certs ); + } else { + info!( + "Listening on {:?} with TLS certificate {}", + addrs, &tls.certs + ); + } + join_set.join_next().await; } None => {