Skip to content

Commit

Permalink
tcp: connect: Add bind_device option
Browse files Browse the repository at this point in the history
Add option to bind an outgoing TCP connection to a specific device,
identified by its name.

Signed-off-by: Konrad Gräfe <[email protected]>
  • Loading branch information
kgraefe committed May 3, 2023
1 parent 7fc14e0 commit fac3e82
Showing 1 changed file with 31 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/adapters/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ use mio::event::{Source};
use socket2::{Socket, Domain, TcpKeepalive, Type, Protocol};

use std::net::{SocketAddr};
#[cfg(unix)]
use std::ffi::{CString};
use std::io::{self, ErrorKind, Read, Write};
#[cfg(target_os = "macos")]
use std::num::NonZeroU32;
use std::ops::{Deref};
use std::mem::{forget, MaybeUninit};
#[cfg(target_os = "windows")]
Expand All @@ -25,11 +29,19 @@ pub const INPUT_BUFFER_SIZE: usize = u16::MAX as usize; // 2^16 - 1

#[derive(Clone, Debug, Default)]
pub struct TcpConnectConfig {
bind_device: Option<String>,
source_address: Option<SocketAddr>,
keepalive: Option<TcpKeepalive>,
}

impl TcpConnectConfig {
/// Bind the TCP connection to a specific interface, identified by its name. On other systems
/// this opion will be ignored.
pub fn with_bind_device(mut self, device: String) -> Self {
self.bind_device = Some(device);
self
}

/// Enables TCP keepalive settings on the socket.
pub fn with_keepalive(mut self, keepalive: TcpKeepalive) -> Self {
self.keepalive = Some(keepalive);
Expand Down Expand Up @@ -98,6 +110,25 @@ impl Remote for RemoteResource {
socket.bind(&source_address.into())?;
}

#[cfg(unix)]
if let Some(bind_device) = config.bind_device {
let device = CString::new(bind_device)?;

#[cfg(not(target_os = "macos"))]
socket.bind_device(Some(device.as_bytes()))?;

#[cfg(target_os = "macos")]
match NonZeroU32::new(unsafe { libc::if_nametoindex(device.as_ptr()) }) {
Some(index) => socket.bind_device_by_index(Some(index))?,
None => {
return Err(io::Error::new(
ErrorKind::NotFound,
"Bind device interface not found",
))
}
}
}

match socket.connect(&peer_addr.into()) {
#[cfg(unix)]
Err(e) if e.raw_os_error() != Some(libc::EINPROGRESS) => return Err(e),
Expand Down

0 comments on commit fac3e82

Please sign in to comment.