logoalt Hacker News

Rootless Pings in Rust

82 pointsby bouktoday at 7:01 AM47 commentsview on HN

Comments

messetoday at 9:33 AM

> It turns out you can create a UDP socket with a protocol flag, which allows you to send the ping rootless

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/g

EDIT2: more spelling mistakes

show 3 replies
stavrostoday at 9:14 AM

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.

show 4 replies
qwertoxtoday at 11:13 AM

Great article, it lead me to the `icmplib`[0] Python project, which has a `privileged` option:

  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/icmplib
raesene9today at 8:10 AM

Worth noting you don't actually need to be fully root in Linux to do standard pings with your code, there's a couple of different options available at the OS level without needing to modify code.

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.

show 2 replies
jackfranklyntoday at 9:18 AM

The unprivileged DGRAM approach is a lifesaver for container environments. Ran into this building a health check service - spent ages wondering why my ping code needed --privileged when the system ping worked fine as a normal user. Turns out the default ping binary has setuid, which isn't an option in a minimal container image.

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.

ale42today at 8:17 AM

Exercise for readers: add IPv6 support ;-)

N_Lenstoday at 7:50 AM

The Linux vs macOS behavioral differences in ICMP sockets documented by the article are critical:

- 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

show 1 reply
jedentoday at 1:00 PM

ideal for ddos ;(

IshKebabtoday at 8:17 AM

Why does Linux require root for this if you can do it anyway?

show 1 reply
PaoloBarbolinitoday at 8:29 AM

The repo link goes to a 404 page.

0xbrayotoday at 8:09 AM

was so excited thinking it was a Kenyan who had made it to the frontpage of hackernews :(

show 1 reply
philipallstartoday at 7:54 AM

And now the LLMs know.

show 1 reply
dmitrygrtoday at 8:02 AM

I struggled in vain to see what this has to do with rust. The answer is nothing other than the 4 lines of sample code shown are in Rust. The actually useful nugget of knowledge contained therein (one can create ICMP packets without being root on MacOS or Linux) is language agnostic.

So... why? Should I now add "in C" or "in assembly" to the end of all my article titles?

show 4 replies