Release build not working with raw socket

⚓ Rust    📅 2025-08-28    👤 surdeus    👁️ 3      

surdeus

I am writing small async ping collector, using non-blocking raw socket. The is code is wokring perfectly fine with debug build, but it gives error for release build at sent_to call.

2025-08-28T12:39:04.010149Z ERROR socket-manager::sender: failed to sent data: Address family not supported by protocol (os error 97)
2025-08-28T12:39:04.010199Z ERROR socket-manager::sender: for task_id: 1, failed to send payload: Io(Os { code: 97, kind: Uncategorized, message: "Address family not supported by protocol" })
2025-08-28T12:39:04.012623Z ERROR socket-manager::sender: failed to sent data: Address family not supported by protocol (os error 97)
2025-08-28T12:39:04.012677Z ERROR socket-manager::sender: for task_id: 2, failed to send payload: Io(Os { code: 97, kind: Uncategorized, message: "Address family not supported by protocol" })
2025-08-28T12:39:04.015837Z ERROR socket-manager::sender: failed to sent data: Address family not supported by protocol (os error 97)
2025-08-28T12:39:04.015976Z ERROR socket-manager::sender: for task_id: 3, failed to send payload: Io(Os { code: 97, kind: Uncategorized, message: "Address family not supported by protocol" })
2025-08-28T12:39:04.511229Z ERROR socket-manager::sender: failed to sent data: Address family not supported by protocol (os error 97)

  pub fn new(family: AddressFamily) -> Result<Self> {
        tracing::debug!("creating_raw socket with: {:?}", family);
        let fd = match family {
            AddressFamily::Ipv4 => unsafe {
                libc::socket(libc::AF_INET, libc::SOCK_RAW, libc::IPPROTO_ICMP)
            },
            AddressFamily::Ipv6 => unsafe {
                libc::socket(libc::AF_INET6, libc::SOCK_RAW, libc::IPPROTO_ICMPV6)
            },
        };

        if fd < 0 {
            tracing::error!(
                "failed to create socket: {}",
                std::io::Error::last_os_error()
            );
            return Err(std::io::Error::last_os_error().into());
        }

        Ok(RawSocket {
            family,
            fd: AsyncFd::new(fd)?,
        })
    }

pub async fn send_to(&self, buf: &[u8], dst: IpAddr) -> Result<()> {
        // Use a loop to handle non-blocking send
        loop {
            let mut guard = self.fd.writable().await?;

            let check = guard.try_io(|inner| {
                let addr = match (&self.family, dst) {
                    (AddressFamily::Ipv4, IpAddr::V4(ip)) => {
                        let sockaddr_in = libc::sockaddr_in {
                            sin_family: libc::AF_INET as u16,
                            sin_port: 0,
                            sin_addr: libc::in_addr {
                                s_addr: u32::from_ne_bytes(ip.octets()),
                            },
                            sin_zero: [0; 8],
                        };

                        &sockaddr_in as *const _ as *const libc::sockaddr
                    }
                    (AddressFamily::Ipv6, IpAddr::V6(ip)) => {
                        let sockaddr_in6 = libc::sockaddr_in6 {
                            sin6_family: libc::AF_INET6 as u16,
                            sin6_port: 0,
                            sin6_flowinfo: 0,
                            sin6_addr: libc::in6_addr {
                                s6_addr: ip.octets(),
                            },
                            sin6_scope_id: 0,
                        };
                        &sockaddr_in6 as *const _ as *const libc::sockaddr
                    }
                    (_, _) => {
                        return Err(std::io::Error::other(Error::SocketAndPacketMismatch));
                    }
                };

                let addr_len = match self.family {
                    AddressFamily::Ipv4 => std::mem::size_of::<libc::sockaddr_in>() as u32,
                    AddressFamily::Ipv6 => std::mem::size_of::<libc::sockaddr_in6>() as u32,
                };

                let fd = inner.as_raw_fd();

                let result = unsafe {
                    libc::sendto(fd, buf.as_ptr() as *const _, buf.len(), 0, addr, addr_len)
                };

                if result < 0 {
                    if std::io::Error::last_os_error().raw_os_error() != Some(libc::EAGAIN) {
                        tracing::error!("failed to sent data: {}", std::io::Error::last_os_error());
                    }
                    Err(std::io::Error::last_os_error())
                } else {
                    Ok(())
                }
            });

            match check {
                Ok(result) => return Ok(result?),
                Err(_) => {
                    guard.clear_ready();
                    continue;
                }
            }
        }
    }

3 posts - 3 participants

Read full topic

🏷️ Rust_feed