Comment by stavros

Comment by stavros a day ago

27 replies

This is interesting, but falls just short of explaining what's going on. Why does UDP work for ICMP? What does the final packet look like, and how is ICMP different from UDP? None of that is explained, it's just "do you want ICMP? Just use UDP" and that's it.

It would have been OK if it were posted as a short reference to something common people might wonder about, but I don't know how often people try to reimplement rootless ping.

dgl a day ago

The BSD socket API has 3 parameters when creating a socket with socket(), the family (e.g. inet) the kind (datagram in this case) and the protocol (often 0, but IPPROTO_ICMP in this case).

Because when the protocol is 0 it means a UDP socket Rust has called its API for creating any(?) datagram sockets UdpSocket, partly resulting in this confusion.

The kernel patch introducing the API also explains it was partly based on the UDP code, due to obviously sharing a lot of properties with it. https://lwn.net/Articles/420800/

  • erk__ a day ago

    The std api can only create UdpSockets, the trick here is that you use Socket2 which allows more kinds of sockets and then you tell UdpSocket that some raw file descriptor is a upd socket through a unsafe api with no checks and I guess it works because they use the same api on posix.

    Edit: It is possible in safe rust as well, see child comment.

    The macro used by socket2: https://docs.rs/socket2/0.6.1/src/socket2/lib.rs.html#108

    The FromRawFd trait: https://doc.rust-lang.org/stable/std/os/fd/trait.FromRawFd.h...

    • the8472 a day ago

      From/Into conversion via OwnedFd is the safe API, RawFd is the older and lower-level one.

      • erk__ a day ago

        Ahh I guess that means that its possible in safe rust to cast a file descriptor to a different type. I was just looking at how socket2 did it and forgot to have a proper look.

  • stavros a day ago

    Thanks, that's quite the misnomer then.

  • stingraycharles a day ago

    So UdpSocket should really be called DatagramSocket, UDP being the protocol that operates on these datagrams?

    Surprising that they got such a fundamental thing wrong.

    • krater23 a day ago

      That happens when someones learning project ("I rewrite a library in the new language I want to learn") ends up in productive code.

      • IshKebab a day ago

        This is in the standard library; it's not a learning project. And it also isn't even incorrect - see erk__'s comment.

        Rust is an excellent language and fully capable of production use.

vbezhenar a day ago

ICMP is just different protocol from UDP. There's field "Protocol" in IP packet. 0x01 = ICMP, 0x06 = TCP, 0x11 = UDP.

I think that this article gets terminology wrong. It's not UDP socket that gets created here, but Datagram socket. Seems to be bad API naming in Rust library.

  • stavros a day ago

    > It's not UDP socket that gets created here, but Datagram socket

    A datagram socket is a UDP socket, though. That's what the D stands for.

    • jmgao a day ago

      Wrong way around: UDP sockets are datagram sockets, there are datagram sockets that are not UDP.

    • Quarrel a day ago

      To give a more nuanced reply versus the "you're wrong" ones already here, the difference is that UDP adds send and receive ports, enabling most modern users (& uses) of UDP. Hence, it is the "User" datagram protocol.

      (it also adds a checksum, which used to be more important than it is nowadays, but still well worth it imho.)

    • pwdisswordfishy 21 hours ago

      In related news, all rectangles are squares and all animals are dogs.

    • meindnoch a day ago

      Not every cola is Coca-Cola, even though "Cola" stands for cola.

    • jdndbdbd a day ago

      No? Why would you think a datagram socket is UDP?

      • stavros a day ago

        What a reasonable question to be asked today.

slugonamission a day ago

So in fairness, this doesn't actually use UDP at all (SOCK_DGRAM does not mean UDP!).

The actual protocol in use, and what's supported, it matched by all of the address family (IPV4), the socket type (DGRAM), and the protocol (ICMP). The match structure for IPV4 is here in Linux at least: https://elixir.bootlin.com/linux/v6.18/source/net/ipv4/af_in...

So ultimately, it's not even UDP, it's just creating a standard ICMP socket.

the8472 a day ago

The semantic wrappers around file descriptors (File, UdpSocket, PidFd, PipeReader, etc.) are advisory and generally interconvertible. Since there's no dedicated IcmpSocket they're using UdpSocket which happens to provide the right functions to invoke the syscalls they need.

jeroenhd 21 hours ago

The rust API in use lets you feed an fd into a UdpSocket which calls the necessary send/recv/etc on it.

The socket itself is an ICMP socket, but the ICMP shaped API just happened to fit into the UDP shaped hole. I'm sure some advanced UDP socket options will break or have weird side effects if your code tries to apply them.