stevenengler / socksns

A tool for running an application in an isolated network namespace, with external network access only through a SOCKS proxy.
MIT License
18 stars 0 forks source link

Support static (named) network namespaces #100

Closed phantomcraft closed 3 months ago

phantomcraft commented 2 years ago

It would be a good idea the support for named namespaces (that created by $ ip netns add ).

Two or more programs could use the same network stack.

Obviously this require root privileges.

stevenengler commented 1 year ago

I'm re-opening this since I think it would be useful, although I don't have any plans to work on it at the moment.

I think in general it would be useful as a way of providing the same "proxy bypass" protection for rootless docker/podman containers. You could create and run a no-network container, then start socksns with the namespace path so that the container could make external requests only through the socks port.

Allowing a namespace path should also allow named namespaces.

stevenengler commented 3 months ago

A note to myself:

It seems that you need to be root in the network namespace's parent user namespace in order to setns that network namespace. With a rootless podman container, you can do this by using podman unshare first to enter the user namespace of the container, and then you can enter the network namespace (for example through nsenter -t 1234 -n ip addr). So generally if you wanted to open a socket in an existing rootless network namespace, you must first find a way to become root in the user namespace that created the network namespace.

Specifically, the man page says:

In order to reassociate itself with a new network, IPC, time, or UTS namespace, the caller must have the CAP_SYS_ADMIN capability both in its own user namespace and in the user namespace that owns the target namespace.

Named network namespaces would still require system root of course.

Edit: Actually this is much simpler, since you can just enter the user namespace of the process first directly using the pid, and then enter the network namespace. For example with a rootless podman container, you can enter its network namespace with just nsenter -t 1234 -U -n ip addr. This probably results in a setns(fd1, CLONE_NEWUSER) and then a setns(fd2, CLONE_NEWNET), where fd{1,2} refers to /proc/1234/ns/{user,net}.

Edit 2: Trying to enter a namespace created through unshare -rn fails when nsenter calls setgroups(0, NULL) after both setns calls. I'm not sure if a setgroups call is needed for our purposes, why nsenter uses it, or what makes the unshare namespace different from the podman one.

Edit 3: nsenter tries to modify the uid and gid when entering a user namespace, but this can be disabled using --preserve-credentials. So using this option, nsenter is able to enter the user and network namespace of unshare -rn wihout an error.

stevenengler commented 3 months ago

It would be a good idea the support for named namespaces (that created by $ ip netns add ).

I've added the --netns option in 47a479f, which I think should cover this (for example socksns --netns /var/run/netns/<some_ns>).

@phantomcraft It's been a while and you probably don't use this anymore, but if you do, please let me know if this new option doesn't work for you.