rust-lang / socket2

Advanced configuration options for sockets.
https://docs.rs/socket2
Apache License 2.0
683 stars 227 forks source link

Not able to create IPv6 raw socket #517

Closed jjnicola closed 4 months ago

jjnicola commented 5 months ago

I have the following function (also one for IPv4 with the IPV4 domain, which works as expected)

fn new_raw_ipv6_socket() -> Result<Socket, FunctionErrorKind> {
    match Socket::new(
        Domain::IPV6, // 10
        socket2::Type::RAW, // 3
        Some(Protocol::from(IPPROTO_RAW)), // 255
    ) {
        Ok(s) => Ok(s),
        Err(e) => Err(FunctionErrorKind::Dirty(format!(
            "new_raw_ipv6_socket: Not possible to create a raw socket: {}",
            e
        ))),
    }
}

If I call the function and try to set an option:

    let soc = new_raw_ipv6_socket()?; // do not fails here

    if let Err(e) = soc.set_header_included(true) { // It fails here
        return Err(FunctionErrorKind::Dirty(format!(
            "Not possible to create a raw socket: {}",
            e
        )));
    };

I get the following error:

send_v6packet: Not possible to create a raw socket: Protocol not available (os error 92)

Is this a bug or I am doing something wrong? This is working as expected in the program written in C. So, I discard some permission issue or OS issue. Thanks in advance.

Thomasdezeeuw commented 5 months ago

Quick search through the Linux code (https://github.com/search?q=repo%3Atorvalds%2Flinux+IP_HDRINCL&type=code) it seems that IP_HDRINCL (used by set_header_included) is IPv4 only?

But I don't use raw socket myself, so this could be a red herring.

jjnicola commented 5 months ago

it seems that IP_HDRINCL (used by set_header_included) is IPv4 only?

Thanks for the hint. But strange. The C code works without errors.

  soc = socket (AF_INET6, SOCK_RAW, IPPROTO_RAW);
  if (soc < 0)
    return NULL;

  if (setsockopt (soc, IPPROTO_IPV6, IP_HDRINCL, (char *) &opt_on,
                  sizeof (opt_on))
      < 0)
    perror ("setsockopt");

In that code, of course I don't get an error.

Thomasdezeeuw commented 5 months ago

Thanks for the hint. But strange. The C code works without errors.

The difference is that your C code uses IPPROTO_IPV6, where as header_included uses IPPROTO_IP (Ipv4): https://github.com/rust-lang/socket2/blob/6a13053e528fe1bbbfff85461589bafc7425f7b0/src/socket.rs#L1151-L1156

I think that's the problem.

We should split header_included into header_included_v4 and header_included_v6 to fix this.

jjnicola commented 5 months ago

Thanks! I have test your suggestion and it worked. I have prepare a PR.