Open bakamomi opened 10 months ago
Hi @bakamomi ,
Try adding a rule to redirect forwarded packets to the daemon:
Hi @gustavo-iniguez-goya
I added this rule. I also tried enabling the built-in "Intercept forwarded connections (docker, etc)". It didn't work.
Correct me if I'm wrong, but the rule you suggested assumes that all traffic from a netns is sent unencrypted to the host where it's forwarded and sent out. But wireguard netns doesn't do this. Traffic goes into the wg interface inside the netns, gets encrypted, then OpenSnitch only sees encrypted udp traffic. Unencrypted traffic exists only inside the wg netns. It should be intercepted before wg encrypts it.
Alright, I keep making this mistake 0:) so let's start over.
Please, post the following information:
cat /sys/kernel/debug/tracing/kprobe_events
Usually there're firewall rules involved to forward traffic from namespaces to the host (docker for example), that's why I asked to add a rule for that. Do you have firewall rules to handle the wireguard connections?
Traffic goes into the wg interface inside the netns, gets encrypted, then OpenSnitch only sees encrypted udp traffic.
mmh, I think that this is the expected behaviour, but I need more details. Are you launching applications also from that namespace? so when they establish the connection it goes through the wireguard tunnel of that namespace?
Debug logs will provide useful information, but maybe we'd need a firewall rule to intercept those connections before they're routed through the tunnel.
Interesting use case!probably I'll need to reproduce it locally.
The debug log turned out to be huge. I posted it on privatebin for convenience. https://bin.urla.no/?d4aba4eb25251af2#AYXK1uH97bJfcoZAjPJmC8dAC5iyWaPeYfPexm8PPTwD
Regardless, the ip address of the wg interface (192.168.3.5) isn't recorded there.
These are the only lines directly related to wireguard:
[2023-08-09 17:23:38] DBG new connection udp => 20222:127.0.0.1 -> 127.0.0.1 ():47551 uid: 0, mark: 0
[2023-08-09 17:23:38] DBG [ebpf conn] not in cache, NOR in execEvents: udp20222127.0.0.1127.0.0.147551, 1794 -> /etc/wireguard/swgp-go
[2023-08-09 17:23:38] DBG [ebpf conn] adding item to cache: udp20222127.0.0.1127.0.0.147551
[2023-08-09 17:23:38] DBG ✔ /etc/wireguard/swgp-go -> 20222:127.0.0.1 => 127.0.0.1:47551, mark: 0 (001-allow-localhost)
I use a wireguard obfuscating proxy (swgp-go). It listens on 20222. Wireguard itself is on 47551. Further in the log you can find messages about trying to resolve discord.com. It happened exactly when I updated discord inside my wg netns. I have systemd-resolved resolving dns records for the wg netns. More importantly, the log didn't record any new connections even though they happened inside the netns.
For reference, I have somewhat complicated setup. The firewall on my baremetal system blocks all outgoing traffic aside from LAN and my remote wg server. When I want to give a program access to the internet, I put it inside one of a netns with internet access. Specifically, I run firejail --netns=wg <application>
Here is how my wg netns looks like:
# ip netns exec wg ip a l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host proto kernel_lo
valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
link/sit 0.0.0.0 brd 0.0.0.0
9: wg1: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 192.168.3.5/24 scope global wg1
valid_lft forever preferred_lft forever
My baremetal system has no interface connected to the wg netns. It's isolated.
# ip a l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
3: wlp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 192.168.80.242/24 brd 192.168.80.255 scope global dynamic noprefixroute wlp1s0
valid_lft 23098sec preferred_lft 23098sec
inet6 xxxx:xxxx:xxxx::4fc/128 scope global dynamic noprefixroute
valid_lft 25495sec preferred_lft 25495sec
inet6 xxxx:xxxx:xxxx:0:xxxx:xxxx:xxxx:16e6/64 scope global noprefixroute
valid_lft forever preferred_lft forever
inet6 xxxx::xxxx:xxxx:xxxx:xxxx/64 scope link noprefixroute
valid_lft forever preferred_lft forever
4: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
link/sit 0.0.0.0 brd 0.0.0.0
6: virbr2: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 10.0.1.1/24 brd 10.0.1.255 scope global virbr2
valid_lft forever preferred_lft forever
7: veth0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff link-netns internet
inet 10.200.0.1/24 scope global veth0
valid_lft forever preferred_lft forever
inet6 fd00::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::ccd:59ff:fe91:a809/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
8: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
Here are kprobe_events:
# cat /sys/kernel/debug/tracing/kprobe_events
r32:kprobes/rtcp_v4_connect tcp_v4_connect
p:kprobes/ptcp_v6_connect tcp_v6_connect
r32:kprobes/rtcp_v6_connect tcp_v6_connect
p:kprobes/pudp_sendmsg udp_sendmsg
p:kprobes/pudpv6_sendmsg udpv6_sendmsg
p:kprobes/piptunnel_xmit iptunnel_xmit
p:kprobes/ptcp_v4_connect tcp_v4_connect
Thank you @bakamomi !
The problem is that we create the netfilter queue and the interception rules in the root namespace.
After thinking a little bit about this, there're a couple of solutions (probably more and better):
Migrate to a eBPF based intercepting solution:
We already intercept these connections via eBPF (you can use the script utils/scripts/debug-ebpf-maps.sh tcp
to see all the intercepted connections).
So maybe we could imitate what libnetfilter_queue does:
1) kernel: a XDP program to block outbound connections by default (configurable),
2) kernel: kprobes/tracepoints to intercept new connections, storing connections properties in a pinned map, shared with the XDP program,
3) kernel: a perf ring buffer to send new connections to userspace
4) userspace: on new connections get the process' properties -> check rules ,
5) userspace: on allow/deny -> update pinned map with the verdict
6) kernel: on new connection attempts to the given connection, apply a verdict.
Keep using libnetfilter_queue:
In order to intercept connections from network namespaces: 1) or they are routed through the host (root namespace), so we can intercept them with host's firewall (like docker and other containers work) 2) or we create the nfqueues per network namespace. I've written a PoC to create nfqueues for the root namespace and another one created manually, and more or less work. But it needs more investigation.
Thanks for looking into this! What way you choose to implement this feature is of course up to you, but here are my 2 cents:
they are routed through the host (root namespace), so we can intercept them with host's firewall (like docker and other containers work)
I think that this would break certain usecases, like when you want to isolate a netns from root completely, e.g., wg netns, or if you push a physical net interface into a netns.
we create the nfqueues per network namespace.
This does sound like the simplest solution, and it won't break anything.
eBPF might be the most robust choice, but I have no idea how hard it would be to implement in opensnitch.
Hi, again! Since you said you already have PoC with nfqueues, can you post it maybe as a pull request or in a separate tree? I wouldn't mind compiling opensntich with the patch applied until you merge it into the main repository.
Sorry @bakamomi , I think the PoC is not practical. We should do it via ebpf.
Some network namespaces forward to the host only encrypted traffic. In particular, wireguard supports this by pushing its interface into a netns https://www.wireguard.com/netns/
Because of this the current method of intercepting netns traffic at the Mangle table doesn't work. Nothing gets intercepted. OpenSnitch sees only encrypted wireguard traffic.
As a stopgap, I considered monitoring traffic inside netns via a new OpenSnitch node by launching an additional instance of the daemon inside this netns. But it seems the UI can connect to "remote" nodes only via tcp. My wireguard netns doesn't even have a bridge to the host. There is no direct tcp link. Instead, I wanted to connect to the node via a unix socket, but the UI supports only one socket connection.
Summary
Please add the ability to monitor traffic inside netns. One possible solution is by allowing "remote" nodes to connect via additional unix sockets like the local one.