diff options
| -rw-r--r-- | lib/default.nix | 44 | ||||
| -rw-r--r-- | lib/krebs/default.nix | 3 | ||||
| -rw-r--r-- | lib/krebs/genipv6.nix | 109 | ||||
| -rw-r--r-- | lib/types.nix | 26 | ||||
| -rw-r--r-- | tv/2configs/xserver/default.nix | 42 | ||||
| -rw-r--r-- | tv/5pkgs/haskell/xmonad-tv/shell.nix | 13 | 
6 files changed, 207 insertions, 30 deletions
diff --git a/lib/default.nix b/lib/default.nix index 348d47e..347830e 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -5,6 +5,7 @@ let      evalSource = import ./eval-source.nix;      git = import ./git.nix { inherit lib; }; +    krebs = import ./krebs lib;      krops = import ../submodules/krops/lib;      shell = import ./shell.nix { inherit lib; };      types = nixpkgs-lib.types // import ./types.nix { inherit lib; }; @@ -28,8 +29,6 @@ let        listToAttrs (map (name: nameValuePair name set.${name})                         (filter (flip hasAttr set) names)); -    setAttr = name: value: set: set // { ${name} = value; }; -      test = re: x: isString x && testString re x;      testString = re: x: match re x != null; @@ -94,7 +93,13 @@ let            in              if max.pos == 0                then a -              else "${concatStringsSep ":" lhs}::${concatStringsSep ":" rhs}"; +              else let +                sep = +                  if 8 - (length lhs + length rhs) == 1 +                    then ":0:" +                    else "::"; +              in +                "${concatStringsSep ":" lhs}${sep}${concatStringsSep ":" rhs}";          drop-leading-zeros =            let @@ -108,7 +113,38 @@ let            in              a: concatStringsSep ":" (map f (splitString ":" a));        in -        a: toLower (group-zeros (drop-leading-zeros a)); +        a: +          toLower +            (if test ".*::.*" a +              then a +              else group-zeros (drop-leading-zeros a)); + +    hashToLength = n: s: substring 0 n (hashString "sha256" s); + +    dropLast = n: xs: reverseList (drop n (reverseList xs)); +    takeLast = n: xs: reverseList (take n (reverseList xs)); + +    # Split string into list of chunks where each chunk is at most n chars long. +    # The leftmost chunk might shorter. +    # Example: stringToGroupsOf "123456" -> ["12" "3456"] +    stringToGroupsOf = n: s: let +      acc = +        foldl' +          (acc: c: if stringLength acc.chunk < n then { +            chunk = acc.chunk + c; +            chunks = acc.chunks; +          } else { +            chunk = c; +            chunks = acc.chunks ++ [acc.chunk]; +          }) +          { +            chunk = ""; +            chunks = []; +          } +          (stringToCharacters s); +    in +      filter (x: x != []) ([acc.chunk] ++ acc.chunks); +    };  in diff --git a/lib/krebs/default.nix b/lib/krebs/default.nix new file mode 100644 index 0000000..c9d9bef --- /dev/null +++ b/lib/krebs/default.nix @@ -0,0 +1,3 @@ +lib: +with lib; +mapNixDir (flip import lib) ./. diff --git a/lib/krebs/genipv6.nix b/lib/krebs/genipv6.nix new file mode 100644 index 0000000..22a23fc --- /dev/null +++ b/lib/krebs/genipv6.nix @@ -0,0 +1,109 @@ +lib: +with lib; +let { +  body = netname: subnetname: suffixSpec: rec { +    address = let +      suffix' = prependZeros suffixLength suffix; +    in +      normalize-ip6-addr +        (checkAddress addressLength (joinAddress subnetPrefix suffix')); +    addressCIDR = "${address}/${toString addressLength}"; +    addressLength = 128; + +    inherit netname; +    netCIDR = "${netAddress}/${toString netPrefixLength}"; +    netAddress = +      normalize-ip6-addr (appendZeros addressLength netPrefix); +    netHash = toString { +      retiolum = 0; +      wiregrill = 1; +    }.${netname}; +    netPrefix = "42:${netHash}"; +    netPrefixLength = { +      retiolum = 32; +      wiregrill = 32; +    }.${netname}; + +    inherit subnetname; +    subnetCIDR = "${subnetAddress}/${toString subnetPrefixLength}"; +    subnetAddress = +      normalize-ip6-addr (appendZeros addressLength subnetPrefix); +    subnetHash = hashToLength 4 subnetname; +    subnetPrefix = joinAddress netPrefix subnetHash; +    subnetPrefixLength = netPrefixLength + 16; + +    suffix = getAttr (typeOf suffixSpec) { +      set = +        concatStringsSep +          ":" +          (stringToGroupsOf +            4 +            (hashToLength (suffixLength / 4) suffixSpec.hostName)); +      string = suffixSpec; +    }; +    suffixLength = addressLength - subnetPrefixLength; +  }; + +  appendZeros = n: s: let +    n' = n / 16; +    zeroCount = n' - length parsedaddr; +    parsedaddr = parseAddress s; +  in +    formatAddress (parsedaddr ++ map (const "0") (range 1 zeroCount)); + +  prependZeros = n: s: let +    n' = n / 16; +    zeroCount = n' - length parsedaddr; +    parsedaddr = parseAddress s; +  in +    formatAddress (map (const "0") (range 1 zeroCount) ++ parsedaddr); + +  hasEmptyPrefix = xs: take 2 xs == ["" ""]; +  hasEmptySuffix = xs: takeLast 2 xs == ["" ""]; +  hasEmptyInfix = xs: any (x: x == "") (trimEmpty 2 xs); + +  hasEmptyGroup = xs: +    any (p: p xs) [hasEmptyPrefix hasEmptyInfix hasEmptySuffix]; + +  ltrimEmpty = n: xs: if hasEmptyPrefix xs then drop n xs else xs; +  rtrimEmpty = n: xs: if hasEmptySuffix xs then dropLast n xs else xs; +  trimEmpty = n: xs: rtrimEmpty n (ltrimEmpty n xs); + +  parseAddress = splitString ":"; +  formatAddress = concatStringsSep ":"; + +  check = s: c: if !c then throw "${s}" else true; + +  checkAddress = maxaddrlen: addr: let +    parsedaddr = parseAddress addr; +    normalizedaddr = trimEmpty 1 parsedaddr; +  in +    assert (check "address malformed; lone leading colon: ${addr}" ( +      head parsedaddr == "" -> tail (take 2 parsedaddr) == "" +    )); +    assert (check "address malformed; lone trailing colon ${addr}" ( +      last parsedaddr == "" -> head (takeLast 2 parsedaddr) == "" +    )); +    assert (check "address malformed; too many successive colons: ${addr}" ( +      length (filter (x: x == "") normalizedaddr) > 1 -> addr == [""] +    )); +    assert (check "address malformed: ${addr}" ( +      all (test "[0-9a-f]{0,4}") parsedaddr +    )); +    assert (check "address is too long: ${addr}" ( +      length normalizedaddr * 16 <= maxaddrlen +    )); +    addr; + +  joinAddress = prefix: suffix: let +    parsedPrefix = parseAddress prefix; +    parsedSuffix = parseAddress suffix; +    normalizePrefix = rtrimEmpty 2 parsedPrefix; +    normalizeSuffix = ltrimEmpty 2 parsedSuffix; +    delimiter = +      optional (length (normalizePrefix ++ normalizeSuffix) < 8 && +                (hasEmptySuffix parsedPrefix || hasEmptyPrefix parsedSuffix)) +               ""; +  in +    formatAddress (normalizePrefix ++ delimiter ++ normalizeSuffix); +} diff --git a/lib/types.nix b/lib/types.nix index 0168533..17c1688 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -19,7 +19,7 @@ rec {          default = config._module.args.name;        };        cores = mkOption { -        type = positive; +        type = uint;        };        nets = mkOption {          type = attrsOf net; @@ -192,6 +192,28 @@ rec {          }));          default = null;        }; +      wireguard = mkOption { +        type = nullOr (submodule ({ config, ... }: { +          options = { +            port = mkOption { +              type = int; +              description = "tinc port to use to connect to host"; +              default = 51820; +            }; +            pubkey = mkOption { +              type = wireguard-pubkey; +            }; +            subnets = mkOption { +              type = listOf cidr; +              description = '' +                wireguard subnets, +                this defines how routing behaves for hosts that can't reach each other. +              ''; +              default = []; +            }; +          }; +        })); +      };      };    }); @@ -548,4 +570,6 @@ rec {      check = filename.check;      merge = mergeOneOption;    }; + +  wireguard-pubkey = str;  } diff --git a/tv/2configs/xserver/default.nix b/tv/2configs/xserver/default.nix index 8d4b13f..f68e8e6 100644 --- a/tv/2configs/xserver/default.nix +++ b/tv/2configs/xserver/default.nix @@ -48,31 +48,35 @@ in {    systemd.services.xmonad = let      xmonad = "${pkgs.haskellPackages.xmonad-tv}/bin/xmonad"; +    xmonad-prepare = pkgs.writeDash "xmonad-prepare" '' +      ${pkgs.coreutils}/bin/mkdir -p "$XMONAD_CACHE_DIR" +      ${pkgs.coreutils}/bin/mkdir -p "$XMONAD_CONFIG_DIR" +      ${pkgs.coreutils}/bin/mkdir -p "$XMONAD_DATA_DIR" +    ''; +    xmonad-ready = pkgs.writeDash "xmonad-ready" '' +      { +        ${pkgs.xorg.xhost}/bin/xhost +SI:localuser:${cfg.user.name} +        ${pkgs.xorg.xhost}/bin/xhost -LOCAL: +      } & +      ${pkgs.xorg.xmodmap}/bin/xmodmap ${import ./Xmodmap.nix args} & +      ${pkgs.xorg.xrdb}/bin/xrdb ${import ./Xresources.nix args} & +      ${pkgs.xorg.xsetroot}/bin/xsetroot -solid '#1c1c1c' & +      wait +    '';    in {      wantedBy = [ "graphical.target" ];      requires = [ "xserver.service" ];      environment = {        DISPLAY = ":${toString config.services.xserver.display}"; -        FZMENU_FZF_DEFAULT_OPTS = toString [          "--color=dark,border:126,bg+:090"          "--inline-info"        ]; -        XMONAD_CACHE_DIR = cfg.cacheDir;        XMONAD_CONFIG_DIR = cfg.configDir;        XMONAD_DATA_DIR = cfg.dataDir; - -      XMONAD_STARTUP_HOOK = pkgs.writeDash "xmonad-startup-hook" '' -        ${pkgs.xorg.xhost}/bin/xhost +LOCAL: & -        ${pkgs.xorg.xmodmap}/bin/xmodmap ${import ./Xmodmap.nix args} & -        ${pkgs.xorg.xrdb}/bin/xrdb ${import ./Xresources.nix args} & -        ${pkgs.xorg.xsetroot}/bin/xsetroot -solid '#1c1c1c' & -        wait -      ''; - -      # XXX JSON is close enough :) -      XMONAD_WORKSPACES0_FILE = pkgs.writeText "xmonad.workspaces0" (toJSON [ +      XMONAD_STARTUP_HOOK = xmonad-ready; +      XMONAD_WORKSPACES0_FILE = pkgs.writeJSON "xmonad-workspaces0.json" [          "Dashboard" # we start here          "23"          "cr" @@ -82,7 +86,7 @@ in {          "mail"          "stockholm"          "za" "zh" "zj" "zs" -      ]); +      ];      };      path = [        config.tv.slock.package @@ -93,14 +97,10 @@ in {        "/run/wrappers" # for su      ];      serviceConfig = { -      SyslogIdentifier = "xmonad"; -      ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${toString [ -        "\${XMONAD_CACHE_DIR}" -        "\${XMONAD_CONFIG_DIR}" -        "\${XMONAD_DATA_DIR}" -      ]}"; -      ExecStart = "@${xmonad} xmonad-${currentSystem} "; +      ExecStartPre = "@${xmonad-prepare} xmonad-prepare"; +      ExecStart = "@${xmonad} xmonad-${currentSystem}";        ExecStop = "@${xmonad} xmonad-${currentSystem} --shutdown"; +      SyslogIdentifier = "xmonad";        User = cfg.user.name;        WorkingDirectory = cfg.user.home;      }; diff --git a/tv/5pkgs/haskell/xmonad-tv/shell.nix b/tv/5pkgs/haskell/xmonad-tv/shell.nix index 936e696..6ca00bc 100644 --- a/tv/5pkgs/haskell/xmonad-tv/shell.nix +++ b/tv/5pkgs/haskell/xmonad-tv/shell.nix @@ -46,7 +46,7 @@ in        xmonad_restart() {(          set -efu          cd "$WORKDIR" -        if systemctl is-active xmonad; then +        if systemctl --quiet is-active xmonad; then            sudo systemctl stop xmonad            cp -b "$config_XMONAD_CACHE_DIR"/xmonad.state "$CACHEDIR"/            echo "xmonad.state: $(cat "$CACHEDIR"/xmonad.state)" @@ -59,9 +59,14 @@ in        xmonad_yield() {(          set -efu -        "$xmonad" --shutdown -        cp -b "$CACHEDIR"/xmonad.state "$config_XMONAD_CACHE_DIR"/ -        sudo systemctl start xmonad +        if ! systemctl --quiet is-active xmonad; then +          "$xmonad" --shutdown +          cp -b "$CACHEDIR"/xmonad.state "$config_XMONAD_CACHE_DIR"/ +          sudo systemctl start xmonad +        else +          echo "xmonad.service is already running" >&2 +          exit -1 +        fi        )}        export PATH=${config.systemd.services.xmonad.path}:$PATH  | 
