Master/child IPC in Rust


#1

I need to build a program with similar process architecture as NGINX. There will be a master process running as root and child processes setuid to a non-privileged user. How do I do this and provide an API to the child processes to be able to call the master root process?

I understand the syscalls for fork and setuid, but is there a Rusty way to do this?


#2

Take a look at the nix crate - it’ll provide more canonical looking APIs over raw libc calls.

As for communication, see if https://crates.io/crates/ipc-channel fits the bill.


#3

This is amazing! Thank you so much!

If I needed to bind, say, a privileged port, and grant access to a child process, would I run Tokio in the master, dispatch requests and receive responses from children, or is there a way to pass the socket fd to one or multiple children?

I will have to go to source in NGINX to see how it handles these things within libc and the kernel.


#4

What are the roles of master and child procs in your scenario?


#5

I am writing a daemon which will 1) setup NAT rules in iptables 2) enable IP forwarding in the kernel, and 3) listen on HTTP as a health check and metrics.

I want to make the HTTP health check its own process so as to prevent privilege escalation. Compromise of the health check shouldn’t mean root access.

I could drop privileges after the setup, but I would like to be able to collect metrics from the child process using IPC such as packets routed, measure I/O usage, etc.

Does that make sense?

I probably won’t need more than one child process, but I am curious as to how to create the same agricultural as NGINX in Rust.


#6

Ok, I see.

nginx is a bit different (AFAIK) in that all workers listen on the accept port (ie SO_REUSEPORT) and then kernel selects one of them to accept a given connection. That connection is then serviced by that worker for its lifetime. The master handles “hot” configuration reloading and worker process management. There are also other child procs (eg cache) that manage the cache, and the cache is in shared memory IIRC.

In your case, it sounds like the health server will just run its own http server and service those requests itself - you can use a tokio-based lib for that part. You can then setup an ipc channel where the master sends health info on some periodic basis, and the health server keeps those updates to them service http requests. Alternatively, you can use shared memory as a cache, have the master update it and then the health server can read it when a request comes in. So yeah, you have several options to pick from :slight_smile: Having a peek at nginx source will help too.