Loading maintainers/maintainer-list.nix +6 −0 Original line number Diff line number Diff line Loading @@ -4453,6 +4453,12 @@ githubId = 103082; name = "Ed Brindley"; }; elesiuta = { email = "elesiuta@gmail.com"; github = "elesiuta"; githubId = 8146662; name = "Eric Lesiuta"; }; eliandoran = { email = "contact@eliandoran.me"; name = "Elian Doran"; Loading nixos/modules/module-list.nix +1 −0 Original line number Diff line number Diff line Loading @@ -961,6 +961,7 @@ ./services/networking/pdns-recursor.nix ./services/networking/pdnsd.nix ./services/networking/peroxide.nix ./services/networking/picosnitch.nix ./services/networking/pixiecore.nix ./services/networking/pleroma.nix ./services/networking/polipo.nix Loading nixos/modules/services/networking/picosnitch.nix 0 → 100644 +26 −0 Original line number Diff line number Diff line { config, lib, pkgs, ... }: with lib; let cfg = config.services.picosnitch; in { options.services.picosnitch = { enable = mkEnableOption (lib.mdDoc "picosnitch daemon"); }; config = mkIf cfg.enable { environment.systemPackages = [ pkgs.picosnitch ]; systemd.services.picosnitch = { description = "picosnitch"; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "simple"; Restart = "always"; RestartSec = 5; ExecStart = "${pkgs.picosnitch}/bin/picosnitch start-no-daemon"; PIDFile = "/run/picosnitch/picosnitch.pid"; }; }; }; } pkgs/tools/networking/picosnitch/default.nix 0 → 100644 +38 −0 Original line number Diff line number Diff line { lib , python3 , bcc }: python3.pkgs.buildPythonApplication rec { pname = "picosnitch"; version = "0.12.0"; src = python3.pkgs.fetchPypi { inherit pname version; sha256 = "b87654b4b92e28cf5418388ba1d3165b9fa9b17ba91af2a1a942f059128f68bc"; }; propagatedBuildInputs = with python3.pkgs; [ setuptools bcc psutil dbus-python requests pandas plotly dash ]; patches = [ ./picosnitch.patch ]; pythonImportsCheck = [ "picosnitch" ]; meta = with lib; { description = "Monitor network traffic per executable with hashing"; homepage = "https://github.com/elesiuta/picosnitch"; changelog = "https://github.com/elesiuta/picosnitch/releases"; license = licenses.gpl3Plus; maintainers = [ maintainers.elesiuta ]; platforms = platforms.linux; }; } pkgs/tools/networking/picosnitch/picosnitch.patch 0 → 100644 +111 −0 Original line number Diff line number Diff line diff --git a/picosnitch.py b/picosnitch.py index a3dbb07..2b74f3e 100755 --- a/picosnitch.py +++ b/picosnitch.py @@ -1356,7 +1356,7 @@ def ui_loop(stdscr: curses.window, splash: str, con: sqlite3.Connection) -> int: update_query = False if execute_query: try: - with open("/run/picosnitch.pid", "r") as f: + with open("/run/picosnitch/picosnitch.pid", "r") as f: run_status = "pid: " + f.read().strip() except Exception: run_status = "not running" @@ -1603,7 +1603,7 @@ def ui_dash(): return cmdline def serve_layout(): try: - with open("/run/picosnitch.pid", "r") as f: + with open("/run/picosnitch/picosnitch.pid", "r") as f: run_status = "pid: " + f.read().strip() except Exception: run_status = "not running" @@ -1771,7 +1771,7 @@ def main(): # master copy of the snitch dictionary, all subprocesses only receive a static copy of it from this point in time snitch = read_snitch() # start picosnitch process monitor - with open("/run/picosnitch.pid", "r") as f: + with open("/run/picosnitch/picosnitch.pid", "r") as f: assert int(f.read().strip()) == os.getpid() if __name__ == "__main__" or sys.argv[1] == "start-no-daemon": sys.exit(main_process(snitch)) @@ -1818,7 +1818,7 @@ def start_picosnitch(): RestartSec=5 Environment="SUDO_UID={os.getenv("SUDO_UID")}" "SUDO_USER={os.getenv("SUDO_USER")}" "DBUS_SESSION_BUS_ADDRESS={os.getenv("DBUS_SESSION_BUS_ADDRESS")}" "PYTHON_USER_SITE={site.USER_SITE}" ExecStart={sys.executable} "{os.path.abspath(__file__)}" start-no-daemon - PIDFile=/run/picosnitch.pid + PIDFile=/run/picosnitch/picosnitch.pid [Install] WantedBy=multi-user.target @@ -1832,12 +1832,12 @@ def start_picosnitch(): subprocess.Popen(["bash", "-c", f'let i=0; rm {BASE_PATH}/dash; while [[ ! -f {BASE_PATH}/dash || "$i" -gt 30 ]]; do let i++; sleep 1; done; rm {BASE_PATH}/dash && /usr/bin/env python3 -m webbrowser -t http://{os.getenv("HOST", "localhost")}:{os.getenv("PORT", "5100")}'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if os.getuid() != 0: args = ["sudo", "-E", sys.executable, os.path.abspath(__file__), sys.argv[1]] - os.execvp("sudo", args) + assert sys.argv[1] not in ["start", "stop", "restart", "start-no-daemon"], "picosnitch requires root privileges to run" with open("/proc/self/status", "r") as f: proc_status = f.read() capeff = int(proc_status[proc_status.find("CapEff:")+8:].splitlines()[0].strip(), base=16) cap_sys_admin = 2**21 - assert capeff & cap_sys_admin, "Missing capability CAP_SYS_ADMIN" + assert sys.argv[1] not in ["start", "stop", "restart", "start-no-daemon"] or (capeff & cap_sys_admin), "Missing capability CAP_SYS_ADMIN" assert importlib.util.find_spec("bcc"), "Requires BCC https://github.com/iovisor/bcc/blob/master/INSTALL.md" tmp_snitch = read_snitch() con = sqlite3.connect(os.path.join(BASE_PATH, "snitch.db")) @@ -1883,8 +1883,8 @@ def start_picosnitch(): except Exception as e: print("Warning: %s%s on line %s" % (type(e).__name__, str(e.args), sys.exc_info()[2].tb_lineno), file=sys.stderr) if sys.argv[1] in ["start", "stop", "restart"]: - if os.path.exists("/usr/lib/systemd/system/picosnitch.service"): - print("Found /usr/lib/systemd/system/picosnitch.service but you are not using systemctl") + if os.path.exists("/usr/lib/systemd/system/picosnitch.service") or os.path.exists("/etc/systemd/system/picosnitch.service"): + print("Found picosnitch.service but you are not using systemctl") if sys.stdin.isatty(): confirm = input(f"Did you intend to run `systemctl {sys.argv[1]} picosnitch` (y/N)? ") if confirm.lower().startswith("y"): @@ -1893,15 +1893,15 @@ def start_picosnitch(): class PicoDaemon(Daemon): def run(self): main() - daemon = PicoDaemon("/run/picosnitch.pid") + daemon = PicoDaemon("/run/picosnitch/picosnitch.pid") if sys.argv[1] == "start": - print("starting picosnitch daemon") + print("starting picosnitch daemon, WARNING: built in daemon mode is not supported on Nix, use picosnitch start-no-daemon or systemctl instead") daemon.start() elif sys.argv[1] == "stop": - print("stopping picosnitch daemon") + print("stopping picosnitch daemon, WARNING: built in daemon mode is not supported on Nix, use picosnitch start-no-daemon or systemctl instead") daemon.stop() elif sys.argv[1] == "restart": - print("restarting picosnitch daemon") + print("restarting picosnitch daemon, WARNING: built in daemon mode is not supported on Nix, use picosnitch start-no-daemon or systemctl instead") daemon.restart() elif sys.argv[1] == "status": daemon.status() @@ -1912,11 +1912,12 @@ def start_picosnitch(): print("Wrote /usr/lib/systemd/system/picosnitch.service\nYou can now run picosnitch using systemctl") return 0 elif sys.argv[1] == "start-no-daemon": - assert not os.path.exists("/run/picosnitch.pid") + assert not os.path.exists("/run/picosnitch/picosnitch.pid") def delpid(): - os.remove("/run/picosnitch.pid") + os.remove("/run/picosnitch/picosnitch.pid") atexit.register(delpid) - with open("/run/picosnitch.pid", "w") as f: + os.makedirs("/run/picosnitch", exist_ok=True) + with open("/run/picosnitch/picosnitch.pid", "w") as f: f.write(str(os.getpid()) + "\n") print("starting picosnitch in simple mode") print(f"using config and log files from: {BASE_PATH}") @@ -1927,7 +1928,7 @@ def start_picosnitch(): assert dash.__version__ and pandas.__version__ and plotly.__version__ print(f"serving web gui on http://{os.getenv('HOST', 'localhost')}:{os.getenv('PORT', '5100')}") args = ["bash", "-c", f"sudo -i -u {os.getenv('SUDO_USER')} touch {BASE_PATH}/dash; nohup {sys.executable} \"{os.path.abspath(__file__)}\" start-dash > /dev/null 2>&1 &"] - os.execvp("bash", args) + return ui_dash() elif sys.argv[1] == "start-dash": return ui_dash() elif sys.argv[1] == "view": Loading
maintainers/maintainer-list.nix +6 −0 Original line number Diff line number Diff line Loading @@ -4453,6 +4453,12 @@ githubId = 103082; name = "Ed Brindley"; }; elesiuta = { email = "elesiuta@gmail.com"; github = "elesiuta"; githubId = 8146662; name = "Eric Lesiuta"; }; eliandoran = { email = "contact@eliandoran.me"; name = "Elian Doran"; Loading
nixos/modules/module-list.nix +1 −0 Original line number Diff line number Diff line Loading @@ -961,6 +961,7 @@ ./services/networking/pdns-recursor.nix ./services/networking/pdnsd.nix ./services/networking/peroxide.nix ./services/networking/picosnitch.nix ./services/networking/pixiecore.nix ./services/networking/pleroma.nix ./services/networking/polipo.nix Loading
nixos/modules/services/networking/picosnitch.nix 0 → 100644 +26 −0 Original line number Diff line number Diff line { config, lib, pkgs, ... }: with lib; let cfg = config.services.picosnitch; in { options.services.picosnitch = { enable = mkEnableOption (lib.mdDoc "picosnitch daemon"); }; config = mkIf cfg.enable { environment.systemPackages = [ pkgs.picosnitch ]; systemd.services.picosnitch = { description = "picosnitch"; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "simple"; Restart = "always"; RestartSec = 5; ExecStart = "${pkgs.picosnitch}/bin/picosnitch start-no-daemon"; PIDFile = "/run/picosnitch/picosnitch.pid"; }; }; }; }
pkgs/tools/networking/picosnitch/default.nix 0 → 100644 +38 −0 Original line number Diff line number Diff line { lib , python3 , bcc }: python3.pkgs.buildPythonApplication rec { pname = "picosnitch"; version = "0.12.0"; src = python3.pkgs.fetchPypi { inherit pname version; sha256 = "b87654b4b92e28cf5418388ba1d3165b9fa9b17ba91af2a1a942f059128f68bc"; }; propagatedBuildInputs = with python3.pkgs; [ setuptools bcc psutil dbus-python requests pandas plotly dash ]; patches = [ ./picosnitch.patch ]; pythonImportsCheck = [ "picosnitch" ]; meta = with lib; { description = "Monitor network traffic per executable with hashing"; homepage = "https://github.com/elesiuta/picosnitch"; changelog = "https://github.com/elesiuta/picosnitch/releases"; license = licenses.gpl3Plus; maintainers = [ maintainers.elesiuta ]; platforms = platforms.linux; }; }
pkgs/tools/networking/picosnitch/picosnitch.patch 0 → 100644 +111 −0 Original line number Diff line number Diff line diff --git a/picosnitch.py b/picosnitch.py index a3dbb07..2b74f3e 100755 --- a/picosnitch.py +++ b/picosnitch.py @@ -1356,7 +1356,7 @@ def ui_loop(stdscr: curses.window, splash: str, con: sqlite3.Connection) -> int: update_query = False if execute_query: try: - with open("/run/picosnitch.pid", "r") as f: + with open("/run/picosnitch/picosnitch.pid", "r") as f: run_status = "pid: " + f.read().strip() except Exception: run_status = "not running" @@ -1603,7 +1603,7 @@ def ui_dash(): return cmdline def serve_layout(): try: - with open("/run/picosnitch.pid", "r") as f: + with open("/run/picosnitch/picosnitch.pid", "r") as f: run_status = "pid: " + f.read().strip() except Exception: run_status = "not running" @@ -1771,7 +1771,7 @@ def main(): # master copy of the snitch dictionary, all subprocesses only receive a static copy of it from this point in time snitch = read_snitch() # start picosnitch process monitor - with open("/run/picosnitch.pid", "r") as f: + with open("/run/picosnitch/picosnitch.pid", "r") as f: assert int(f.read().strip()) == os.getpid() if __name__ == "__main__" or sys.argv[1] == "start-no-daemon": sys.exit(main_process(snitch)) @@ -1818,7 +1818,7 @@ def start_picosnitch(): RestartSec=5 Environment="SUDO_UID={os.getenv("SUDO_UID")}" "SUDO_USER={os.getenv("SUDO_USER")}" "DBUS_SESSION_BUS_ADDRESS={os.getenv("DBUS_SESSION_BUS_ADDRESS")}" "PYTHON_USER_SITE={site.USER_SITE}" ExecStart={sys.executable} "{os.path.abspath(__file__)}" start-no-daemon - PIDFile=/run/picosnitch.pid + PIDFile=/run/picosnitch/picosnitch.pid [Install] WantedBy=multi-user.target @@ -1832,12 +1832,12 @@ def start_picosnitch(): subprocess.Popen(["bash", "-c", f'let i=0; rm {BASE_PATH}/dash; while [[ ! -f {BASE_PATH}/dash || "$i" -gt 30 ]]; do let i++; sleep 1; done; rm {BASE_PATH}/dash && /usr/bin/env python3 -m webbrowser -t http://{os.getenv("HOST", "localhost")}:{os.getenv("PORT", "5100")}'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if os.getuid() != 0: args = ["sudo", "-E", sys.executable, os.path.abspath(__file__), sys.argv[1]] - os.execvp("sudo", args) + assert sys.argv[1] not in ["start", "stop", "restart", "start-no-daemon"], "picosnitch requires root privileges to run" with open("/proc/self/status", "r") as f: proc_status = f.read() capeff = int(proc_status[proc_status.find("CapEff:")+8:].splitlines()[0].strip(), base=16) cap_sys_admin = 2**21 - assert capeff & cap_sys_admin, "Missing capability CAP_SYS_ADMIN" + assert sys.argv[1] not in ["start", "stop", "restart", "start-no-daemon"] or (capeff & cap_sys_admin), "Missing capability CAP_SYS_ADMIN" assert importlib.util.find_spec("bcc"), "Requires BCC https://github.com/iovisor/bcc/blob/master/INSTALL.md" tmp_snitch = read_snitch() con = sqlite3.connect(os.path.join(BASE_PATH, "snitch.db")) @@ -1883,8 +1883,8 @@ def start_picosnitch(): except Exception as e: print("Warning: %s%s on line %s" % (type(e).__name__, str(e.args), sys.exc_info()[2].tb_lineno), file=sys.stderr) if sys.argv[1] in ["start", "stop", "restart"]: - if os.path.exists("/usr/lib/systemd/system/picosnitch.service"): - print("Found /usr/lib/systemd/system/picosnitch.service but you are not using systemctl") + if os.path.exists("/usr/lib/systemd/system/picosnitch.service") or os.path.exists("/etc/systemd/system/picosnitch.service"): + print("Found picosnitch.service but you are not using systemctl") if sys.stdin.isatty(): confirm = input(f"Did you intend to run `systemctl {sys.argv[1]} picosnitch` (y/N)? ") if confirm.lower().startswith("y"): @@ -1893,15 +1893,15 @@ def start_picosnitch(): class PicoDaemon(Daemon): def run(self): main() - daemon = PicoDaemon("/run/picosnitch.pid") + daemon = PicoDaemon("/run/picosnitch/picosnitch.pid") if sys.argv[1] == "start": - print("starting picosnitch daemon") + print("starting picosnitch daemon, WARNING: built in daemon mode is not supported on Nix, use picosnitch start-no-daemon or systemctl instead") daemon.start() elif sys.argv[1] == "stop": - print("stopping picosnitch daemon") + print("stopping picosnitch daemon, WARNING: built in daemon mode is not supported on Nix, use picosnitch start-no-daemon or systemctl instead") daemon.stop() elif sys.argv[1] == "restart": - print("restarting picosnitch daemon") + print("restarting picosnitch daemon, WARNING: built in daemon mode is not supported on Nix, use picosnitch start-no-daemon or systemctl instead") daemon.restart() elif sys.argv[1] == "status": daemon.status() @@ -1912,11 +1912,12 @@ def start_picosnitch(): print("Wrote /usr/lib/systemd/system/picosnitch.service\nYou can now run picosnitch using systemctl") return 0 elif sys.argv[1] == "start-no-daemon": - assert not os.path.exists("/run/picosnitch.pid") + assert not os.path.exists("/run/picosnitch/picosnitch.pid") def delpid(): - os.remove("/run/picosnitch.pid") + os.remove("/run/picosnitch/picosnitch.pid") atexit.register(delpid) - with open("/run/picosnitch.pid", "w") as f: + os.makedirs("/run/picosnitch", exist_ok=True) + with open("/run/picosnitch/picosnitch.pid", "w") as f: f.write(str(os.getpid()) + "\n") print("starting picosnitch in simple mode") print(f"using config and log files from: {BASE_PATH}") @@ -1927,7 +1928,7 @@ def start_picosnitch(): assert dash.__version__ and pandas.__version__ and plotly.__version__ print(f"serving web gui on http://{os.getenv('HOST', 'localhost')}:{os.getenv('PORT', '5100')}") args = ["bash", "-c", f"sudo -i -u {os.getenv('SUDO_USER')} touch {BASE_PATH}/dash; nohup {sys.executable} \"{os.path.abspath(__file__)}\" start-dash > /dev/null 2>&1 &"] - os.execvp("bash", args) + return ui_dash() elif sys.argv[1] == "start-dash": return ui_dash() elif sys.argv[1] == "view":