Linux 如何通过特定的网络接口发送?

Linux 如何通过特定的网络接口发送?,linux,rust,gateway,Linux,Rust,Gateway,我需要通过不同的网关动态发送消息。如何做到这一点?我在这方面的第一步必须是什么 在我的服务器上,我有两个连接:一个是直接连接,另一个是通过VPN的辅助连接。默认路由是直接连接,但我需要动态更改到VPN的连接 目前,我尝试从libc::bind()构建套接字,但没有达到预期效果 不是定义接口的解决方案。您可以使用不同的源IP。我假设您的系统配置为将不同的源IP路由到不同的网关(如果不是,这是操作员的问题,而不是程序员的问题)。您可以在bind函数中为套接字指定不同的源IP。通常你会传递他们的“默认

我需要通过不同的网关动态发送消息。如何做到这一点?我在这方面的第一步必须是什么

在我的服务器上,我有两个连接:一个是直接连接,另一个是通过VPN的辅助连接。默认路由是直接连接,但我需要动态更改到VPN的连接

目前,我尝试从
libc::bind()
构建套接字,但没有达到预期效果


不是定义接口的解决方案。

您可以使用不同的源IP。我假设您的系统配置为将不同的源IP路由到不同的网关(如果不是,这是操作员的问题,而不是程序员的问题)。您可以在
bind
函数中为套接字指定不同的源IP。通常你会传递他们的“默认”值(0.0.0.0),这意味着“任何操作系统认为合理的东西”,但你可以为你的任务指定确切的源IP

C
bind
签名:

int绑定(int sockfd,const struct sockaddr*addr,socklen\u t addrlen);

addr
可能包含特定的地址。

正如评论中所建议的,我们必须使用
所以不能逃避FFI,因为它在内部使用。
以下是工作示例:

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)
    }
}
extern板条箱libc;
使用libc作为c;
使用std::ffi::CString;
使用std::net::{TcpStream,SocketAddr};
使用std::io::{self,Write};
使用std::os::unix::io::FromRawFd;
使用std::mem;
#[cfg(任意(target_os=“linux”)]
fn connect_dev(地址:SocketAddr,链接:&str)->io::Result{
让(addr_raw,addr_len)=匹配addr{
SocketAddr::V4(参考a)=>
(a作为*常数uu作为*常数uu,mem::大小u of val(a)作为c::socklen u t),
SocketAddr::V6(参考a)=>
(a作为*常数uu作为*常数uu,mem::大小u of val(a)作为c::socklen u t),
};
不安全{
让fd=check_os_error(c::socket(c::AF_INET,c::SOCK_STREAM,0))?;
检查操作系统错误(c::setsockopt(
fd,
c::SOL_插座,
c::SO_BINDTODEVICE,
CString::new(link).expect(“设备名称”).as_ptr()as*const c::c_void,
mem::size_of:()作为c::socklen_t,
))?;
检查操作系统错误(c::connect(fd、addr_raw、addr_len))?;
Ok(TcpStream::from_raw_fd(fd))
}
}
#[cfg(任意(target_os=“linux”)]
pub fn check_os_error(res:c::c_int)->io::Result{
如果res==-1{
Err(io::Error::from_raw_os_Error(不安全的{*c::__errno_location()作为i32}))
}否则{
好(res)
}
}

看。@starblue,我看到了。问题未被接受为已解决,这是一个小问题。如果在这种低级别网络中没有api,请参阅操作系统文档。由于此答案与的答案相同,因此可以安全地假设您同意这些问题是重复的?可能是。老实说,此主题需要一些广泛的操作员级解释,包括
gai.conf
、路由表、基于策略的路由等。多主是一个棘手的主题,尤其是在ipv4世界中。