diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 3ccdfe8e0c047..4e8ebd64aaf55 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -613,6 +613,7 @@ ./services/networking/hylafax/default.nix ./services/networking/i2pd.nix ./services/networking/i2p.nix + ./services/networking/create_ap.nix ./services/networking/iodine.nix ./services/networking/iperf3.nix ./services/networking/ircd-hybrid/default.nix diff --git a/nixos/modules/services/networking/create_ap.nix b/nixos/modules/services/networking/create_ap.nix new file mode 100644 index 0000000000000..3d5e2da98e682 --- /dev/null +++ b/nixos/modules/services/networking/create_ap.nix @@ -0,0 +1,134 @@ +{ config, lib, pkgs, ... }: +with lib; + +let + cfg = config.services.create_ap; + + valueToText = + let + conversions = { + string = id; + int = toString; + bool = value: if value then "1" else "0"; + }; + in value: conversions.${builtins.typeOf value} value; + + configFile = pkgs.writeText "create_ap.conf" + (concatStrings (mapAttrsToList (name: value: + "${name}=${valueToText value}\n" + ) (filterAttrs (_: value: value != null) cfg.settings))); + + wifiIface = cfg.settings.WIFI_IFACE; + inetIface = cfg.settings.INTERNET_IFACE; + +in { + + options.services.create_ap = with types; { + enable = mkEnableOption "Enable Create Access Point Service"; + + settings = mkOption { + type = attrsOf (nullOr (oneOf [ str int bool ])); + description = '' + create_ap configuration, see + for information on supported values. + ''; + example = literalExample '' + { + HIDDEN = true; + FREQ_BAND = 5; + DHCP_DNS = "1.1.1.1"; + COUNTRY = "US"; + } + ''; + }; + + wifiInterface = mkOption { + description = '' + Wi-Fi interface to use (Use ip link show to list available). + ''; + type = str; + example = "wlan0"; + }; + + internetInterface = mkOption { + description = '' + Interface to use for internet connection (Use ip link show to list available). + ''; + type = str; + example = "enp0"; + }; + + ssid = mkOption { + description = "SSID of the access point."; + type = str; + example = "MyAccessPoint"; + }; + + passphrase = mkOption { + description = "Passphrase to use for access point."; + type = str; + example = "12345678"; + }; + + gateway = mkOption { + description = "IPv4 Gateway for the Access Point."; + type = str; + default = "192.168.12.1"; + example = "10.0.0.1"; + }; + + channel = mkOption { + type = either str int; + example = 1; + default = "default"; + description = "WLAN Channel number."; + }; + }; + + config = mkIf cfg.enable { + + services.create_ap.settings = { + DAEMONIZE = false; + CHANNEL = mkDefault cfg.channel; + GATEWAY = mkDefault cfg.gateway; + WIFI_IFACE = mkDefault cfg.wifiInterface; + INTERNET_IFACE = mkDefault cfg.internetInterface; + SSID = mkDefault cfg.ssid; + PASSPHRASE = mkDefault cfg.passphrase; + }; + + environment.systemPackages = [ pkgs.create_ap ]; + + systemd.services.create_ap = { + description = "Create AP Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" + "sys-subsystem-net-devices-${wifiIface}.device" + "sys-subsystem-net-devices-${inetIface}.device" ]; + bindsTo = [ "sys-subsystem-net-devices-${wifiIface}.device" + "sys-subsystem-net-devices-${inetIface}.device" ]; + serviceConfig = + let capabilities = [ + "CAP_CHOWN" + "CAP_DAC_OVERRIDE" + "CAP_DAC_READ_SEARCH" + "CAP_KILL" + "CAP_NET_ADMIN" + "CAP_NET_RAW" + "CAP_NET_BIND_SERVICE" + ]; in { + KillSignal = "SIGINT"; + Restart = "on-failure"; + RestartSec = 5; + DynamicUser = true; + ProtectSystem = "strict"; + ProtectHome = true; + # create_ap parses and updates NetworkManager.conf + ReadWritePaths = "-/etc/NetworkManager/"; + AmbientCapabilities = capabilities; + CapabilityBoundingSet = capabilities; + ExecStart = "${pkgs.create_ap}/bin/create_ap --config ${configFile}"; + }; + }; + }; +} diff --git a/pkgs/tools/networking/create_ap/default.nix b/pkgs/tools/networking/create_ap/default.nix new file mode 100644 index 0000000000000..6699a59b7203c --- /dev/null +++ b/pkgs/tools/networking/create_ap/default.nix @@ -0,0 +1,93 @@ +{ stdenv, pkgs, fetchFromGitHub, iw, procps, hostapd, iproute, getopt, bash +, dnsmasq, iptables, coreutils, gnugrep, gnused, gawk, which, flock + +, haveged ? null +, networkmanager ? null +# for iwconfig +, wirelesstools ? null + +# To fall back to haveged if entropy is low. +# +# Defaulting to false because not having it does not break things. +# If it is really needed, warnings will be logged to journal. +, useHaveged ? false + +# nmcli is not required for create_ap. +# (defaulting to true because it is very likely already present) +, useNetworkManager ? true + +# You only need this if 'iw' can not recognize your adapter +, useWirelessTools ? true }: + +assert useHaveged -> !isNull haveged; +assert useNetworkManager -> !isNull networkmanager; +assert useWirelessTools -> !isNull wirelesstools; + +with stdenv.lib; +with stdenv.lib.lists; + +let binPath = makeBinPath ([ iw procps hostapd iproute getopt bash dnsmasq + iptables coreutils which flock gnugrep gnused gawk ] + ++ optional useHaveged haveged + ++ optional useNetworkManager networkmanager + ++ optional useWirelessTools wirelesstools); +in + +stdenv.mkDerivation rec { + name = "${pname}-${version}"; + version = "0.4.6"; + pname = "create_ap"; + + src = fetchFromGitHub { + owner = "oblique"; + repo = "create_ap"; + rev = "v${version}"; + sha256 = "0wwwdc63vg987512nac46h91lg0a1gzigdqrgijk4b4andr94cp4"; + }; + + nativeBuildInputs = [ pkgs.makeWrapper ]; + + patches = [ ./noroot.patch ]; + + dontBuild = true; + + installPhase = '' + mkdir -p $out/bin/ + mv create_ap $out/bin/create_ap + wrapProgram $out/bin/create_ap --prefix PATH : ${binPath} + ''; + + meta = { + homepage = https://github.com/oblique/create_ap; + description = "Creates a NATed or Bridged WiFi Access Point"; + longDescription = '' + Features: + + - Create an AP (Access Point) at any channel. + - Choose one of the following encryptions: WPA, WPA2, WPA/WPA2, Open (no encryption). + - Hide your SSID. + - Disable communication between clients (client isolation). + - IEEE 802.11n & 802.11ac support + - Internet sharing methods: NATed or Bridged or None (no Internet sharing). + - Choose the AP Gateway IP (only for 'NATed' and 'None' Internet sharing methods). + - You can create an AP with the same interface you are getting your Internet connection. + - You can pass your SSID and password through pipe or through arguments (see examples). + + See for details. + + Example service configuration: + + services.create_ap = { + enable = true; + wifi-iface = "wlan0"; + internet-iface = "eth0"; + gateway = "10.0.0.1"; + ssid = "MyAccessPoint"; + passphrase = "12345678"; + }; + ''; + license = licenses.bsd2; + maintainers = with maintainers; [ klntsky ]; + platforms = platforms.linux; + }; +} diff --git a/pkgs/tools/networking/create_ap/noroot.patch b/pkgs/tools/networking/create_ap/noroot.patch new file mode 100644 index 0000000000000..d3da19611f0e6 --- /dev/null +++ b/pkgs/tools/networking/create_ap/noroot.patch @@ -0,0 +1,27 @@ +diff --git a/create_ap b/create_ap +index 8fa6671..3949c75 100755 +--- a/create_ap ++++ b/create_ap +@@ -138,10 +138,6 @@ init_lock() { + eval "exec $LOCK_FD>$LOCK_FILE" > /dev/null 2>&1 || return 1 + umask $SCRIPT_UMASK + +- # there is a case where lock file was created from a normal +- # user. change the owner to root as soon as we can. +- [[ $(id -u) -eq 0 ]] && chown 0:0 $LOCK_FILE +- + # create mutex counter lock file + echo 0 > $COUNTER_LOCK_FILE + +@@ -1267,11 +1263,6 @@ if [[ -n "$LIST_CLIENTS_ID" ]]; then + exit 0 + fi + +-if [[ $(id -u) -ne 0 ]]; then +- echo "You must run it as root." >&2 +- exit 1 +-fi +- + if [[ -n "$STOP_ID" ]]; then + echo "Trying to kill $PROGNAME instance associated with $STOP_ID..." + send_stop "$STOP_ID" diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 58f114d1b1ae4..a7d8880abae4d 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -813,6 +813,8 @@ in cue = callPackage ../development/tools/cue { }; + create_ap = callPackage ../tools/networking/create_ap { }; + deskew = callPackage ../applications/graphics/deskew { }; detect-secrets = python3Packages.callPackage ../development/tools/detect-secrets { };