Remix.run Logo
stavros 6 hours ago

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 6 hours ago | parent | next [-]

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__ 6 hours ago | parent | next [-]

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 4 hours ago | parent [-]

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

erk__ 4 hours ago | parent [-]

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.

stingraycharles 6 hours ago | parent | prev | next [-]

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 5 hours ago | parent [-]

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

IshKebab 5 hours ago | parent [-]

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.

Sharlin 3 hours ago | parent [-]

It's not, it's the `socket2` library. The standard sockets don't allow (ab)using actual `UdpSocket`s as a different kind of datagram socket.

IshKebab an hour ago | parent [-]

We're talking about UdpSocket: https://doc.rust-lang.org/stable/std/net/struct.UdpSocket.ht...

Sharlin 43 minutes ago | parent [-]

Yes, I know, but the point is that the standard UdpSocket is correctly named as it doesn’t represent any other datagram socket. Uh, we’re pribably in agreement here actually.

IshKebab 18 minutes ago | parent [-]

Yeah exactly! :-D

stavros 6 hours ago | parent | prev [-]

Thanks, that's quite the misnomer then.

the8472 6 hours ago | parent | prev | next [-]

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.

vbezhenar 6 hours ago | parent | prev | next [-]

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 6 hours ago | parent [-]

> 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 5 hours ago | parent | next [-]

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

Quarrel 3 hours ago | parent | prev | next [-]

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.)

meindnoch an hour ago | parent | prev | next [-]

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

jdndbdbd 4 hours ago | parent | prev [-]

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

stavros 4 hours ago | parent [-]

What a reasonable question to be asked today.

cstrahan an hour ago | parent | next [-]

Let me rephrase GP into (I hope) a more useful analogy. — actually, here’s the whole analogous exchange:

“A rectangle is an equal-sided rectangle (i.e. “square”) though. That’s what the R stands for.”

“No? Why would you think a rectangle is a square?”

Just as not all rectangles are squares (squares are a specific subset of rectangles), not all datagram protocols are UDP (UDP is just one particular datagram protocol).

messe 4 hours ago | parent | prev [-]

What networks are you using without ICMP?

Presumably you're also using systems that don't support Unix Domain Sockets which can be configured as SOCK_STREAM, SOCK_DGRAM, and even gasp SOCK_SEQPACKET (equivalent to SOCK_DGRAM in this case admittedly).

slugonamission 6 hours ago | parent | prev [-]

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.