feat(socket): support advanced routing configuration for client socket
Rust CI / cargo fmt (push) Successful in 16s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 35s
Rust CI / cargo clippy (push) Successful in 36s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 51s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo doc (push) Successful in 21s
Supply chain / cargo-deny advisories (push) Successful in 9s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 30s
Supply chain / cargo-deny bans licenses sources (push) Successful in 8s
Supply chain / actionlint (push) Successful in 2s
Netem Interop / netem interop (push) Successful in 1m5s
Rust CI / cargo fmt (push) Successful in 16s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 35s
Rust CI / cargo clippy (push) Successful in 36s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 51s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo doc (push) Successful in 21s
Supply chain / cargo-deny advisories (push) Successful in 9s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 30s
Supply chain / cargo-deny bans licenses sources (push) Successful in 8s
Supply chain / actionlint (push) Successful in 2s
Netem Interop / netem interop (push) Successful in 1m5s
Enable binding to a specific network interface, applying a firewall mark, or selecting a routing table (FIB) for outgoing packets on supported platforms.
This commit is contained in:
3 files changed
+77
No files matched your search
@@ -231,6 +231,15 @@ pub struct SocketConfig {
|
|||||||
/// `None` binds to an unspecified address with an ephemeral port matching
|
/// `None` binds to an unspecified address with an ephemeral port matching
|
||||||
/// the selected remote address family.
|
/// the selected remote address family.
|
||||||
pub bind_addr: Option<SocketAddr>,
|
pub bind_addr: Option<SocketAddr>,
|
||||||
|
/// Network interface to bind this socket to (`SO_BINDTODEVICE`).
|
||||||
|
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||||
|
pub bind_to_device: Option<String>,
|
||||||
|
/// Firewall mark applied to outgoing packets (`SO_MARK`).
|
||||||
|
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||||
|
pub mark: Option<u32>,
|
||||||
|
/// FreeBSD FIB used for routing this socket (`SO_SETFIB`).
|
||||||
|
#[cfg(target_os = "freebsd")]
|
||||||
|
pub fib: Option<u32>,
|
||||||
/// Optional IPv4 TTL or IPv6 hop limit applied to sent packets.
|
/// Optional IPv4 TTL or IPv6 hop limit applied to sent packets.
|
||||||
///
|
///
|
||||||
/// `None` leaves the platform default unchanged. Values must fit in the
|
/// `None` leaves the platform default unchanged. Values must fit in the
|
||||||
|
|||||||
@@ -12,6 +12,14 @@ use crate::{
|
|||||||
socket_options::apply_ttl_to_socket,
|
socket_options::apply_ttl_to_socket,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "android",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "fuchsia",
|
||||||
|
target_os = "linux"
|
||||||
|
))]
|
||||||
|
use crate::socket_options::apply_routing_options;
|
||||||
|
|
||||||
pub(crate) fn validate_open_timeouts(timeouts: &[Duration]) -> Result<(), ClientError> {
|
pub(crate) fn validate_open_timeouts(timeouts: &[Duration]) -> Result<(), ClientError> {
|
||||||
if timeouts.is_empty() {
|
if timeouts.is_empty() {
|
||||||
return Err(ClientError::NoOpenTimeouts);
|
return Err(ClientError::NoOpenTimeouts);
|
||||||
@@ -115,6 +123,13 @@ fn create_connected_udp_socket(
|
|||||||
remote: SocketAddr,
|
remote: SocketAddr,
|
||||||
) -> Result<UdpSocket, ClientError> {
|
) -> Result<UdpSocket, ClientError> {
|
||||||
let socket = create_prebind_udp_socket(config, remote)?;
|
let socket = create_prebind_udp_socket(config, remote)?;
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "android",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "fuchsia",
|
||||||
|
target_os = "linux"
|
||||||
|
))]
|
||||||
|
apply_routing_options(&socket, config, remote)?;
|
||||||
let bind_addr = config.bind_addr.unwrap_or_else(|| {
|
let bind_addr = config.bind_addr.unwrap_or_else(|| {
|
||||||
if remote.is_ipv4() {
|
if remote.is_ipv4() {
|
||||||
SocketAddr::from(([0, 0, 0, 0], 0))
|
SocketAddr::from(([0, 0, 0, 0], 0))
|
||||||
|
|||||||
@@ -5,11 +5,64 @@ use std::{
|
|||||||
|
|
||||||
use socket2::SockRef;
|
use socket2::SockRef;
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "android",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "fuchsia",
|
||||||
|
target_os = "linux"
|
||||||
|
))]
|
||||||
|
use socket2::Socket;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{MAX_DSCP_CODEPOINT, MAX_TTL},
|
config::{MAX_DSCP_CODEPOINT, MAX_TTL},
|
||||||
error::ClientError,
|
error::ClientError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "android",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "fuchsia",
|
||||||
|
target_os = "linux"
|
||||||
|
))]
|
||||||
|
pub(crate) fn apply_routing_options(
|
||||||
|
socket: &Socket,
|
||||||
|
config: &crate::SocketConfig,
|
||||||
|
remote: SocketAddr,
|
||||||
|
) -> Result<(), ClientError> {
|
||||||
|
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||||
|
{
|
||||||
|
if let Some(device) = &config.bind_to_device {
|
||||||
|
socket
|
||||||
|
.bind_device(Some(device.as_bytes()))
|
||||||
|
.map_err(|source| ClientError::SocketOption {
|
||||||
|
operation: "bind socket to device",
|
||||||
|
remote,
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
if let Some(mark) = config.mark {
|
||||||
|
socket
|
||||||
|
.set_mark(mark)
|
||||||
|
.map_err(|source| ClientError::SocketOption {
|
||||||
|
operation: "set firewall mark",
|
||||||
|
remote,
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "freebsd")]
|
||||||
|
if let Some(fib) = config.fib {
|
||||||
|
socket
|
||||||
|
.set_fib(fib)
|
||||||
|
.map_err(|source| ClientError::SocketOption {
|
||||||
|
operation: "set FIB",
|
||||||
|
remote,
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts a public DSCP codepoint (`0..=`[`MAX_DSCP_CODEPOINT`]) into the
|
/// Converts a public DSCP codepoint (`0..=`[`MAX_DSCP_CODEPOINT`]) into the
|
||||||
/// raw IP TOS / Traffic Class byte it occupies the upper six bits of.
|
/// raw IP TOS / Traffic Class byte it occupies the upper six bits of.
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in new issue
Block a user