Initial checkin

This commit is contained in:
niten 2021-11-21 14:20:06 -08:00
commit 23351e725d
8 changed files with 316 additions and 0 deletions

7
flake.nix Normal file
View File

@ -0,0 +1,7 @@
{
description = "Fudo Nix Helper Functions";
outputs = { self, nixpkgs, ... }: {
overlay = import ./overlay.nix;
};
}

70
lib/dns.nix Normal file
View File

@ -0,0 +1,70 @@
{ pkgs, ... }:
with pkgs.lib;
let
join-lines = concatStringsSep "\n";
dump = obj: builtins.trace obj obj;
makeSrvRecords = protocol: service: records: let
service-blah = (dump service);
record-blah = (dump records);
in
join-lines (map (record:
"_${service}._${protocol} IN SRV ${toString record.priority} ${
toString record.weight
} ${toString record.port} ${record.host}.") records);
makeSrvProtocolRecords = protocol: services:
join-lines (mapAttrsToList (makeSrvRecords protocol) services);
srvRecordOpts = with types; {
options = {
weight = mkOption {
type = int;
description = "Weight relative to other records.";
default = 1;
};
priority = mkOption {
type = int;
description = "Priority to give this record.";
default = 0;
};
port = mkOption {
type = port;
description = "Port to use when connecting.";
};
host = mkOption {
type = str;
description = "Host to contact for this service.";
example = "my-host.my-domain.com.";
};
};
};
srvRecordPair = domain: protocol: service: record: {
"_${service}._${protocol}.${domain}" =
"${toString record.priority} ${toString record.weight} ${
toString record.port
} ${record.host}.";
};
in rec {
srvRecords = with types; attrsOf (attrsOf (listOf (submodule srvRecordOpts)));
srvRecordsToBindZone = srvRecords:
join-lines (mapAttrsToList makeSrvProtocolRecords srvRecords);
concatMapAttrs = f: attrs:
concatMap (x: x) (mapAttrsToList (key: val: f key val) attrs);
srvRecordsToPairs = domain: srvRecords:
listToAttrs (concatMapAttrs (protocol: services:
concatMapAttrs
(service: records: map (srvRecordPair domain protocol service) records) services)
srvRecords);
}

32
lib/filesystem.nix Normal file
View File

@ -0,0 +1,32 @@
{ pkgs, ... }:
with pkgs.lib;
let
head-or-null = lst: if (lst == []) then null else head lst;
is-regular-file = filename: type: type == "regular" || type == "link";
regular-files = path: filterAttrs is-regular-file (builtins.readDir path);
matches-ext = ext: filename: type: (builtins.match ".+[.]${ext}$" filename) != null;
is-nix-file = matches-ext "nix";
strip-ext = ext: filename: head-or-null (builtins.match "(.+)[.]${ext}$" filename);
get-ext = filename: head-or-null (builtins.match "^.+[.](.+)$" filename);
hostname-from-file = filename: strip-ext "nix";
nix-files = path:
attrNames
(filterAttrs is-nix-file
(filterAttrs is-regular-file
(builtins.readDir path)));
basename-to-file-map = path: let
files = nix-files path;
in listToAttrs
(map (file:
nameValuePair (strip-ext "nix" file)
(path + "/${file}"))
files);
import-by-basename = path:
mapAttrs (attr: attr-file: import attr-file)
(basename-to-file path);
in {
inherit basename-to-file-map import-by-basename;
}

78
lib/ip.nix Normal file
View File

@ -0,0 +1,78 @@
{ pkgs, ... }:
with pkgs.lib;
let
pow = x: e: if (e == 0) then 1 else x * (pow x (e - 1));
generateNBits = n:
let
helper = n: c:
if (c == n) then pow 2 c else (pow 2 c) + (helper n (c + 1));
in if (n <= 0) then
throw "Can't generate 0 or fewer bits"
else
helper (n - 1) 0;
rightPadBits = int: bits: bitOr int (generateNBits bits);
reverseIpv4 = ip: concatStringsSep "." (reverseList (splitString "." ip));
intToBinaryList = int:
let
helper = int: cur:
let curExp = pow 2 cur;
in if (curExp > int) then
[ ]
else
[ (if ((bitAnd curExp int) > 0) then 1 else 0) ]
++ (helper int (cur + 1));
in reverseList (helper int 0);
leftShift = int: n: int * (pow 2 n);
rightShift = int: n: int / (pow 2 n);
in rec {
ipv4ToInt = ip:
let els = map toInt (reverseList (splitString "." ip));
in foldr (a: b: a + b) 0 (imap0 (i: el: (leftShift el (i * 8))) els);
intToIpv4 = int:
concatStringsSep "."
(map (i: toString (bitAnd (rightShift int (i * 8)) 255)) [ 3 2 1 0 ]);
maskFromV32Network = network:
let
fullMask = ipv4ToInt "255.255.255.255";
insignificantBits = 32 - (getNetworkMask network);
in intToIpv4
(leftShift (rightShift fullMask insignificantBits) insignificantBits);
networkMinIp = network: intToIpv4 (1 + (ipv4ToInt (getNetworkBase network)));
networkMaxIp = network:
intToIpv4 (rightPadBits (ipv4ToInt (getNetworkBase network))
(32 - (getNetworkMask network)));
# To avoid broadcast IP...
networkMaxButOneIp = network:
intToIpv4 ((rightPadBits (ipv4ToInt (getNetworkBase network))
(32 - (getNetworkMask network))) - 1);
ipv4OnNetwork = ip: network:
let
ip-int = ipv4ToInt ip;
net-min = networkMinIp network;
net-max = networkMaxIp network;
in (ip-int >= networkMinIp) && (ip-int <= networkMaxIp);
getNetworkMask = network: toInt (elemAt (splitString "/" network) 1);
getNetworkBase = network:
let
ip = elemAt (splitString "/" network) 0;
insignificantBits = 32 - (getNetworkMask network);
in intToIpv4
(leftShift (rightShift (ipv4ToInt ip) insignificantBits) insignificantBits);
}

8
lib/lisp.nix Normal file
View File

@ -0,0 +1,8 @@
{ pkgs, ... }:
with pkgs.lib;
rec {
gather-dependencies = pkg: unique (pkg.propagatedBuildInputs ++ (concatMap gather-dependencies pkg.propagatedBuildInputs));
lisp-source-registry = pkg: concatStringsSep ":" (map (p: "${p}//") (gather-dependencies pkg));
}

53
lib/network.nix Normal file
View File

@ -0,0 +1,53 @@
{ pkgs, ... }:
with pkgs.lib;
let
generate-mac-address = hostname: interface: pkgs.stdenv.mkDerivation {
name = "mk-mac-${hostname}-${interface}";
phases = [ "installPhase" ];
installPhase = ''
echo ${hostname}-${interface} | sha1sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/' > $out
'';
};
# dropUntil = pred: lst: let
# drop-until-helper = pred: lst:
# if (length lst) == 0 then [] else
# if (pred (head lst)) then lst else (drop-until-helper pred (tail lst));
# in drop-until-helper pred lst;
# dropWhile = pred: dropUntil (el: !(pred el));
# is-whitespace = str: (builtins.match "^[[:space:]]*$" str) != null;
# stripWhitespace = str: let
# lines = builtins.split "\n" str;
# lines-front-stripped = dropWhile is-whitespace lines;
# lines-rear-stripped = lib.reverseList
# (dropWhile is-whitespace
# (lib.reverseList lines-front-stripped));
# in concatStringsSep "\n" lines-rear-stripped;
host-ipv4 = config: hostname: let
domain = config.fudo.hosts.${hostname}.domain;
host-network = config.fudo.networks.${domain};
in host-network.hosts.${hostname}.ipv4-address;
host-ipv6 = config: hostname: let
domain = config.fudo.hosts.${hostname}.domain;
host-network = config.fudo.networks.${domain};
in host-network.hosts.${hostname}.ipv6-address;
host-ips = config: hostname: let
ipv4 = host-ipv4 config hostname;
ipv6 = host-ipv6 config hostname;
not-null = o: o != null;
in filter not-null [ ipv4 ipv6 ];
in {
inherit host-ipv4 host-ipv6 host-ips;
generate-mac-address = hostname: interface: let
pkg = generate-mac-address hostname interface;
in removeSuffix "\n" (builtins.readFile "${pkg}");
}

54
lib/passwd.nix Normal file
View File

@ -0,0 +1,54 @@
{ pkgs, ... }:
with pkgs.lib;
let
hash-ldap-passwd-pkg = name: passwd-file: pkgs.stdenv.mkDerivation {
name = "${name}-ldap-passwd";
phases = [ "installPhase" ];
buildInputs = with pkgs; [ openldap ];
installPhase = ''
slappasswd -T ${passwd-file} > $out
'';
};
hash-ldap-passwd = name: passwd-file:
builtins.readFile "${hash-ldap-passwd-pkg name passwd-file}";
generate-random-passwd = name: length: pkgs.stdenv.mkDerivation {
name = "${name}-random-passwd";
phases = [ "installPhase" ];
buildInputs = with pkgs; [ pwgen ];
installPhase = ''
pwgen --secure --num-passwords=1 ${toString length} > $out
'';
};
generate-stablerandom-passwd = name: { seed, length ? 20, ... }:
pkgs.stdenv.mkDerivation {
name = "${name}-stablerandom-passwd";
phases = [ "installPhase" ];
buildInputs = with pkgs; [ pwgen ];
installPhase = ''
echo "${name}-${seed}" > seedfile
pwgen --secure --num-passwords=1 -H seedfile ${toString length} > $out
'';
};
in {
hash-ldap-passwd = hash-ldap-passwd;
random-passwd-file = name: length:
builtins.toPath "${generate-random-passwd name length}";
stablerandom-passwd-file = name: seed:
builtins.toPath "${generate-stablerandom-passwd name { seed = seed; }}";
}

14
overlay.nix Normal file
View File

@ -0,0 +1,14 @@
(final: prev: with builtins; {
lib = let
pkgs = prev;
lib = prev.lib;
in
lib // {
ip = import ./lib/ip.nix { inherit pkgs; };
dns = import ./lib/dns.nix { inherit pkgs; };
passwd = import ./lib/passwd.nix { inherit pkgs; };
lisp = import ./lib/lisp.nix { inherit pkgs; };
network = import ./lib/network.nix { inherit pkgs; };
fs = import ./lib/filesystem.nix { inherit pkgs; };
};
})