linux - 绑定(bind)() : "Cannot assign request address"

标签 linux networking rust

我知道bind: cannot assign requested addressCannot assign requested address - possible causes? ,我无法从中得出解决方案。

我正在尝试直接使用 libc 创建 TCP 流(特别是 std::net::TcpListener )。运行代码时,我遇到错误无法分配请求的地址错误代码:99

确切的输出是:

error message: error code: : Cannot assign requested address
thread 'main' panicked at 'error code: 99', src/main.rs:43:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

我的代码(playground):

use libc; // 0.2.136

use std::mem::{size_of, transmute};

fn main() {
    // Create socket
    let socket_fd = unsafe {
        let socket = libc::socket(libc::AF_INET6, libc::SOCK_STREAM | libc::SOCK_NONBLOCK, 0);
        assert_ne!(socket, -1);
        let optval = 1i32;
        let res = libc::setsockopt(
            socket,
            libc::SOL_SOCKET,
            libc::SO_REUSEPORT,
            (&optval as *const i32).cast(),
            4,
        );
        assert_eq!(res, 0);
        socket
    };

    // Bind socket
    
    // decimal 127.0.0.1 -> hexadecimal 007f.0000.0000.0001
    let sin6_addr = unsafe { transmute::<_, libc::in6_addr>(*b"007f000000000001") };
    let socket_address = libc::sockaddr_in6 {
        sin6_family: libc::AF_INET6 as u16,
        sin6_port: 8080,
        sin6_flowinfo: u32::default(),
        sin6_addr,
        sin6_scope_id: u32::default(),
    };
    let socket_address_length = size_of::<libc::sockaddr_in6>() as u32;
    unsafe {
        let res = libc::bind(
            socket_fd,
            (&socket_address as *const libc::sockaddr_in6).cast(),
            socket_address_length,
        );
        if res == -1 {
            let err = errno();
            print_error("error message: ");
            panic!("error code: {err}");
        }
    }
    
    assert_eq!(unsafe { libc::close(socket_fd) },0);
}

fn print_error(s: &str) {
    unsafe {
        libc::perror(s.as_ptr().cast());
    }
}
fn errno() -> i32 {
    unsafe { *libc::__errno_location() }
}

我在这里设置了选项SO_REUSEPORT,因为我需要创建一个多个进程可以监听的流。

https://lwn.net/Articles/542629/ :

The basic concept of SO_REUSEPORT is simple enough. Multiple servers (processes or threads) can bind to the same port

该端口似乎未被使用:

jonathan@jonathan-pc:~$ sudo lsof -i -P -n
COMMAND    PID            USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
systemd-r  793 systemd-resolve   13u  IPv4  19452      0t0  UDP 127.0.0.53:53 
systemd-r  793 systemd-resolve   14u  IPv4  19453      0t0  TCP 127.0.0.53:53 (LISTEN)
avahi-dae  855           avahi   12u  IPv4  31377      0t0  UDP *:5353 
avahi-dae  855           avahi   13u  IPv6  31378      0t0  UDP *:5353 
avahi-dae  855           avahi   14u  IPv4  31379      0t0  UDP *:49594 
avahi-dae  855           avahi   15u  IPv6  31380      0t0  UDP *:58397 
NetworkMa  859            root   36u  IPv4  36212      0t0  UDP 192.168.0.22:68->192.168.0.1:67 
NetworkMa  859            root   37u  IPv4 110801      0t0  UDP 192.168.0.17:68->192.168.0.1:67 
tor       1038      debian-tor    6u  IPv4  31407      0t0  TCP 127.0.0.1:9050 (LISTEN)
rust-anal 4117        jonathan   46u  IPv4  33176      0t0  UDP 127.0.0.1:35972->127.0.0.53:53 
rust-anal 4189        jonathan   46u  IPv4  33176      0t0  UDP 127.0.0.1:35972->127.0.0.53:53 
firefox   4297        jonathan    3u  IPv4 112786      0t0  TCP 192.168.0.22:46702->151.101.1.69:443 (ESTABLISHED)
firefox   4297        jonathan   29u  IPv4 100032      0t0  TCP 192.168.0.22:55828->34.120.208.123:443 (ESTABLISHED)
firefox   4297        jonathan   56u  IPv4 115182      0t0  TCP 192.168.0.22:50798->52.51.190.37:443 (ESTABLISHED)
firefox   4297        jonathan   75u  IPv4  95741      0t0  TCP 192.168.0.22:48466->142.250.200.10:443 (ESTABLISHED)
firefox   4297        jonathan   81u  IPv4  67879      0t0  TCP 192.168.0.22:55638->34.214.17.205:443 (ESTABLISHED)
firefox   4297        jonathan  116u  IPv4 111739      0t0  TCP 192.168.0.22:37986->172.217.169.68:443 (ESTABLISHED)
firefox   4297        jonathan  121u  IPv4  95751      0t0  TCP 192.168.0.22:46054->198.252.206.25:443 (ESTABLISHED)
firefox   4297        jonathan  129u  IPv4 102073      0t0  TCP 192.168.0.22:51478->34.120.237.76:443 (ESTABLISHED)
firefox   4297        jonathan  136u  IPv4  96742      0t0  TCP 192.168.0.22:36606->34.120.115.102:443 (ESTABLISHED)
firefox   4297        jonathan  139u  IPv4  97943      0t0  TCP 192.168.0.22:36626->172.217.169.68:443 (ESTABLISHED)
firefox   4297        jonathan  144u  IPv4  99520      0t0  TCP 192.168.0.22:49264->198.252.206.25:443 (ESTABLISHED)
firefox   4297        jonathan  157u  IPv4 104859      0t0  TCP 192.168.0.22:58042->93.184.220.29:80 (ESTABLISHED)
jonathan@jonathan-pc:~$ 

最佳答案

您正在将 b"007f000000000001" 转换为 libc::in6_addr。但我认为这不是正确的做法。

查看手册页,该结构是:

struct in6_addr {
   uint8_t   s6_addr[16];
};

也就是说,只有 16 个字节,这对于 IPv6 来说是正确的。但您的字节实际上是该字符串的 ASCII 值:30303766...,虽然从技术上讲是一个 IPv6 地址,但它不是您的本地地址,因此您无法绑定(bind)到它。

此外,在 IPv6 中,正确的本地主机地址是 ::1,而不是 127.0.0.1。即 15 个零后跟一个 1。

如果您想使用 transmute 绑定(bind)到 IPv6 本地主机,则:

let sin6_addr = unsafe { transmute::<_, libc::in6_addr>([0_u8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]) };

或者如果您坚持使用文字字符串(为什么?):

let sin6_addr = unsafe { transmute::<_, libc::in6_addr>(*b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01") };

关于linux - 绑定(bind)() : "Cannot assign request address",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74280276/

相关文章:

linux - 备份数据库使用带日期功能的crontab

Linux排序和切割除最大值以外的行

linux - 如果我将 tomcat 7 绑定(bind)到第二个 IP 地址,它会在需要时使用第一个 IP 地址吗?

docker - 无法使用https/443从kubernetes Pod中获取/ curl

struct - 更新类结构枚举变体中的字段

rust - 什么是 impl Trait + 'lifetime

rust - 我可以对 trait 对象进行类型自省(introspection),然后向下转型吗?

linux - 将 cvs diff 的内容复制到一个文件中

linux - 用于解析列中数据的 Shell 脚本

networking - 从 docker 容器内访问仅 vagrant/virtual box 主机网络上的其他机器