Reputation: 739
I need send messages through different gateways dynamically. How do that and what must be my first step in this direction?
On my server I have two connections: one-direct, and secondary over VPN. Default route is direct connection, but i need dynamically change connection to VPN.
At current time I try build socket from libc::bind()
it's work, but have not expected effect.
Changing the outgoing IP is not a solution to define the interface.
Upvotes: 2
Views: 2862
Reputation: 739
As suggested in a comment we must use SO_BINDTODEVICE
, and no way to escape FFI cause it used internally.
Here working example:
extern crate libc;
use libc as c;
use std::ffi::CString;
use std::net::{TcpStream, SocketAddr};
use std::io::{self, Write};
use std::os::unix::io::FromRawFd;
use std::mem;
#[cfg(any(target_os = "linux"))]
fn connect_dev(addr: SocketAddr, link: &str) -> io::Result<TcpStream> {
let (addr_raw, addr_len) = match addr {
SocketAddr::V4(ref a) =>
(a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t),
SocketAddr::V6(ref a) =>
(a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t),
};
unsafe {
let fd = check_os_error(c::socket(c::AF_INET, c::SOCK_STREAM, 0))?;
check_os_error(c::setsockopt(
fd,
c::SOL_SOCKET,
c::SO_BINDTODEVICE,
CString::new(link).expect("device name").as_ptr() as *const c::c_void,
mem::size_of::<CString>() as c::socklen_t,
))?;
check_os_error(c::connect(fd, addr_raw, addr_len))?;
Ok(TcpStream::from_raw_fd(fd))
}
}
#[cfg(any(target_os = "linux"))]
pub fn check_os_error(res: c::c_int) -> io::Result<c::c_int> {
if res == -1 {
Err(io::Error::from_raw_os_error(unsafe { *c::__errno_location() as i32 }))
} else {
Ok(res)
}
}
Upvotes: 1
Reputation: 7897
You can use a different source IPs. I assume that you have your system configured to route different source IPs into different gateways (if not, it's an operator problem, not a programmer). You can specify different source IP in bind
function for socket. Normally you pass their 'default' value (0.0.0.0) which means 'anything OS find reasonable', but you can specify exact source IP for your task.
A C bind
signature:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
addr
may contain the specific address.
Upvotes: 0