I am aware of bind: cannot assign requested address and Cannot assign requested address - possible causes?, I have not been able to derive a solution from these.
I am trying to create a TCP stream (specifically here a std::net::TcpListener
) directly with libc. I am encountering the error Cannot assign requested address
and error code: 99
when running my code.
The exact output being:
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
My code (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() }
}
I set the option SO_REUSEPORT
here as I need to create a stream that multiple processes can listen to.
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
The port does not appear to be in use:
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:~$
CodePudding user response:
You are transmuting b"007f000000000001"
into a libc::in6_addr
. But I don't thing that is the proper thing to do.
Looking at the man page, that struct is:
struct in6_addr {
uint8_t s6_addr[16];
};
That is, just 16 bytes, the proper thing for an IPv6. But your bytes are actually the ASCII values of that string: 30303766...
, that while technically an IPv6 address, it is not a local one of yours so you cannot bind to it.
Moreover, in IPv6 the proper localhost address is ::1
, not 127.0.0.1
. That is 15 zeros followed by a single one.
If you want to bind to the IPv6 localhost by using a transmute
that would be:
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]) };
Or if you insist on using a literal string (why?):
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") };