anfragment / zen

Simple, free and efficient ad-blocker and privacy guard for Windows, macOS and Linux
https://zenprivacy.net
MIT License
2.11k stars 48 forks source link

Linux: support for desktop environments other than GNOME #21

Open anfragment opened 7 months ago

anfragment commented 7 months ago

The only thing stopping Zen from working in other desktop environments is that it can't set the system proxy settings. On GNOME it is done via couple gsettings commands, but I couldn't find any documentation on similar ways to do this programmatically on other desktop environments. Feel free to add a comment if you think you can help.

anfragment commented 7 months ago

Hello, just a quick headsup, I just ran the Zen executable on Archlinux with Hyprland and NetworkManager, and it seems to be working just fine. I'm wondering if the necessary package isn't just NetworkManager ?

Hi! Does your setup happen to have the gsettings command line tool?

hollisticated-horse commented 7 months ago

How about working with /etc/environment ? Its a file that stores the system-wide variables initialized upon boot:

http_proxy="http://127.0.0.1:<port>"
https_proxy="http://127.0.0.1:<port>"

You could have shell commands change this file either adding or removing lines from it ? Only problem is that the user needs to logout and login again for changes to take effect.

myyc commented 7 months ago

How about working with /etc/environment ? Its a file that stores the system-wide variables initialized upon boot:

http_proxy="http://127.0.0.1:<port>"
https_proxy="http://127.0.0.1:<port>"

You could have shell commands change this file either adding or removing lines from it ? Only problem is that the user needs to logout and login again for changes to take effect.

this is a bad idea in general because it depends on zen being active at all times and will cause all sorts of issues if it's not active. maybe it'd be better to replace it with instructions to set this up manually if someone doesn't use gnome, maybe even within the browser only? either way, i will update the arch linux package to depend on glib2 and networkmanager, since those gsettings flags depend on both.

on the other hand, @anfragment anecdotally i did notice that proxy settings were persistent upon quitting zen so maybe this should change if zen is stopped? or is it a bug? not sure.

hollisticated-horse commented 7 months ago

What if Zen is setup to toggle off the proxy setting on exit ? Wouldn't it mittigate the issue ?

@anfragment @myyc

And what if you use NetworkManager's nmcli :


nmcli connection modify <connection_name> proxy yes
nmcli connection modify <connection_name> proxy.method manual
nmcli connection modify <connection_name> proxy.http http://127.0.0.1:<port>
nmcli connection modify <connection_name> proxy.https http://127.0.0.1:<port>

This would mean that the settings could be changed without having to login again. Then you only depend on networkmanager.

The issue with this potential solution, is that you depend on NetworkManager, and that you'd need to loop through all connection names to set the proxy settings. You can also set proxy settings per device types : wlan, wwan, etc, using nmcli device status and loop through thoses:

  nmcli connection modify "$device" proxy yes
  nmcli connection modify "$device" proxy.method manual
  nmcli connection modify "$device" proxy.http "$proxy"
  nmcli connection modify "$device" proxy.https "$proxy"

or by type maybe

anfragment commented 7 months ago

on the other hand, @anfragment anecdotally i did notice that proxy settings were persistent upon quitting zen so maybe this should change if zen is stopped? or is it a bug? not sure.

Yes, it's a bug, the proxy doesn't properly shut down when the app gets closed on Linux. Should get fixed in a release later this week.

anfragment commented 7 months ago

@hollisticated-horse @myyc nmcli looks promising. NetworkManager is desktop environment agnostic, right? Does every NetworkManager installation come with nmcli?

hollisticated-horse commented 7 months ago

@anfragment

From my research, NetworkManager seems desktop environment agnostic and comes with nmcli.
See compiled list of links:

myyc commented 7 months ago

And what if you use NetworkManager's nmcli :

have you tried it? the above suggestion doesn't work, maybe it refers to an older version of networkmanager. i still think that the most reliable way would be to stick to supporting gnome and kde only, and showing instructions for other setups.

hollisticated-horse commented 7 months ago

@myyc I'm also struggling to make those commands work reliably. I'll do some testing and get back to you guys @myyc @anfragment

EDIT 1:

proxy.method is indeed wrong.

myyc commented 7 months ago

still maintain that if you don't use gnome or kde you should probably configure proxy settings yourself as opposed to having an external piece of software messing with networkmanager or wiping environment variable configs by accident.

anfragment commented 7 months ago

still maintain that if you don't use gnome or kde you should probably configure proxy settings yourself as opposed to having an external piece of software messing with networkmanager or wiping environment variable configs by accident.

Good point. Non-technical users should have an easy way to reset their proxy settings in case something goes wrong with the app. I've done some searching and it seems like even on KDE there is no alternative to gsettings, which means that we would have to stick to only setting the system proxy automatically on GNOME. Currently the app fails to launch if we didn't find the gsettings binary. I'll work on fixing that and adding a notification for users to manually configure their proxy settings. @myyc @hollisticated-horse really appreciate your help in figuring this out, thank you guys.

myyc commented 7 months ago

potentially you could even do it programmatically in go instead of using gsettings? chatgpt suggest the following

package main

import (
        "fmt"
        "github.com/godbus/dbus"
)

func main() {
        conn, err := dbus.SessionBus()
        if err != nil {
                fmt.Println("Failed to connect to the D-Bus session bus:", err)
                return
        }
        defer conn.Close()

        proxySettings := conn.Object("org.gnome.SettingsDaemon", "/org/gnome/SettingsDaemon/Proxy")
        err = proxySettings.Call("org.freedesktop.DBus.Properties.Set", 0, "org.gnome.system.proxy", "mode", dbus.MakeVariant("manual")).Err
        if err != nil {
                fmt.Println("Failed to set proxy mode:", err)
                return
        }

        fmt.Println("Proxy mode set to manual")
}

but i'm not sure using godbus is better than spawning gsettings.

hollisticated-horse commented 7 months ago

I had a quick look at the mullvad electron app, thinking that they must also work with proxys but am unsure of what I found.

Otherwise, I was looking through the archlinux wiki page proxy server page and found this:

Environment_variables

Some programs, such as wget and (used by pacman) CURL, use environment variables of the form *protocol*_proxy to determine the proxy for a given protocol (e.g. HTTP, FTP, ...).

Below is an example on how to set these variables in a shell:

export http_proxy=<a rel="nofollow" class="external free" href="http://10.203.0.1:5187/">http://10.203.0.1:5187/</a>
export https_proxy=$http_proxy
export ftp_proxy=$http_proxy
export rsync_proxy=$http_proxy
export no_proxy="localhost,127.0.0.1,localaddress,.localdomain.com"

Some programs look for the all caps version of the environment variables.

Also:

Alternatively, there is a tool named proxyman-gitAUR which claims to configure system-wide proxy settings easily.

and :

Automation with network managers

NetworkManager cannot change the environment variables. netctl could set-up these environment variables but they would not be seen by other applications as they are not child of netctl.

Which makes me think that the nmcli route might be dead.

https://github.com/himanshub16/ProxyMan/blob/master/shellrc.sh has shell functions to set and unset proxy server.

Which could be interesting to explore.

corbolais commented 6 months ago

Hi there,

Using NM could be one road ahead. It's proxy vars env agnostic which is a good thing. Trying to capture any and all env vars ever used and to be used is whack-a-mole for proxy settings.

As not everyone is using NM, additionally setting known proxy env vars wouldn't hurt.

Feature: if proxy settings are set per connection/device there is no circumventing it by malicious programs or misconfigurations. At least, they're not rooted, that is.

BUT: IIUC, it's just about redirection of HTTP[S] for ad filtering purposes. So the correct route would be setting up iptables/netfilter for the Linux and PF for BSD folks, resp., to redirect the relevant ports.

cheers

anfragment commented 6 months ago

@corbolais thanks for the suggestion, setting some iptables rules might indeed be the solution I was looking for.

hollisticated-horse commented 6 months ago

So when looking up how to use iptables, I end up with this function to set iptables rules: as an example:

func setIpRule() {
    cmd := exec.Command("iptables", "-t", "nat", "-A", "PREROUTING", "-p", "tcp", "--dport", "80", "-j", "REDIRECT", "--to-port", "8080")
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
}

and this function to delete the previous rule.

func delIpRule() {
    cmd := exec.Command("iptables", "-t", "nat", "-D", "PREROUTING", "-p", "tcp", "--dport", "80", "-j", "REDIRECT", "--to-port", "8080")
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
}

Is this what you envisioned @corbolais ?

To be noted, it seems that iptables is not persistent across reboots from the get go. There is a package,iptables-persistent. This packages makes it so that any erected iptables rules will be saved to the corresponding IPv4 and IPv6 files:

/etc/iptables/rules.v4
/etc/iptables/rules.v6

Btw, there is a go package that provides an API for iptables : https://github.com/coreos/go-iptables

Not sure if it's needed, but it's there.

For pf, I assume it is similar ?

corbolais commented 6 months ago

@hollisticated-horse those rules look about right. You probably want to use -I 1 instead of -A. Users might have custom rules or default ufw rules on Ubuntu/Fedora/.. active and appended rules might get ignored if the previous last rule i.e. is a DROP.

Persistency is another chapter in it's own right. It'd be probably best to create a systemd service using a one-shot rule install/removal upon boot/shutdown. Best to check beforehand whether the rule is already installed.

Not sure of the best way to handle this for a multitude of distributions. And there's also a plethora of tools to run custom rulesets. I'd most likely start with injecting and removing the rule oob, like you suggested. Then see where this is leading. OTOH, this issue is no new thing, the net might offer a better solution.

PF, I'm not familiar with. It's a verbose filter language even more so than ufw cmdline syntax is.

anfragment commented 6 months ago

Also, I think we'd need to set the rule using the OUTPUT chain instead of the PREROUTING chain, since it only affects incoming instead of outgoing packets (see: https://manpages.debian.org/unstable/iptables/iptables.8.en.html#nat). From my limited understanding of iptables, this would also mean that requests originating from Zen itself will get routed back to it, creating an infinite loop. This can be solved by adding the -m owner ! --uid-owner zenuser option to the rule, but this would mean that we'd have to run Zen via a separate user, which sounds like a whole another headache in itself.

corbolais commented 6 months ago

@anfragment Correct. For locally generated packets nat OUTPUT is the right choice.

iptables -t nat -A OUTPUT --match owner --uid-owner $ZEN_USR -p tcp --dport 80 -j ACCEPT    
iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination $ZEN_IP:8080

Running ZEN with it's own user id is good practice anyway.

There's a treasure trove to be ingested at https://wiki.squid-cache.org/ConfigExamples/Intercept . The squid-cache wiki is invaluable in this regard. This should keep you busy for the next days.. ;-)

Happy holidays

C

anfragment commented 6 months ago

Thanks for the valuable input @corbolais. Best of luck to you in the coming year!

hollisticated-horse commented 2 months ago

Hello, stumbled upon this tool written in go, to manage forwards with iptables. Might be a lead ?

https://github.com/alegrey91/fwdctl