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 hinges 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/gEDIT2: more spelling mistakes
https://github.com/ThomasHabets/rust-ping-example-corrected
There is no UDP used anywhere in this example. ICMP is not UDP.
I'm not saying my fix is pretty (e.g. uses unwrap(), and ugly destination address parsing), but that's not the point.
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.
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.
Historically, to receive ICMP packets, I think you had to open a RAW socket and snoop everything. Obviously, this required root or similar.
IPPROTO_ICMP allows you to send ICMP packets and receive responses from the same address, without root. But you can't use it for traceroute because it only accepts ICMP responses from the ultimate destination you sent to; not some TTL failure intermediary.
Finally, IP_RECVERR (Linux 2.2) on UDP sockets allows you to receive associated ICMP errors from any hop for a send. (This is useful for traceroute, but not ICMP ping.)
I think there are also some caveats on how you can monitor for these type of events in Rust in particular? IIRC, the mainstream async stuff only watches for read/write events, and these aren't those.
- 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
When this option is enabled, this library fully manages the exchanges and the structure of ICMP packets. Disable this option if you want to use this function without root privileges and let the kernel handle ICMP headers.
[0] https://github.com/ValentinBELYN/icmplibThe cross-platform checksum difference is a pain though. Linux handling it for you is convenient until you test on macOS and everything breaks silently.
So... why? Should I now add "in C" or "in assembly" to the end of all my article titles?