bunpen: barebones pasta integration
totally untested, except that it builds
This commit is contained in:
@@ -107,7 +107,7 @@ export fn namespace_restrict(what: *restrict::resources) void = {
|
|||||||
case restrict::net_none =>
|
case restrict::net_none =>
|
||||||
errors::ext::check("namespace: unshare net", rt::ext::unshare(rt::ext::clone_flag::NEWNET));
|
errors::ext::check("namespace: unshare net", rt::ext::unshare(rt::ext::clone_flag::NEWNET));
|
||||||
case let subset: restrict::net_subset =>
|
case let subset: restrict::net_subset =>
|
||||||
errors::ext::check("namespace: unshare net", rt::ext::unshare(rt::ext::clone_flag::NEWNET));
|
setup_pasta(subset);
|
||||||
case restrict::net_all =>
|
case restrict::net_all =>
|
||||||
log::println("[namespace] keeping net namespace");
|
log::println("[namespace] keeping net namespace");
|
||||||
};
|
};
|
||||||
@@ -164,7 +164,12 @@ type ns_ctx = struct {
|
|||||||
// - in the parent: wait for the child, then propagate its exit status
|
// - in the parent: wait for the child, then propagate its exit status
|
||||||
fn fork_and_propagate() (void | os::exec::error) = {
|
fn fork_and_propagate() (void | os::exec::error) = {
|
||||||
match (os::exec::fork()?) {
|
match (os::exec::fork()?) {
|
||||||
case let child_pid: os::exec::process =>
|
case let child_pid: os::exec::process => return wait_and_propagate(child_pid);
|
||||||
|
case => log::println("[namespace/fork] continuing as child");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fn wait_and_propagate(child_pid: os::exec::process) (void | os::exec::error) = {
|
||||||
forward_signals(child_pid);
|
forward_signals(child_pid);
|
||||||
log::println("[namespace/fork] signals configured");
|
log::println("[namespace/fork] signals configured");
|
||||||
let status = wait_child(child_pid)?;
|
let status = wait_child(child_pid)?;
|
||||||
@@ -173,8 +178,6 @@ fn fork_and_propagate() (void | os::exec::error) = {
|
|||||||
// seems correct behavior may be to send the same termination signal to ourselves.
|
// seems correct behavior may be to send the same termination signal to ourselves.
|
||||||
log::printfln("[namespace/fork] child exited with {}; forwarding as {}", status.status, rc);
|
log::printfln("[namespace/fork] child exited with {}; forwarding as {}", status.status, rc);
|
||||||
os::exit(rc); // propagate exit code
|
os::exit(rc); // propagate exit code
|
||||||
case => log::println("[namespace/fork] continuing as child");
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn wait_child(child_pid: os::exec::process) (os::exec::status | os::exec::error) = {
|
fn wait_child(child_pid: os::exec::process) (os::exec::status | os::exec::error) = {
|
||||||
|
46
pkgs/additional/bunpen/restrict/ns/pasta.ha
Normal file
46
pkgs/additional/bunpen/restrict/ns/pasta.ha
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// vim: set shiftwidth=2 :
|
||||||
|
use errors;
|
||||||
|
use errors::ext;
|
||||||
|
use fmt;
|
||||||
|
use os;
|
||||||
|
use os::exec;
|
||||||
|
use restrict;
|
||||||
|
use rt;
|
||||||
|
use rt::ext;
|
||||||
|
|
||||||
|
fn setup_pasta(net: restrict::net_subset) void = {
|
||||||
|
// `pasta PID [options]`: creates a device in the netns of PID.
|
||||||
|
// ordering:
|
||||||
|
// 1. fork
|
||||||
|
// 2. child: enter netns, signal parent.
|
||||||
|
// 3. parent: fork and spawn `pasta --pid /proc/fd/$N`
|
||||||
|
// then dumbly wait on child until completion
|
||||||
|
// 4. child: wait for `pasta` to signal readiness on fd `$N`
|
||||||
|
//
|
||||||
|
// after that, we can continue on & exec into the user code
|
||||||
|
//
|
||||||
|
// TODO: this currently lacks the synchronization described above
|
||||||
|
|
||||||
|
match (os::exec::fork()) {
|
||||||
|
case let child_pid: os::exec::process =>
|
||||||
|
errors::ext::check("setup_pasta: attach", attach_pasta(child_pid));
|
||||||
|
errors::ext::check("setup_pasta: wait", wait_and_propagate(child_pid));
|
||||||
|
case void =>
|
||||||
|
errors::ext::check("namespace: unshare net", rt::ext::unshare(rt::ext::clone_flag::NEWNET));
|
||||||
|
case let e: os::exec::error =>
|
||||||
|
errors::ext::check("setup_pasta: fork", e);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// spawn pasta as a separate process, and have it attach to the netns of the given pid.
|
||||||
|
fn attach_pasta(child: os::exec::process) (void | os::exec::error | rt::errno) = {
|
||||||
|
return match (os::exec::fork()?) {
|
||||||
|
case let pasta_pid: os::exec::process => yield void;
|
||||||
|
case void =>
|
||||||
|
let pidstr = fmt::asprint(child: int);
|
||||||
|
defer free(pidstr);
|
||||||
|
let pasta_args = [ "pasta", pidstr ];
|
||||||
|
// TODO: append dns, gateway arguments to `pasta`.
|
||||||
|
yield rt::ext::execvpe("pasta", pasta_args, os::getenvs());
|
||||||
|
};
|
||||||
|
};
|
Reference in New Issue
Block a user