diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 4f841ecfe0d..bb2c0a8f180 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -91,6 +91,7 @@ ./programs/bcc.nix ./programs/blcr.nix ./programs/browserpass.nix + ./programs/captive-browser.nix ./programs/ccache.nix ./programs/cdemu.nix ./programs/chromium.nix diff --git a/nixos/modules/programs/captive-browser.nix b/nixos/modules/programs/captive-browser.nix new file mode 100644 index 00000000000..9765a5fa3df --- /dev/null +++ b/nixos/modules/programs/captive-browser.nix @@ -0,0 +1,108 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.captive-browser; +in +{ + ###### interface + + options = { + programs.captive-browser = { + enable = mkEnableOption "captive browser"; + + package = mkOption { + type = types.package; + default = pkgs.captive-browser; + }; + + interface = mkOption { + type = types.str; + description = "your public network interface (wlp3s0, wlan0, eth0, ...)"; + }; + + # the options below are the same as in "captive-browser.toml" + browser = mkOption { + type = types.str; + default = concatStringsSep " " [ ''${pkgs.chromium}/bin/chromium'' + ''--user-data-dir=$HOME/.chromium-captive'' + ''--proxy-server="socks5://$PROXY"'' + ''--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE localhost"'' + ''--no-first-run'' + ''--new-window'' + ''--incognito'' + ''http://cache.nixos.org/'' + ]; + description = '' + the shell (/bin/sh) command executed once the proxy starts. + When browser exits, the proxy exits. An extra env var PROXY is available. + + Here, we use a separate Chrome instance in Incognito mode, so that + it can run (and be waited for) alongside the default one, and that + it maintains no state across runs. To configure this browser open a + normal window in it, settings will be preserved. + + @volth: chromium is to open a plain HTTP (not HTTPS nor redirect to HTTPS!) website. + upstream uses http://example.com but I have seen captive portals whose DNS server resolves "example.com" to 127.0.0.1 + ''; + }; + + dhcp-dns = mkOption { + type = types.str; + description = '' + the shell (/bin/sh) command executed to obtain the DHCP + DNS server address. The first match of an IPv4 regex is used. + IPv4 only, because let's be real, it's a captive portal. + ''; + }; + + socks5-addr = mkOption { + type = types.str; + default = "localhost:1666"; + description = ''the listen address for the SOCKS5 proxy server''; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + + programs.captive-browser.dhcp-dns = mkOptionDefault ( + if config.networking.networkmanager.enable then + "${pkgs.networkmanager}/bin/nmcli dev show ${escapeShellArg cfg.interface} | ${pkgs.gnugrep}/bin/fgrep IP4.DNS" + else if config.networking.dhcpcd.enable then + "${pkgs.dhcpcd}/bin/dhcpcd -U ${escapeShellArg cfg.interface} | ${pkgs.gnugrep}/bin/fgrep domain_name_servers" + else if config.networking.useNetworkd then + "${cfg.package}/bin/systemd-networkd-dns ${escapeShellArg cfg.interface}" + else + "${config.security.wrapperDir}/udhcpc --quit --now -f -i ${escapeShellArg cfg.interface} -O dns --script ${ + pkgs.writeScript "udhcp-script" '' + #!/bin/sh + if [ "$1" = bound ]; then + echo "$dns" + fi + ''}" + ); + + security.wrappers.udhcpc = { + capabilities = "cap_net_raw+p"; + source = "${pkgs.busybox}/bin/udhcpc"; + }; + + security.wrappers.captive-browser = { + capabilities = "cap_net_raw+p"; + source = pkgs.writeScript "captive-browser" '' + #!${pkgs.bash}/bin/bash + export XDG_CONFIG_HOME=${pkgs.writeTextDir "captive-browser.toml" '' + browser = """${cfg.browser}""" + dhcp-dns = """${cfg.dhcp-dns}""" + socks5-addr = """${cfg.socks5-addr}""" + bind-device = """${cfg.interface}""" + ''} + exec ${cfg.package}/bin/captive-browser + ''; + }; + }; +} diff --git a/pkgs/applications/networking/browsers/captive-browser/default.nix b/pkgs/applications/networking/browsers/captive-browser/default.nix new file mode 100644 index 00000000000..e7bec997119 --- /dev/null +++ b/pkgs/applications/networking/browsers/captive-browser/default.nix @@ -0,0 +1,22 @@ +{ lib, fetchFromGitHub, buildGoPackage }: + +buildGoPackage rec { + name = "captive-browser"; + version = "2019-04-16"; + goPackagePath = name; + + src = fetchFromGitHub { + owner = "FiloSottile"; + repo = "captive-browser"; + rev = "08450562e58bf9564ee98ad64ef7b2800e53338f"; + sha256 = "17icgjg7h0xm8g4yy38qjhsvlz9pmlmj9kydz01y2nyl0v02i648"; + }; + + meta = with lib; { + description = "Dedicated Chrome instance to log into captive portals without messing with DNS settings"; + homepage = https://blog.filippo.io/captive-browser; + license = licenses.mit; + platforms = platforms.linux; + maintainers = with maintainers; [ volth ]; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 5e5a84bf9af..7c61d49eb74 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -10005,6 +10005,8 @@ in capnproto = callPackage ../development/libraries/capnproto { }; + captive-browser = callPackage ../applications/networking/browsers/captive-browser { }; + ndn-cxx = callPackage ../development/libraries/ndn-cxx { }; cddlib = callPackage ../development/libraries/cddlib {};