This is wrong, despite the Rust library in question's naming convention. You're not creating a UDP socket. You're creating an IP (AF_INET), datagram socket (SOCK_DGRAM), using protocol ICMP (IPPROTO_ICMP). The issue is that the rust library apparently conflates datagram and UDP, when they're not the same thing.
You can do the same in C, by calling socket(2) with the above arguments. It hings on Linux allowing rootless pings from the GIDs in
$ sysctl net.ipv4.ping_group_range
net.ipv4.ping_group_range = 999 59999
EDIT: s/ICMP4/ICMP/gIt 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.
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/
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...
Surprising that they got such a fundamental thing wrong.
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.
A datagram socket is a UDP socket, though. That's what the D stands for.
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.
The cross-platform checksum difference is a pain though. Linux handling it for you is convenient until you test on macOS and everything breaks silently.
1. You can just add the capability CAP_NET_RAW to your process, at which point it can ping freely
2. There's a sysctl that allows for unprivileged ping "net.ipv4.ping_group_range" which can be used at the host level to allow different groups to use ICMP ping.
What are consequences of this capability? Seems like restricting this to root was done for a reason?
The goal of the capabilities system was to allow processes and users to gain a small portion of root privileges without giving them all.
In the "old days" ping on a Linux host would be setuid root, so it essentially had all of root's rights. In more modern setups it either has CAP_NET_RAW or the ping_group sysctl is used to allow non-root users to use it.
- Linux overwrites identifier and checksum fields
- macOS requires correct checksum calculation
- macOS includes IP header in response, Linux doesn't
I think this is the kind of subtle difference that would trip up even experienced programmers
The trick used here only allows pings. This trick is gated behind other ACLs.
So... why? Should I now add "in C" or "in assembly" to the end of all my article titles?