msantos / procket

Erlang interface to low level socket operations
http://blog.listincomprehension.com/search/label/procket
BSD 3-Clause "New" or "Revised" License
283 stars 80 forks source link

Support for network namespaces #37

Closed vasu-dasari closed 7 years ago

vasu-dasari commented 7 years ago

Caller can specify namespace while creating a new socket as a tuple to procket:open() options list.

For example like this:

    procket:open(0, [{netns,"/var/run/netns/blue"},
        {protocol, 16#0008}, {type, raw}, {family, packet}])

This would set the process/thread making this call switch to network namespace of "blue".

Added a new nif to setup netns. ERL_NIF_TERM nif_setns(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);

Also added a new example code to sniff on network namespace: examples/sniff.erl

msantos commented 7 years ago

Excellent, thanks!

There are 2 issues when using setns() as an NIF:

I think adding setns NIF support is very useful though. For general use, I think binding the socket to the namespace in the setuid helper might be safer.

What do you think?

Also needs some changes for non-linux systems. I can add that in. Basically just this: https://github.com/msantos/alcove/blob/master/rebar.config.script#L69

vasu-dasari commented 7 years ago

Interesting. I thought that the setns would affect only the thread it is called from. Apparently, it affected the whole beam. For example, this following code did not work:

start() ->
    spawn(fun() -> start_sniff_on("/var/run/netns/blue", "veth1") end),
    spawn(fun() -> start_sniff_on("/var/run/netns/red",  "veth3") end).

start_sniff_on(Ns, IfName) ->
    {ok, Fd} = procket:open(0, [{netns,Ns},
            {protocol, 16#0008}, {type, raw}, {family, packet}]),
    ok = packet:bind(Fd, packet:ifindex(Fd,IfName)),
    erlang:open_port({fd, Fd, Fd}, [binary, stream]),
    loop().

I believe you are suggesting a way of tying a socket to a namespace by using the code snippet you pointed. Unfortunately, I see this is the only place setns is invoked.

int main(int argc, char *argv[]) {
    (void)setns(0,0);
    return 0;
}

And I do not see how this code ties socket to a namespace. Can you post code snippet on how to accomplish this. If not, I need to do some learning to make this happen.

I think binding the socket to the namespace in the setuid helper might be safer.

msantos commented 7 years ago

Having beam enter a namespace could be useful though: having beam join an existing container, etc.

About the code snippet: a small program is compiled by rebar. If it succeeds, than HAVE_SETNS is defined and support is enabled. This will allow the NIF to compile on, e.g., FreeBSD and OpenBSD.

I'll push my patch to enable namespace support in the setuid helper. Tomorrow I'll merge in your NIF patch and the example.

vasu-dasari commented 7 years ago

Good. Let me know if I can help anyway.

msantos commented 7 years ago

Merged, thanks!