Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http: use separate sockets for IPv4 and IPv6 #221

Merged
merged 1 commit into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/actions/test-file-transfers/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ address_ipv4 = '127.0.0.1:3000'" > udp.toml
echo "log_level = 'debug'

[network]
address = '127.0.0.1:3004'" > http.toml
address_ipv4 = '127.0.0.1:3004'" > http.toml
./target/debug/aquatic http -c http.toml > "$HOME/http.log" 2>&1 &

# HTTP with TLS
echo "log_level = 'debug'

[network]
address = '127.0.0.1:3001'
address_ipv4 = '127.0.0.1:3001'
enable_tls = true
tls_certificate_path = './server.crt'
tls_private_key_path = './key.pk8'
Expand Down
4 changes: 2 additions & 2 deletions crates/http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ Generate the configuration file:
./target/release/aquatic_http -p > "aquatic-http-config.toml"
```

Make necessary adjustments to the file. You will likely want to adjust `address`
(listening address) under the `network` section.
Make necessary adjustments to the file. You will likely want to adjust
listening addresses under the `network` section.

To run over TLS, configure certificate and private key files.

Expand Down
1 change: 1 addition & 0 deletions crates/http/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use aquatic_http_protocol::{
use glommio::channels::shared_channel::SharedSender;
use slotmap::new_key_type;

#[allow(dead_code)]
#[derive(Copy, Clone, Debug)]
pub struct ConsumerId(pub usize);

Expand Down
51 changes: 31 additions & 20 deletions crates/http/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::{net::SocketAddr, path::PathBuf};
use std::{
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
path::PathBuf,
};

use aquatic_common::{access_list::AccessListConfig, privileges::PrivilegeConfig};
use aquatic_toml_config::TomlConfig;
Expand Down Expand Up @@ -70,25 +73,24 @@ impl aquatic_common::cli::Config for Config {
#[derive(Clone, Debug, PartialEq, TomlConfig, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct NetworkConfig {
/// Bind to this address
/// Use IPv4
pub use_ipv4: bool,
/// Use IPv6
pub use_ipv6: bool,
/// IPv4 address and port
///
/// When providing an IPv4 style address, only IPv4 traffic will be
/// handled. Examples:
/// - "0.0.0.0:3000" binds to port 3000 on all network interfaces
/// - "127.0.0.1:3000" binds to port 3000 on the loopback interface
/// (localhost)
/// Examples:
/// - Use 0.0.0.0:3000 to bind to all interfaces on port 3000
/// - Use 127.0.0.1:3000 to bind to the loopback interface (localhost) on
/// port 3000
pub address_ipv4: SocketAddrV4,
/// IPv6 address and port
///
/// When it comes to IPv6-style addresses, behaviour is more complex and
/// differs between operating systems. On Linux, to accept both IPv4 and
/// IPv6 traffic on any interface, use "[::]:3000". Set the "only_ipv6"
/// flag below to limit traffic to IPv6. To bind to the loopback interface
/// and only accept IPv6 packets, use "[::1]:3000" and set the only_ipv6
/// flag. Receiving both IPv4 and IPv6 traffic on loopback is currently
/// not supported. For other operating systems, please refer to their
/// respective documentation.
pub address: SocketAddr,
/// Only allow access over IPv6
pub only_ipv6: bool,
/// Examples:
/// - Use [::]:3000 to bind to all interfaces on port 3000
/// - Use [::1]:3000 to bind to the loopback interface (localhost) on
/// port 3000
pub address_ipv6: SocketAddrV6,
/// Maximum number of pending TCP connections
pub tcp_backlog: i32,
/// Enable TLS
Expand Down Expand Up @@ -125,21 +127,30 @@ pub struct NetworkConfig {
/// header. Works with typical multi-IP setups (e.g., "X-Forwarded-For")
/// as well as for single-IP setups (e.g., nginx "X-Real-IP")
pub reverse_proxy_ip_header_format: ReverseProxyPeerIpHeaderFormat,
/// Set flag on IPv6 socket to only accept IPv6 traffic.
///
/// This should typically be set to true unless your OS does not support
/// double-stack sockets (that is, sockets that receive both IPv4 and IPv6
/// packets).
pub set_only_ipv6: bool,
}

impl Default for NetworkConfig {
fn default() -> Self {
Self {
address: SocketAddr::from(([0, 0, 0, 0], 3000)),
use_ipv4: true,
use_ipv6: true,
address_ipv4: SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 3000),
address_ipv6: SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 3000, 0, 0),
enable_tls: false,
tls_certificate_path: "".into(),
tls_private_key_path: "".into(),
only_ipv6: false,
tcp_backlog: 1024,
keep_alive: true,
runs_behind_reverse_proxy: false,
reverse_proxy_ip_header_name: "X-Forwarded-For".into(),
reverse_proxy_ip_header_format: Default::default(),
set_only_ipv6: true,
}
}
}
Expand Down
24 changes: 21 additions & 3 deletions crates/http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ const SHARED_CHANNEL_SIZE: usize = 1024;
pub fn run(config: Config) -> ::anyhow::Result<()> {
let mut signals = Signals::new([SIGUSR1])?;

if !(config.network.use_ipv4 || config.network.use_ipv6) {
return Result::Err(anyhow::anyhow!(
"Both use_ipv4 and use_ipv6 can not be set to false"
));
}

let state = State::default();

update_access_list(&config.access_list, &state.access_list)?;
Expand All @@ -35,7 +41,14 @@ pub fn run(config: Config) -> ::anyhow::Result<()> {
config.socket_workers + config.swarm_workers,
SHARED_CHANNEL_SIZE,
);
let priv_dropper = PrivilegeDropper::new(config.privileges.clone(), config.socket_workers);

let num_sockets_per_worker =
if config.network.use_ipv4 { 1 } else { 0 } + if config.network.use_ipv6 { 1 } else { 0 };

let priv_dropper = PrivilegeDropper::new(
config.privileges.clone(),
config.socket_workers * num_sockets_per_worker,
);

let opt_tls_config = if config.network.enable_tls {
Some(Arc::new(ArcSwap::from_pointee(create_rustls_config(
Expand All @@ -55,7 +68,12 @@ pub fn run(config: Config) -> ::anyhow::Result<()> {
let state = state.clone();
let opt_tls_config = opt_tls_config.clone();
let request_mesh_builder = request_mesh_builder.clone();
let priv_dropper = priv_dropper.clone();

let mut priv_droppers = Vec::new();

for _ in 0..num_sockets_per_worker {
priv_droppers.push(priv_dropper.clone());
}

let handle = Builder::new()
.name(format!("socket-{:02}", i + 1))
Expand All @@ -68,7 +86,7 @@ pub fn run(config: Config) -> ::anyhow::Result<()> {
state,
opt_tls_config,
request_mesh_builder,
priv_dropper,
priv_droppers,
server_start_instant,
i,
))
Expand Down
Loading
Loading