Compare commits

...

70 Commits

Author SHA1 Message Date
ab25c07f69 An attempt was made 2024-01-09 21:56:10 +00:00
aad8adf5da nixos/middleman: Add hack for working Gitea Docker image pull
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 26m52s
2024-01-09 18:50:11 +00:00
205a948486 nixos/middleman: Fix HedgeDoc websockets 2024-01-09 17:35:34 +00:00
39e7c703ba pkgs: Add modrinth-app
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 34m35s
2024-01-09 17:19:13 +00:00
d07ef96d28 envrc: Use watch_file instead of nix_direnv_watch_file 2024-01-09 13:33:00 +00:00
1a29a7d589 nixos/simpcraft: Staging server running
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 26m57s
2024-01-09 00:22:17 +00:00
ca6fe534dc nixos/git: Use separate nginx 2024-01-08 23:31:06 +00:00
e277cce3bc nixos/object: Add HedgeDoc
Some checks failed
CI / Check, build and cache Nix flake (push) Has been cancelled
2024-01-08 21:40:20 +00:00
c9ce57e2c5 nixos/middleman: Add public directory
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 24m53s
2024-01-07 03:40:33 +00:00
04dfc89f07 nixos/simpcraft: Add ToTheMoonStar to whitelist
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 24m53s
2024-01-06 14:59:57 +00:00
cfbbed8285 nixos/simpcraft: Upgrade to 0.1.1 2024-01-05 20:07:48 +00:00
066c87d3d6 nixos/simpcraft: Add mods
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m39s
2024-01-05 02:13:15 +00:00
e24ac05bb2 nixos/home/routing-common: Add vibe DNS
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m7s
2024-01-03 03:10:44 +00:00
a2b146e8ba nixos: Add librespeed
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 22m56s
2024-01-03 01:07:12 +00:00
a03fdbdbdd nixos/simpcraft: Add Eefah98 to whitelist
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m44s
2024-01-02 22:13:06 +00:00
5915f664cc nixos/simpcraft: Add hynge_ to whitelist 2024-01-02 20:49:08 +00:00
42111c530e nixos/colony: Reduce memory for mail VM
Some checks failed
CI / Check, build and cache Nix flake (push) Failing after 35m28s
2024-01-01 21:45:54 +00:00
a741e3eea2 nixos/whale2: Minecraft server updates
Some checks failed
CI / Check, build and cache Nix flake (push) Failing after 1h14m44s
2024-01-01 20:32:15 +00:00
7a4372dfe7 nixos/whale2: Add Minecraft server
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 25m30s
2024-01-01 16:28:04 +00:00
65917bad5c nixos/kelder: Disable minecraft-server 2024-01-01 16:26:45 +00:00
16c7fd7659 nixos/kelder: Update Minecraft and Nextcloud
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m55s
2023-12-31 20:21:02 +00:00
2fffefd22d Update river public IP
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m24s
2023-12-31 15:15:22 +00:00
c14aebf4a3 nixos/colony: Only start needed LVs in initrd to prevent race
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m2s
2023-12-30 21:07:12 +00:00
677f3f26ab home-manager/common: Use vi bindings for tmux 2023-12-29 21:04:07 +00:00
c55600c5af lib: Make awaitPostgres code early in preStart 2023-12-29 19:05:28 +00:00
64c3e2d720 nixos/colony: Give 8GiB more RAM to git
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 53m46s
Installer / Build installer (push) Successful in 4m43s
2023-12-28 18:54:43 +00:00
20d5fa29ae nixos/deploy: Minor improvements 2023-12-28 18:33:55 +00:00
046937de27 Update inputs and add custom NixOS branding
Some checks failed
CI / Check, build and cache Nix flake (push) Failing after 34m39s
2023-12-28 17:39:14 +00:00
bba87ef73b nixos/home/routing-common: Add trusted AS211024 to input chain
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 20m12s
2023-12-23 12:33:10 +00:00
4e3ff0a466 nixos/home/routing-common: Add dynamic DNS update script
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 20m48s
2023-12-23 01:22:41 +00:00
b1af3dbf18 nixos/tower: Add wireshark and Tailscale shell abbrev 2023-12-23 00:49:24 +00:00
f58b71e8d3 nixos/britway: Use internal addresses for DNS 2023-12-23 00:49:02 +00:00
0a86a649a6 nixos: Add SFH VM config
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 21m29s
2023-12-22 01:34:28 +00:00
85189e74f8 Add missing trusted AS211024 prefixes
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 20m12s
2023-12-20 23:43:04 +00:00
e760569b3e Don't blindly trust as211024
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 20m22s
2023-12-20 23:06:27 +00:00
0fe863844f nixos/estuary: Don't announce home prefix for now (MTU issues) 2023-12-20 22:51:01 +00:00
d44fdcfe6a nixos/home/routing-common: Restrict SSH access 2023-12-20 20:41:19 +00:00
b48e7b1c33 nixos: Initial waffletail
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 20m52s
2023-12-20 19:21:31 +00:00
d0b155d786 nixos/middleman: Wait for psql before starting nginx 2023-12-20 18:38:22 +00:00
01cb95de6d nixos/containers: Fix initial dummy deploy 2023-12-20 18:29:08 +00:00
46df9b8aa8 nixos/britway: Setup split DNS
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 19m27s
2023-12-20 16:43:20 +00:00
b2342c7a05 nixos/tower: Add tailscale
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 19m54s
2023-12-20 10:16:07 +00:00
a572be0708 nixos/britway: Use AS211024 source address for SNAT
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 19m26s
2023-12-20 01:44:24 +00:00
68bf705e85 Intra-AS211024 routing
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 19m5s
2023-12-20 01:30:27 +00:00
21136e98b2 nixos/britway: Add tailscale
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 19m49s
2023-12-20 00:21:39 +00:00
b537524e5a nixos/britway: Add headscale 2023-12-19 23:40:54 +00:00
10769a4441 nixos/britway: Export route to Dublin
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 19m2s
2023-12-19 16:59:45 +00:00
9b05e7cd8d nixos/britway: Add BGP
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 19m10s
2023-12-19 15:51:16 +00:00
eda0cdbe0e nixos: Add initial britway
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 19m34s
2023-12-19 14:30:27 +00:00
f321a039f3 nixos/home/routing-common: Send MTU DHCP option
Some checks reported warnings
CI / Check, build and cache Nix flake (push) Has been cancelled
Installer / Build installer (push) Successful in 4m36s
2023-12-17 15:19:14 +00:00
fc6c4f461f Add netboot archive (including to installer workflow)
Some checks reported warnings
CI / Check, build and cache Nix flake (push) Has been cancelled
Installer / Build installer (push) Successful in 4m31s
2023-12-17 14:56:39 +00:00
22bf75d0a0 deploy-rs: Default to skipping checks and disabling auto / magic rollback 2023-12-17 13:40:25 +00:00
318972a086 nixos/home/routing-common: Split DHCP pools 2023-12-17 13:39:55 +00:00
9fa8299b71 nixos/home/routing-common: Add missing radvd search domain
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m45s
2023-12-16 19:33:53 +00:00
490413c24b nixos/routing-common: Working DHCP
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 18m48s
2023-12-16 18:50:51 +00:00
9cec5051bf nixos/estuary: Remvoe efero upstream 2023-12-16 16:53:55 +00:00
70f49c8438 nixos/home/routing-common: Working IPv6 router 2023-12-16 15:59:33 +00:00
8b0db3ac7f nixos/home/routing-common: Add route to other router's public IPv4 2023-12-16 13:00:10 +00:00
cc07964fac nixos/palace: Add BindsTo= dependency for river on cellar 2023-12-16 12:54:10 +00:00
4624480c8b home-manager/common: Fix Nix cache config for users
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 18m32s
2023-12-13 22:57:54 +00:00
3bc8befb7d nixos/cellar: Enable SPDK dynamic scheduler
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m37s
2023-12-13 21:53:10 +00:00
1b853d405c nixos/palace: Set up virtual IOMMU for cellar
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m49s
2023-12-13 11:23:47 +00:00
82b24c3c55 nixos/cellar: Move SPDK config to separate module
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m56s
2023-12-13 02:19:04 +00:00
2f2764a364 Add json2nix util 2023-12-13 00:40:36 +00:00
4b48d7e788 nixos/nvme: Add module
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m30s
2023-12-12 01:37:14 +00:00
5686aa1a01 nixos/shill: Replicate port forwards for internal routing
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m23s
2023-12-11 16:53:09 +00:00
20a3873d25 nixos/colony: Replicate port forwards for internal routing 2023-12-11 16:51:43 +00:00
d9d7a714cd nixos/firewall: Add ability to forward per external IP 2023-12-11 14:59:40 +00:00
93892224b7 nixos/home/routing-common: Allow VRRP traffic
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m34s
2023-12-11 02:31:26 +00:00
5e5f70501c nixos/river: Initial NVMe-oF booting river :)
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m32s
2023-12-11 01:55:02 +00:00
125 changed files with 10586 additions and 1656 deletions

2
.envrc
View File

@@ -1,2 +1,2 @@
nix_direnv_watch_file devshell/{default,commands,install,vm-tasks}.nix
watch_file devshell/{default,commands,install,vm-tasks}.nix
use flake

View File

@@ -1,4 +1,4 @@
name: Installer ISO
name: Installer
on:
push:
@@ -6,7 +6,7 @@ on:
jobs:
installer:
name: Build installer ISO
name: Build installer
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
@@ -24,20 +24,27 @@ jobs:
extra-substituters = https://nix-cache.nul.ie/main
extra-trusted-public-keys = main:mMChkG8LwXrFirVfudqjSHasK1jV31OVElYD3eImYl8=
- name: Set up attic
id: setup
run: |
nix run .#nixpkgs.mine.x86_64-linux.attic-client -- \
login --set-default colony https://nix-cache.nul.ie "${{ secrets.NIX_CACHE_TOKEN }}"
echo "short_rev=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- name: Build installer ISO
id: build
run: |
nix build .#nixosConfigurations.installer.config.my.buildAs.iso
short_rev="$(git rev-parse --short HEAD)"
ln -s result/iso/nixos-installer-devplayer0.iso nixos-installer-devplayer0-$short_rev.iso
echo "short_rev=$short_rev" >> "$GITHUB_OUTPUT"
- name: Create release for ISO
nix build .#nixfiles.config.nixos.systems.installer.configuration.config.my.buildAs.iso
ln -s "$(readlink result)"/iso/jackos-installer.iso \
jackos-installer-${{ steps.setup.outputs.short_rev }}.iso
- name: Build installer netboot archive
run: |
nix build .#nixfiles.config.nixos.systems.installer.configuration.config.my.buildAs.netbootArchive
ln -s "$(readlink result)" \
jackos-installer-netboot-${{ steps.setup.outputs.short_rev }}.tar
- name: Create release
uses: https://gitea.com/actions/release-action@main
with:
title: Latest installer
files: |
nixos-installer-devplayer0-${{ steps.build.outputs.short_rev }}.iso
jackos-installer-${{ steps.setup.outputs.short_rev }}.iso
jackos-installer-netboot-${{ steps.setup.outputs.short_rev }}.tar

View File

@@ -47,8 +47,8 @@ in
(nodesFor homes)
);
autoRollback = true;
magicRollback = true;
autoRollback = false;
magicRollback = false;
};
# Filter out null values so deploy merges overriding options correctly

View File

@@ -48,6 +48,12 @@ in
help = "Print the ed25519 pubkey for a host";
command = "${pkgs.openssh}/bin/ssh-keyscan -t ed25519 \"$1\" 2> /dev/null | awk '{ print $2 \" \" $3 }'";
}
{
name = "json2nix";
category = "utilities";
help = "Convert JSON to formatted Nix";
command = "nix eval --impure --expr 'builtins.fromJSON (builtins.readFile /dev/stdin)' | ${pkgs.nixfmt}/bin/nixfmt";
}
{
name = "fmt";
@@ -91,6 +97,18 @@ in
help = "Build NixOS configuration into an ISO";
command = ''nix build "''${@:2}" ".#nixfiles.config.nixos.systems.\"$1\".configuration.config.my.buildAs.iso"'';
}
{
name = "build-kexec";
category = "tasks";
help = "Build NixOS configuration as kexec tree";
command = ''nix build "''${@:2}" ".#nixfiles.config.nixos.systems.\"$1\".configuration.config.my.buildAs.kexecTree"'';
}
{
name = "build-netboot";
category = "tasks";
help = "Build NixOS configuration as netboot archive";
command = ''nix build "''${@:2}" ".#nixfiles.config.nixos.systems.\"$1\".configuration.config.my.buildAs.netbootArchive"'';
}
{
name = "build-home";
category = "tasks";

View File

@@ -24,7 +24,9 @@ in
coreutils
nixVersions.stable
rage
deploy-rs.deploy-rs
(pkgs.writeShellScriptBin "deploy" ''
exec ${deploy-rs.deploy-rs}/bin/deploy --skip-checks "$@"
'')
home-manager
attic-client
];

154
flake.lock generated
View File

@@ -35,11 +35,11 @@
]
},
"locked": {
"lastModified": 1698258239,
"narHash": "sha256-qnhoYYIJ0L/P7H/f56lQUEvpzNlXh4sxuHpRERV+B44=",
"lastModified": 1702969472,
"narHash": "sha256-IJP9sC+/gLUdWhm6TsnWpw6A1zQWUfn53ym63KeLXvU=",
"owner": "zhaofengli",
"repo": "attic",
"rev": "e9918bc6be268da6fa97af6ced15193d8a0421c0",
"rev": "bdafd64910bb2b861cf90fa15f1fc93318b6fbf6",
"type": "github"
},
"original": {
@@ -95,26 +95,17 @@
},
"crane": {
"inputs": {
"flake-compat": [
"attic",
"flake-compat"
],
"flake-utils": [
"attic",
"flake-utils"
],
"nixpkgs": [
"attic",
"nixpkgs"
],
"rust-overlay": "rust-overlay"
]
},
"locked": {
"lastModified": 1677892403,
"narHash": "sha256-/Wi0L1spSWLFj+UQxN3j0mPYMoc7ZoAujpUF/juFVII=",
"lastModified": 1702918879,
"narHash": "sha256-tWJqzajIvYcaRWxn+cLUB9L9Pv4dQ3Bfit/YjU5ze3g=",
"owner": "ipetkov",
"repo": "crane",
"rev": "105e27adb70a9890986b6d543a67761cbc1964a2",
"rev": "7195c00c272fdd92fc74e7d5a0a2844b9fadb2fb",
"type": "github"
},
"original": {
@@ -185,11 +176,11 @@
"utils": "utils"
},
"locked": {
"lastModified": 1698921442,
"narHash": "sha256-7KmvhQ7FuXlT/wG4zjTssap6maVqeAMBdtel+VjClSM=",
"lastModified": 1703087360,
"narHash": "sha256-0VUbWBW8VyiDRuimMuLsEO4elGuUw/nc2WDeuO1eN1M=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "660180bbbeae7d60dad5a92b30858306945fd427",
"rev": "b709d63debafce9f5645a5ba550c9e0983b3d1f7",
"type": "github"
},
"original": {
@@ -241,14 +232,14 @@
"nixpkgs": [
"nixpkgs-unstable"
],
"systems": "systems_3"
"systems": "systems_4"
},
"locked": {
"lastModified": 1698410321,
"narHash": "sha256-MphuSlgpmKwtJncGMohryHiK55J1n6WzVQ/OAfmfoMc=",
"lastModified": 1701787589,
"narHash": "sha256-ce+oQR4Zq9VOsLoh9bZT8Ip9PaMLcjjBUHVPzW5d7Cw=",
"owner": "numtide",
"repo": "devshell",
"rev": "1aed986e3c81a4f6698e85a7452cbfcc4b31a36e",
"rev": "44ddedcbcfc2d52a76b64fb6122f209881bd3e1e",
"type": "github"
},
"original": {
@@ -276,11 +267,11 @@
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1668681692,
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
@@ -418,14 +409,14 @@
},
"flake-utils_7": {
"inputs": {
"systems": "systems_4"
"systems": "systems_5"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
@@ -451,7 +442,7 @@
},
"flake-utils_9": {
"inputs": {
"systems": "systems_5"
"systems": "systems_6"
},
"locked": {
"lastModified": 1681202837,
@@ -474,11 +465,11 @@
]
},
"locked": {
"lastModified": 1700814205,
"narHash": "sha256-lWqDPKHRbQfi+zNIivf031BUeyciVOtwCwTjyrhDB5g=",
"lastModified": 1703367386,
"narHash": "sha256-FMbm48UGrBfOWGt8+opuS+uLBLQlRfhiYXhHNcYMS5k=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "aeb2232d7a32530d3448318790534d196bf9427a",
"rev": "d5824a76bc6bb93d1dce9ebbbcb09a9b6abcc224",
"type": "github"
},
"original": {
@@ -494,11 +485,11 @@
]
},
"locked": {
"lastModified": 1701433070,
"narHash": "sha256-Gf9JStfENaUQ7YWFz3V7x/srIwr4nlnVteqaAxtwpgM=",
"lastModified": 1703754036,
"narHash": "sha256-JpJdcj9Tg4lMuYikXDpajA8wOp+rHyn9RD2rKBEM4cQ=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "4a8545f5e737a6338814a4676dc8e18c7f43fc57",
"rev": "c24c298562fe41b39909f632c5a7151bbf6b4628",
"type": "github"
},
"original": {
@@ -508,11 +499,11 @@
},
"impermanence": {
"locked": {
"lastModified": 1697303681,
"narHash": "sha256-caJ0rXeagaih+xTgRduYtYKL1rZ9ylh06CIrt1w5B4g=",
"lastModified": 1703656108,
"narHash": "sha256-hCSUqdFJKHHbER8Cenf5JRzjMlBjIdwdftGQsO0xoJs=",
"owner": "nix-community",
"repo": "impermanence",
"rev": "0f317c2e9e56550ce12323eb39302d251618f5b5",
"rev": "033643a45a4a920660ef91caa391fbffb14da466",
"type": "github"
},
"original": {
@@ -531,13 +522,13 @@
"locked": {
"lastModified": 1685908677,
"narHash": "sha256-E4zUPEUFyVWjVm45zICaHRpfGepfkE9Z2OECV9HXfA4=",
"owner": "guibou",
"owner": "nix-community",
"repo": "nixGL",
"rev": "489d6b095ab9d289fe11af0219a9ff00fe87c7c5",
"type": "github"
},
"original": {
"owner": "guibou",
"owner": "nix-community",
"repo": "nixGL",
"type": "github"
}
@@ -560,11 +551,11 @@
},
"nixpkgs-mine": {
"locked": {
"lastModified": 1701607327,
"narHash": "sha256-pHX6S1mrUSFVq6v0HiZuShfXLL01wiWvgivCabX2x+M=",
"lastModified": 1703756459,
"narHash": "sha256-ztEMyPQZh3Pb+LOoWl5lbIK2LenP59sOUBC86CDmLio=",
"owner": "devplayer0",
"repo": "nixpkgs",
"rev": "c8af66cb9046a65cbab33563f804b7bad46173af",
"rev": "e80160eb2ac3a7111d07cc43a15c16b9edca01ea",
"type": "github"
},
"original": {
@@ -576,11 +567,11 @@
},
"nixpkgs-mine-stable": {
"locked": {
"lastModified": 1701607437,
"narHash": "sha256-ozMDOyJtxr/CznI6lrwtt9JkU32Y2cLr2B4vlW85Tfw=",
"lastModified": 1703756491,
"narHash": "sha256-9VL34e0gzomwqRnryRn23V2ImYcaZIQdp7CsWg5TmlE=",
"owner": "devplayer0",
"repo": "nixpkgs",
"rev": "67ef05e2dd98d1fd856028eba1bb4edb847f6c6e",
"rev": "36611f5f7cfd401f51ad4ca76fd6ee85a714bb74",
"type": "github"
},
"original": {
@@ -592,11 +583,11 @@
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1701389149,
"narHash": "sha256-rU1suTIEd5DGCaAXKW6yHoCfR1mnYjOXQFOaH7M23js=",
"lastModified": 1703467016,
"narHash": "sha256-/5A/dNPhbQx/Oa2d+Get174eNI3LERQ7u6WTWOlR1eQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5de0b32be6e85dc1a9404c75131316e4ffbc634c",
"rev": "d02d818f22c777aa4e854efc3242ec451e5d462a",
"type": "github"
},
"original": {
@@ -607,11 +598,11 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1701253981,
"narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=",
"lastModified": 1703438236,
"narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58",
"rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
"type": "github"
},
"original": {
@@ -678,7 +669,7 @@
"nixpkgs": [
"nixpkgs-unstable"
],
"rust-overlay": "rust-overlay_2"
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1682237245,
@@ -715,33 +706,6 @@
}
},
"rust-overlay": {
"inputs": {
"flake-utils": [
"attic",
"crane",
"flake-utils"
],
"nixpkgs": [
"attic",
"crane",
"nixpkgs"
]
},
"locked": {
"lastModified": 1675391458,
"narHash": "sha256-ukDKZw922BnK5ohL9LhwtaDAdCsJL7L6ScNEyF1lO9w=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "383a4acfd11d778d5c2efcf28376cbd845eeaedf",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"rust-overlay_2": {
"inputs": {
"flake-utils": [
"ragenix",
@@ -862,13 +826,31 @@
"type": "github"
}
},
"utils": {
"systems_6": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {

View File

@@ -26,7 +26,7 @@
impermanence.url = "github:nix-community/impermanence";
boardie.url = "github:devplayer0/boardie";
boardie.inputs.nixpkgs.follows = "nixpkgs-unstable";
nixGL.url = "github:guibou/nixGL";
nixGL.url = "github:nix-community/nixGL";
nixGL.inputs.nixpkgs.follows = "nixpkgs-unstable";
# Packages not in nixpkgs
@@ -63,7 +63,7 @@
flake = flake-utils.lib;
};
pkgsLibOverlay = final: prev: { lib = prev.lib.extend libOverlay; };
myPkgsOverlay = final: prev: import ./pkgs { lib = prev.lib; pkgs = prev; };
myPkgsOverlay = final: prev: import ./pkgs { lib = final.lib; pkgs = prev; };
# Override the flake-level lib since we're going to use it for non-config specific stuff
pkgsFlakes = mapAttrs (_: pkgsFlake: pkgsFlake // { lib = pkgsFlake.lib.extend libOverlay; }) {
@@ -118,6 +118,7 @@
nixos/boxes/castle
nixos/boxes/home/stream.nix
nixos/boxes/home/palace
nixos/boxes/britway
nixos/boxes/kelder
# Homes
@@ -128,7 +129,7 @@
modules = [
{
_module.args = {
inherit lib pkgsFlakes hmFlakes inputs;
inherit lib pkgsFlakes hmFlakes self inputs;
pkgs' = configPkgs';
};

View File

@@ -47,9 +47,14 @@ in
nix = {
package = mkIf (!(versionAtLeast config.home.stateVersion "22.11")) pkgs.nix;
settings = {
settings = with lib.my.c.nix; {
experimental-features = [ "nix-command" "flakes" "ca-derivations" ];
max-jobs = mkDefault "auto";
extra-substituters = cache.substituters;
extra-trusted-public-keys = cache.keys;
connect-timeout = 5;
fallback = true;
};
};
@@ -75,6 +80,7 @@ in
tmux = {
enable = true;
keyMode = "vi";
};
bash = {
@@ -235,12 +241,6 @@ in
exact = true;
};
};
settings = with lib.my.c.nix; {
extra-substituters = cache.substituters;
extra-trusted-public-keys = cache.keys;
connect-timeout = 5;
fallback = true;
};
};
})
(mkIf config.my.isStandalone {

View File

@@ -10,12 +10,14 @@ rec {
gitea-runner = 401;
jellyseerr = 402;
atticd = 403;
kea = 404;
};
gids = {
matrix-syncv3 = 400;
gitea-runner = 401;
jellyseerr = 402;
atticd = 403;
kea = 404;
};
};
@@ -24,7 +26,7 @@ rec {
latest = pkgs: pkgs.linuxKernel.packages.linux_6_6;
};
nginx = {
nginx = rec {
proxyHeaders = ''
# Setting any proxy_header in a child (e.g. location) will nuke the parents...
proxy_set_header X-Origin-URI $request_uri;
@@ -38,6 +40,55 @@ rec {
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Scheme $scheme;
'';
baseHttpConfig = ''
# NixOS provides a logrotate config that auto-compresses :)
log_format main
'$remote_addr - $remote_user [$time_local] $scheme "$host" "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main;
# optimisation
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# gzip
gzip on;
gzip_proxied any;
gzip_comp_level 5;
gzip_types
application/atom+xml
application/javascript
application/json
application/xml
application/xml+rss
image/svg+xml
text/css
text/javascript
text/plain
text/xml;
gzip_vary on;
# proxying
proxy_buffering off;
proxy_redirect off;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_http_version 1.1;
${proxyHeaders}
'';
};
networkd = {
noL3 = {
LinkLocalAddressing = "no";
DHCP = "no";
LLDP = false;
EmitLLDP = false;
IPv6AcceptRA = false;
};
};
nix = {
@@ -104,6 +155,57 @@ rec {
};
home.v6 = "2a0e:97c0:4d0::/48";
};
firewallForwards = aa: [
{
port = "http";
dst = aa.middleman.internal.ipv4.address;
}
{
port = "https";
dst = aa.middleman.internal.ipv4.address;
}
{
port = 8448;
dst = aa.middleman.internal.ipv4.address;
}
{
port = 25565;
dst = aa.simpcraft-oci.internal.ipv4.address;
}
{
port = 25566;
dst = aa.simpcraft-staging-oci.internal.ipv4.address;
}
{
port = 25575;
dst = aa.simpcraft-oci.internal.ipv4.address;
}
{
port = 2456;
dst = aa.valheim-oci.internal.ipv4.address;
proto = "udp";
}
{
port = 2457;
dst = aa.valheim-oci.internal.ipv4.address;
proto = "udp";
}
{
port = 41641;
dst = aa.waffletail.internal.ipv4.address;
proto = "udp";
}
{
port = 25565;
dst = aa.simpcraft-oci.internal.ipv4.address;
proto = "udp";
}
];
fstrimConfig = {
enable = true;
# backup happens at 05:00
@@ -125,8 +227,8 @@ rec {
"stream"
];
routersPubV4 = [
"109.255.252.123" # placeholder
"109.255.252.166"
"109.255.1.246"
"109.255.252.63"
];
prefixes = with lib.my.net.cidr; rec {
@@ -143,14 +245,17 @@ rec {
hi = {
v4 = subnet 4 1 all.v4;
v6 = subnet 4 1 all.v6;
mtu = hiMTU;
};
lo = {
v4 = subnet 3 1 all.v4;
v6 = subnet 4 2 all.v6;
mtu = 1500;
};
untrusted = {
v4 = subnet 6 16 all.v4;
v6 = subnet 4 3 all.v6;
mtu = 1500;
};
inherit (colony.prefixes) as211024;
};
@@ -174,6 +279,47 @@ rec {
};
};
britway = {
domain = "lon1.int.${pubDomain}";
pubV4 = "45.76.141.188";
prefixes = {
vultr = {
v6 = "2001:19f0:7402:128b::/64";
};
inherit (colony.prefixes) as211024;
};
# Need to use this IP as the source address for BGP
assignedV6 = "2001:19f0:7402:128b:5400:04ff:feac:6e06";
};
tailscale = {
prefix = {
v4 = "100.64.0.0/10";
v6 = "fd7a:115c:a1e0::/48";
};
};
as211024 = rec {
trusted = {
v4 = [
colony.prefixes.as211024.v4
colony.prefixes.all.v4
home.prefixes.all.v4
tailscale.prefix.v4
];
v6 = [
colony.prefixes.as211024.v6
colony.prefixes.all.v6
home.prefixes.all.v6
tailscale.prefix.v6
];
};
nftTrust = ''
iifname as211024 ip saddr { ${concatStringsSep ", " trusted.v4} } accept
iifname as211024 ip6 saddr { ${concatStringsSep ", " trusted.v6} } accept
'';
};
kelder = {
groups = {
storage = 2000;

View File

@@ -1,10 +1,11 @@
{ lib }:
let
inherit (builtins) length match elemAt filter;
inherit (builtins) length match elemAt filter replaceStrings substring;
inherit (lib)
genAttrs mapAttrsToList filterAttrsRecursive nameValuePair types
mkOption mkOverride mkForce mkIf mergeEqualOption optional
showWarnings concatStringsSep flatten unique;
showWarnings concatStringsSep flatten unique optionalAttrs
mkBefore;
inherit (lib.flake) defaultSystems;
in
rec {
@@ -123,6 +124,12 @@ rec {
home-manager = mkOpt' (enum [ "unstable" "stable" "mine" "mine-stable" ]) "unstable" "Branch of home-manager to use.";
};
nft = rec {
ipEscape = replaceStrings ["." ":"] ["-" "-"];
natFilterChain = ip: "filter-fwd-${ipEscape ip}";
dnatChain = ip: "fwd-${ipEscape ip}";
};
mkVLAN = name: vid: {
"25-${name}" = {
netdevConfig = {
@@ -146,6 +153,9 @@ rec {
LLDP = true;
EmitLLDP = "customer-bridge";
};
linkConfig = optionalAttrs (a.mtu != null) {
MTUBytes = toString a.mtu;
};
ipv6AcceptRAConfig = {
Token = mkIf (a.ipv6.iid != null) "static:${a.ipv6.iid}";
UseDNS = true;
@@ -157,7 +167,7 @@ rec {
systemdAwaitPostgres = pkg: host: {
after = [ "systemd-networkd-wait-online.service" ];
preStart = ''
preStart = mkBefore ''
until ${pkg}/bin/pg_isready -h ${host}; do
sleep 0.5
done
@@ -230,4 +240,18 @@ rec {
filterOpts = filterAttrsRecursive (_: v: v != null);
};
versionOverlay = { self, pkgsFlake }: final: prev:
let
date = substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101");
revCode = flake: flake.shortRev or "dirty";
in
{
trivial = prev.trivial // {
release = "23.12:u-${prev.trivial.release}";
codeName = "Amogus";
revisionWithDefault = default: self.rev or default;
versionSuffix = ".${date}.${revCode self}:u-${revCode pkgsFlake}";
};
};
}

197
nixos/boxes/britway/bgp.nix Normal file
View File

@@ -0,0 +1,197 @@
{ lib, pkgs, config, assignments, ... }:
let
inherit (lib.my.c.britway) assignedV6;
securebitSpace = "2a0e:97c0:4d0::/44";
intnet6 = "2a0e:97c0:4df::/48";
amsnet6 = "2a0e:97c0:4d2::/48";
homenet6 = "2a0e:97c0:4d0::/48";
in
{
config = {
my = {
secrets.files."britway/bgp-password-vultr.conf" = {
owner = "bird2";
group = "bird2";
};
};
environment.etc."bird/vultr-password.conf".source = config.age.secrets."britway/bgp-password-vultr.conf".path;
systemd = {
services.bird2.after = [ "systemd-networkd-wait-online@veth0.service" ];
network = {
config.networkConfig.ManageForeignRoutes = false;
};
};
services = {
bird2 = {
enable = true;
preCheckConfig = ''
echo '"dummy"' > vultr-password.conf
'';
# TODO: Clean up and modularise
config = ''
define OWNAS = 211024;
define OWNIP4 = ${assignments.vultr.ipv4.address};
define OWNNETSET4 = [ ${assignments.vultr.ipv4.address}/32 ];
define INTNET6 = ${intnet6};
define AMSNET6 = ${amsnet6};
define HOMENET6 = ${homenet6};
define OWNIP6 = ${assignments.vultr.ipv6.address};
define OWNNETSET6 = [ ${intnet6}, ${amsnet6}, ${homenet6} ];
#define TRANSSET6 = [ ::1/128 ];
define DUB1IP6 = ${lib.my.c.home.vips.as211024.v6};
define PREFIXP = 110;
define PREFPEER = 120;
filter bgp_import {
if net !~ OWNNETSET4 && net !~ OWNNETSET6 then accept; else reject;
}
filter bgp_export {
if net ~ OWNNETSET4 || net ~ OWNNETSET6 then accept; else reject;
}
router id from "veth0";
protocol device {}
protocol direct {
interface "veth0";
ipv4;
ipv6;
}
protocol static static4 {
ipv4 {
import all;
export none;
};
}
protocol static static6 {
# Special case: We have to do the routing on behalf of this _internal_ next-hop
route INTNET6 via "as211024";
route HOMENET6 via DUB1IP6;
ipv6 {
import all;
export none;
};
}
protocol kernel kernel4 {
ipv4 {
import none;
export none;
};
}
protocol kernel kernel6 {
ipv6 {
import none;
export filter {
if net = HOMENET6 then accept;
reject;
};
};
}
protocol bgp bgptools {
local as OWNAS;
multihop;
description "bgp.tools monitoring";
neighbor 2a0c:2f07:9459::b11 as 212232;
source address OWNIP6;
ipv4 {
import none;
export all;
add paths tx;
};
ipv6 {
import none;
export all;
add paths tx;
};
}
template bgp base_bgp4 {
local as OWNAS;
direct;
allow local as;
ipv4 {
import keep filtered;
export none;
};
}
template bgp upstream_bgp4 from base_bgp4 {
ipv4 {
#import none;
import filter bgp_import;
};
}
template bgp peer_bgp4 from base_bgp4 {
ipv4 {
import filter bgp_import;
preference PREFPEER;
};
}
template bgp ixp_bgp4 from base_bgp4 {
ipv4 {
import filter bgp_import;
preference PREFIXP;
};
}
template bgp base_bgp6 {
local ${assignedV6} as OWNAS;
direct;
# So we can see routes we announce from other routers
allow local as;
ipv6 {
import keep filtered;
export filter bgp_export;
};
}
template bgp upstream_bgp6 from base_bgp6 {
ipv6 {
#import none;
import filter bgp_import;
};
}
template bgp peer_bgp6 from base_bgp6 {
ipv6 {
import filter bgp_import;
preference PREFPEER;
};
}
template bgp ixp_bgp6 from base_bgp6 {
ipv6 {
import filter bgp_import;
preference PREFIXP;
};
}
protocol bgp upstream4_vultr from upstream_bgp4 {
description "Vultr transit (IPv4)";
neighbor 169.254.169.254 as 64515;
multihop 2;
password
include "vultr-password.conf";;
}
protocol bgp upstream6_vultr from upstream_bgp6 {
description "Vultr transit (IPv6)";
neighbor 2001:19f0:ffff::1 as 64515;
multihop 2;
password
include "vultr-password.conf";;
}
'';
};
};
};
}

View File

@@ -0,0 +1,174 @@
{ lib, ... }:
let
inherit (lib.my) net;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.britway) prefixes domain pubV4 assignedV6;
in
{
nixos.systems.britway = {
system = "x86_64-linux";
nixpkgs = "mine";
assignments = {
vultr = {
inherit domain;
ipv4 = {
address = pubV4;
mask = 23;
gateway = "45.76.140.1";
};
ipv6 = {
iid = "::1";
address = "2001:19f0:7402:128b::1";
};
};
as211024 = {
ipv4 = {
address = net.cidr.host 5 prefixes.as211024.v4;
gateway = null;
};
ipv6.address = net.cidr.host ((2*65536*65536*65536) + 1) prefixes.as211024.v6;
};
};
configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
let
inherit (lib) mkMerge mkForce;
inherit (lib.my) networkdAssignment;
in
{
imports = [
"${modulesPath}/profiles/qemu-guest.nix"
./bgp.nix
./nginx.nix
./tailscale.nix
];
config = mkMerge [
{
boot = {
initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "sr_mod" ];
loader = {
systemd-boot.enable = false;
grub = {
enable = true;
device = "/dev/vda";
};
};
};
fileSystems = {
"/boot" = {
device = "/dev/disk/by-partuuid/c557ef12-da44-41d1-84f5-d32a711feefd";
fsType = "ext4";
};
"/nix" = {
device = "/dev/disk/by-partuuid/d42d0853-b054-4104-8afd-6d36287c7ca3";
fsType = "ext4";
};
"/persist" = {
device = "/dev/disk/by-partuuid/f14fbcf4-5242-456b-a4db-ef15d053d62e";
fsType = "ext4";
neededForBoot = true;
};
};
services = {
iperf3 = {
enable = true;
openFirewall = true;
};
};
networking = { inherit domain; };
systemd.network = {
config = {
routeTables.ts-extra = 1337;
};
links = {
"10-veth0" = {
matchConfig.PermanentMACAddress = "56:00:04:ac:6e:06";
linkConfig.Name = "veth0";
};
};
networks = {
"20-veth0" = mkMerge [
(networkdAssignment "veth0" assignments.vultr)
{
address = [ "${assignedV6}/64" ];
}
];
"90-l2mesh-as211024" = mkMerge [
(networkdAssignment "as211024" assignments.as211024)
{
matchConfig.Name = "as211024";
networkConfig.IPv6AcceptRA = mkForce false;
routes = map (r: { routeConfig = r; }) [
{
Destination = lib.my.c.colony.prefixes.all.v4;
Gateway = allAssignments.estuary.as211024.ipv4.address;
}
{
Destination = lib.my.c.home.prefixes.all.v4;
Gateway = lib.my.c.home.vips.as211024.v4;
}
{
# Just when routing traffic from Tailscale nodes, otherwise use WAN
Destination = lib.my.c.colony.prefixes.all.v6;
Gateway = allAssignments.estuary.as211024.ipv6.address;
Table = "ts-extra";
}
];
routingPolicyRules = map (r: { routingPolicyRuleConfig = r; }) [
{
IncomingInterface = "tailscale0";
To = lib.my.c.colony.prefixes.all.v6;
Table = "ts-extra";
}
];
}
];
};
};
my = {
server.enable = true;
secrets = {
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAmXC9egI46Qtaiifhq2I+rv2s1yPyzTlO4BHzUb+3Su";
files = {
"l2mesh/as211024.key" = {};
};
};
vpns = {
l2.pskFiles = {
as211024 = config.age.secrets."l2mesh/as211024.key".path;
};
};
firewall = {
trustedInterfaces = [ "tailscale0" ];
extraRules = ''
table inet filter {
chain forward {
${lib.my.c.as211024.nftTrust}
oifname as211024 accept
}
}
table inet nat {
chain postrouting {
iifname tailscale0 oifname veth0 snat ip to ${assignments.vultr.ipv4.address}
iifname tailscale0 oifname veth0 snat ip6 to ${assignments.as211024.ipv6.address}
}
}
'';
};
};
}
];
};
};
}

View File

@@ -0,0 +1,109 @@
{ lib, pkgs, config, ... }:
let
inherit (builtins) mapAttrs;
inherit (lib) mkMerge mkDefault;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.nginx) baseHttpConfig proxyHeaders;
in
{
config = {
my = {
secrets.files = {
"dhparams.pem" = {
owner = "acme";
group = "acme";
mode = "440";
};
"britway/cloudflare-credentials.conf" = {
owner = "acme";
group = "acme";
};
};
firewall = {
tcp.allowed = [ "http" "https" ];
};
};
users = {
users = {
nginx.extraGroups = [ "acme" ];
};
};
security.acme = {
acceptTerms = true;
defaults = {
email = "dev@nul.ie";
server = "https://acme-v02.api.letsencrypt.org/directory";
reloadServices = [ "nginx" ];
dnsResolver = "8.8.8.8";
};
certs = {
"${pubDomain}" = {
extraDomainNames = [
"*.${pubDomain}"
];
dnsProvider = "cloudflare";
credentialsFile = config.age.secrets."britway/cloudflare-credentials.conf".path;
};
};
};
services = {
nginx = {
enable = true;
enableReload = true;
logError = "stderr info";
recommendedTlsSettings = true;
serverTokens = true;
sslDhparam = config.age.secrets."dhparams.pem".path;
# Based on recommended*Settings, but probably better to be explicit about these
appendHttpConfig = ''
${baseHttpConfig}
# caching
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=512m;
'';
virtualHosts =
let
hosts = {
"_" = {
default = true;
forceSSL = true;
onlySSL = false;
locations = {
"/".root = "${pkgs.nginx}/html";
};
};
"ts.${pubDomain}" = {
locations."/" = {
proxyPass = "http://localhost:${toString config.services.headscale.port}";
proxyWebsockets = true;
extraConfig = ''
proxy_buffering off;
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
'';
};
};
};
defaultsFor = mapAttrs (n: _: {
onlySSL = mkDefault true;
useACMEHost = mkDefault pubDomain;
kTLS = mkDefault true;
http2 = mkDefault true;
});
in
mkMerge [
hosts
(defaultsFor hosts)
];
};
};
};
}

View File

@@ -0,0 +1,110 @@
{ lib, pkgs, config, assignments, allAssignments, ... }:
let
inherit (lib) concatStringsSep;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.britway) prefixes domain;
# Can't use overrideAttrs because we need to override `vendorHash` within `buildGoModule`
headscale = pkgs.headscale.override {
buildGoModule = args: pkgs.buildGoModule (args // rec {
version = "0.23.0-alpha2";
src = pkgs.fetchFromGitHub {
owner = "juanfont";
repo = "headscale";
rev = "v${version}";
hash = "sha256-sz+uQyyq/5YYDe5I44x5x2nvd48swAhNlInB8KZYvDo=";
};
vendorHash = "sha256-u9AmJguQ5dnJpfhOeLN43apvMHuraOrJhvlEIp9RoIc=";
});
};
advRoutes = concatStringsSep "," [
lib.my.c.home.prefixes.all.v4
lib.my.c.home.prefixes.all.v6
];
pubNameservers = [
"1.1.1.1"
"1.0.0.1"
"2606:4700:4700::1111"
"2606:4700:4700::1001"
];
in
{
config = {
environment.systemPackages = [
# For CLI
config.services.headscale.package
];
services = {
headscale = {
enable = true;
package = headscale;
settings = {
disable_check_updates = true;
unix_socket_permission = "0770";
server_url = "https://ts.${pubDomain}";
db_type = "sqlite3";
db_path = "/var/lib/headscale/db.sqlite3";
noise.private_key_path = "/var/lib/headscale/noise_private.key";
ip_prefixes = with lib.my.c.tailscale.prefix; [ v4 v6 ];
dns_config = {
# Use IPs that will route inside the VPN to prevent interception
# (e.g. DNS rebinding filtering)
restricted_nameservers = {
"${domain}" = pubNameservers;
"${lib.my.c.colony.domain}" = with allAssignments.estuary.base; [
ipv4.address ipv6.address
];
"${lib.my.c.home.domain}" = with allAssignments; [
river.hi.ipv4.address
river.hi.ipv6.address
stream.hi.ipv4.address
stream.hi.ipv6.address
];
};
magic_dns = true;
base_domain = "ts.${pubDomain}";
override_local_dns = false;
};
oidc = {
only_start_if_oidc_is_available = true;
issuer = "https://accounts.google.com";
client_id = "545475967061-l45cln081mp8t4li2c34v7t7b8la6f4f.apps.googleusercontent.com";
client_secret_path = config.age.secrets."britway/oidc-secret.txt".path;
scope = [ "openid" "profile" "email" ];
allowed_users = [ "jackos1998@gmail.com" ];
};
};
};
tailscale = {
enable = true;
authKeyFile = config.age.secrets."tailscale-auth.key".path;
openFirewall = true;
interfaceName = "tailscale0";
extraUpFlags = [
"--operator=${config.my.user.config.name}"
"--login-server=https://ts.nul.ie"
"--netfilter-mode=off"
"--advertise-exit-node"
"--advertise-routes=${advRoutes}"
"--accept-routes=false"
];
};
};
my = {
secrets = {
files = {
"britway/oidc-secret.txt" = {
owner = "headscale";
group = "headscale";
mode = "440";
};
"tailscale-auth.key" = {};
};
};
};
};
}

View File

@@ -17,13 +17,9 @@ in
mask = 22;
gateway = null;
};
};
lo = {
inherit domain;
ipv4 = {
address = net.cidr.host 40 prefixes.lo.v4;
mask = 21;
gateway = null;
ipv6 = {
iid = "::3:1";
address = net.cidr.host (65536*3+1) prefixes.hi.v6;
};
};
};
@@ -108,7 +104,13 @@ in
blueman.enable = true;
};
programs.virt-manager.enable = true;
programs = {
virt-manager.enable = true;
wireshark = {
enable = true;
package = pkgs.wireshark-qt;
};
};
virtualisation.libvirtd.enable = true;
networking = {
@@ -147,7 +149,6 @@ in
wait-online.enable = false;
netdevs = mkMerge [
(mkVLAN "lan-hi" vlans.hi)
(mkVLAN "lan-lo" vlans.lo)
];
links = {
"10-et2.5g" = {
@@ -169,28 +170,23 @@ in
networks = {
"50-lan" = {
matchConfig.Name = "et2.5g";
DHCP = "yes";
DHCP = "no";
address = [ "10.16.7.1/16" ];
};
"50-et100g" = {
matchConfig.Name = "et100g";
vlan = [ "lan-hi" "lan-lo" ];
vlan = [ "lan-hi" ];
networkConfig.IPv6AcceptRA = false;
};
"60-lan-hi" = mkMerge [
(networkdAssignment "lan-hi" assignments.hi)
{
DHCP = "yes";
matchConfig.Name = "lan-hi";
linkConfig.MTUBytes = "9000";
}
];
"60-lan-lo" = mkMerge [
(networkdAssignment "lan-lo" assignments.lo)
{
matchConfig.Name = "lan-lo";
linkConfig.MTUBytes = "1500";
}
];
};
};
};
@@ -251,6 +247,7 @@ in
secrets = {
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMlVuTzKObeaUuPocCF41IO/8X+443lzUJLuCIclt2vr";
};
nvme.uuid = "2230b066-a674-4f45-a1dc-f7727b3a9e7b";
firewall = {
enable = false;

View File

@@ -1,7 +1,7 @@
{ lib, ... }:
let
inherit (lib.my) net;
inherit (lib.my.c.colony) domain prefixes;
inherit (lib.my.c.colony) domain prefixes firewallForwards;
in
{
imports = [ ./vms ];
@@ -66,10 +66,21 @@ in
};
});
kernelModules = [ "kvm-amd" ];
kernelParams = [ "amd_iommu=on" "console=ttyS0,115200n8" "console=ttyS1,115200n8" "console=tty0" ];
kernelParams = [
"amd_iommu=on"
"console=ttyS0,115200n8" "console=ttyS1,115200n8" "console=tty0"
"systemd.setenv=SYSTEMD_SULOGIN_FORCE=1"
];
initrd = {
kernelModules = [ "dm-raid" ];
availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
systemd = {
enable = true;
# Onlu activate volumes needed for boot to prevent thin check from getting killed while switching root
contents."/etc/lvm/lvm.conf".text = ''
activation/auto_activation_volume_list = [ "main/colony-nix" "main/colony-persist" ]
'';
};
};
};
@@ -137,6 +148,15 @@ in
services = {
"serial-getty@ttyS0".enable = true;
"serial-getty@ttyS1".enable = true;
lvm-activate-main = {
description = "Activate remaining LVs";
before = [ "local-fs-pre.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.lvm2.bin}/bin/vgchange -aay main";
};
wantedBy = [ "sysinit.target" ];
};
rsync-lvm-meta = {
description = "rsync lvm metadata backups / archives to rsync.net";
@@ -248,6 +268,14 @@ in
Destination = allAssignments.shill.internal.ipv4.address;
Gateway = allAssignments.shill.routing.ipv4.address;
}
{
Destination = lib.my.c.tailscale.prefix.v4;
Gateway = allAssignments.shill.routing.ipv4.address;
}
{
Destination = lib.my.c.tailscale.prefix.v6;
Gateway = allAssignments.shill.internal.ipv6.address;
}
{
Destination = prefixes.oci.v4;
@@ -351,6 +379,7 @@ in
firewall = {
trustedInterfaces = [ "vms" ];
nat.forwardPorts."${allAssignments.estuary.internal.ipv4.address}" = firewallForwards allAssignments;
extraRules = ''
define cust = { vm-mail, vm-darts }
table inet filter {

View File

@@ -120,7 +120,7 @@
cpus = 12;
threads = 2;
};
memory = 49152;
memory = 40960;
networks.vms.mac = "52:54:00:27:3d:5c";
cleanShutdown.timeout = 120;
drives = [ ] ++ (optionals (!config.my.build.isDevVM) [
@@ -160,7 +160,7 @@
cpus = 12;
threads = 2;
};
memory = 32768;
memory = 40960;
networks.vms.mac = "52:54:00:75:78:a8";
cleanShutdown.timeout = 120;
drives = [
@@ -181,7 +181,7 @@
cpus = 3;
threads = 2;
};
memory = 8192;
memory = 6144;
networks.public = {
bridge = null;
mac = "52:54:00:a8:d1:03";

View File

@@ -27,7 +27,9 @@ in
define HOMENET6 = ${homenet6};
define OWNIP6 = ${assignments.base.ipv6.address};
define OWNNETSET6 = [ ${intnet6}, ${amsnet6}, ${homenet6} ];
# we have issues with sending ICMPv6 too big back on the wrong interface right now...
define OWNNETSET6 = [ ${intnet6}, ${amsnet6} ];
define CCNETSET6 = [ ];
#define TRANSSET6 = [ ::1/128 ];
define DUB1IP6 = ${lib.my.c.home.vips.as211024.v6};
@@ -42,7 +44,7 @@ in
if net ~ OWNNETSET4 || net ~ OWNNETSET6 then accept; else reject;
}
filter bgp_export_cc {
if net ~ OWNNETSET4 || net ~ OWNNETSET6 || net ~ CCNETSET4 then accept; else reject;
if net ~ OWNNETSET4 || net ~ OWNNETSET6 || net ~ CCNETSET4 || net ~ CCNETSET6 then accept; else reject;
}
router id from "wan";
@@ -188,10 +190,12 @@ in
protocol bgp upstream6_coloclue_eun2 from upstream_bgp6 {
description "ColoClue euNetworks 2 (IPv6)";
neighbor 2a02:898:0:20::e2 as 8283;
ipv6 { export filter bgp_export_cc; };
}
protocol bgp upstream6_coloclue_eun3 from upstream_bgp6 {
description "ColoClue euNetworks 3 (IPv6)";
neighbor 2a02:898:0:20::e1 as 8283;
ipv6 { export filter bgp_export_cc; };
}
protocol bgp upstream6_ifog from upstream_bgp6 {
@@ -204,14 +208,15 @@ in
neighbor 2001:7f8:10f::1b1b:154 as 6939;
}
protocol bgp upstream4_fogixp_efero from upstream_bgp4 {
description "efero transit (on FogIXP, IPv4)";
neighbor 185.1.147.107 as 208431;
}
protocol bgp upstream6_fogixp_efero from upstream_bgp6 {
description "efero transit (on FogIXP, IPv6)";
neighbor 2001:7f8:ca:1::107 as 208431;
}
# Not working so well lately...
# protocol bgp upstream4_fogixp_efero from upstream_bgp4 {
# description "efero transit (on FogIXP, IPv4)";
# neighbor 185.1.147.107 as 208431;
# }
# protocol bgp upstream6_fogixp_efero from upstream_bgp6 {
# description "efero transit (on FogIXP, IPv6)";
# neighbor 2001:7f8:ca:1::107 as 208431;
# }
protocol bgp peer4_cc_luje from peer_bgp4 {
description "LUJE.net (on ColoClue, IPv4)";

View File

@@ -2,7 +2,7 @@
let
inherit (builtins) elemAt;
inherit (lib.my) net mkVLAN;
inherit (lib.my.c.colony) pubV4 domain prefixes;
inherit (lib.my.c.colony) pubV4 domain prefixes firewallForwards;
in
{
nixos = {
@@ -13,8 +13,9 @@ in
security.enable = true;
peers = {
estuary.addr = pubV4;
# river.addr = elemAt lib.my.c.home.routersPubV4 0;
river.addr = elemAt lib.my.c.home.routersPubV4 0;
stream.addr = elemAt lib.my.c.home.routersPubV4 1;
britway.addr = lib.my.c.britway.pubV4;
};
};
};
@@ -65,6 +66,7 @@ in
let
inherit (lib) flatten mkIf mkMerge mkForce;
inherit (lib.my) networkdAssignment;
inherit (lib.my.c) networkd;
in
{
imports = [ "${modulesPath}/profiles/qemu-guest.nix" ./dns.nix ./bgp.nix ];
@@ -246,13 +248,7 @@ in
Kind = "vlan";
};
vlan = [ "frys-ix" "nl-ix" "fogixp" "ifog-transit" ];
networkConfig = {
LinkLocalAddressing = "no";
DHCP = "no";
LLDP = false;
EmitLLDP = false;
IPv6AcceptRA = false;
};
networkConfig = networkd.noL3;
};
"85-ifog-transit" = {
matchConfig.Name = "ifog-transit";
@@ -302,6 +298,15 @@ in
Destination = prefixes.cust.v6;
Gateway = allAssignments.colony.internal.ipv6.address;
}
{
Destination = lib.my.c.tailscale.prefix.v4;
Gateway = allAssignments.colony.routing.ipv4.address;
}
{
Destination = lib.my.c.tailscale.prefix.v6;
Gateway = allAssignments.colony.internal.ipv6.address;
}
] ++
(map (pName: [
{
@@ -321,6 +326,12 @@ in
{
matchConfig.Name = "as211024";
networkConfig.IPv6AcceptRA = mkForce false;
routes = map (r: { routeConfig = r; }) [
{
Destination = lib.my.c.home.prefixes.all.v4;
Gateway = lib.my.c.home.vips.as211024.v4;
}
];
}
];
"95-kelder" = {
@@ -355,38 +366,12 @@ in
};
};
firewall = {
trustedInterfaces = [ "as211024" ];
udp.allowed = [ 5353 lib.my.c.kelder.vpn.port ];
tcp.allowed = [ 5353 "bgp" ];
nat = {
enable = true;
externalInterface = "wan";
externalIP = assignments.internal.ipv4.address;
forwardPorts = [
{
port = "http";
dst = allAssignments.middleman.internal.ipv4.address;
}
{
port = "https";
dst = allAssignments.middleman.internal.ipv4.address;
}
{
port = 8448;
dst = allAssignments.middleman.internal.ipv4.address;
}
{
port = 2456;
dst = allAssignments.valheim-oci.internal.ipv4.address;
proto = "udp";
}
{
port = 2457;
dst = allAssignments.valheim-oci.internal.ipv4.address;
proto = "udp";
}
];
forwardPorts."${assignments.internal.ipv4.address}" = firewallForwards allAssignments;
};
extraRules =
let
@@ -408,12 +393,16 @@ in
# Safe enough to allow all SSH
tcp dport ssh accept
${matchInet "tcp dport { http, https, 8448 } accept" "middleman"}
${matchInet "udp dport { 2456-2457 } accept" "valheim-oci"}
ip6 daddr ${aa.middleman.internal.ipv6.address} tcp dport { http, https, 8448 } accept
${matchInet "tcp dport { http, https } accept" "git"}
ip6 daddr ${aa.simpcraft-oci.internal.ipv6.address} tcp dport { 25565, 25575 } accept
ip6 daddr ${aa.simpcraft-staging-oci.internal.ipv6.address} tcp dport 25565 accept
return
}
chain routing-udp {
ip6 daddr ${aa.valheim-oci.internal.ipv6.address} udp dport { 2456-2457 } accept
ip6 daddr ${aa.waffletail.internal.ipv6.address} udp dport 41641 accept
ip6 daddr ${aa.simpcraft-oci.internal.ipv6.address} udp dport 25565 accept
return
}
chain filter-routing {
@@ -430,7 +419,8 @@ in
}
chain forward {
iifname { wan, $ixps } oifname base jump filter-routing
${lib.my.c.as211024.nftTrust}
iifname { wan, as211024, $ixps } oifname base jump filter-routing
oifname $ixps jump ixp
iifname base oifname { base, wan, $ixps } accept
oifname { as211024, kelder } accept
@@ -443,11 +433,9 @@ in
table inet nat {
chain prerouting {
${matchInet "meta l4proto { udp, tcp } th dport domain redirect to :5353" "estuary"}
ip daddr ${aa.git.internal.ipv4.address} tcp dport { http, https } dnat to ${aa.middleman.internal.ipv4.address}
ip6 daddr ${aa.git.internal.ipv6.address} tcp dport { http, https } dnat to ${aa.middleman.internal.ipv6.address}
}
chain postrouting {
ip saddr ${prefixes.all.v4} snat to ${assignments.internal.ipv4.address}
ip saddr ${prefixes.all.v4} oifname != as211024 snat to ${assignments.internal.ipv4.address}
}
}
'';

View File

@@ -52,7 +52,7 @@ in
allowFrom = [
"127.0.0.0/8" "::1/128"
prefixes.all.v4 prefixes.all.v6
];
] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
};
settings = {
@@ -145,9 +145,14 @@ in
http IN A ${assignments.internal.ipv4.address}
http IN AAAA ${allAssignments.middleman.internal.ipv6.address}
librespeed IN CNAME http.${config.networking.domain}.
valheim IN A ${assignments.internal.ipv4.address}
valheim IN AAAA ${allAssignments.valheim-oci.internal.ipv6.address}
simpcraft IN A ${assignments.internal.ipv4.address}
simpcraft IN AAAA ${allAssignments.simpcraft-oci.internal.ipv6.address}
simpcraft-staging IN A ${assignments.internal.ipv4.address}
simpcraft-staging IN AAAA ${allAssignments.simpcraft-staging-oci.internal.ipv6.address}
mail-vm IN A ${net.cidr.host 0 prefixes.mail.v4}
mail-vm IN AAAA ${net.cidr.host 1 prefixes.mail.v6}

View File

@@ -1,8 +1,11 @@
{ lib, ... }:
let
inherit (builtins) mapAttrs;
inherit (lib) mkMerge mkDefault;
inherit (lib.my) net;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.colony) domain prefixes;
inherit (lib.my.c.nginx) baseHttpConfig proxyHeaders;
in
{
nixos.systems.git = {
@@ -72,9 +75,109 @@ in
};
};
users = {
users = {
nginx.extraGroups = [ "acme" ];
};
};
security.acme = {
acceptTerms = true;
defaults = {
email = "dev@nul.ie";
server = "https://acme-v02.api.letsencrypt.org/directory";
reloadServices = [ "nginx" ];
dnsResolver = "8.8.8.8";
};
certs = {
"${pubDomain}" = {
extraDomainNames = [
"*.${pubDomain}"
];
dnsProvider = "cloudflare";
credentialsFile = config.age.secrets."middleman/cloudflare-credentials.conf".path;
};
};
};
services = {
fstrim = lib.my.c.colony.fstrimConfig;
# Hacks for Jsch (Minecraft FastBack) to work
openssh = {
hostKeys = [
{
bits = 4096;
path = "/etc/ssh/ssh_host_rsa_key";
type = "rsa";
}
{
path = "/etc/ssh/ssh_host_ed25519_key";
type = "ed25519";
}
{
type = "ecdsa-sha2-nistp256";
path = "/etc/ssh/ssh_host_ecdsa_key";
}
];
settings = {
Macs = [
"hmac-sha2-512-etm@openssh.com"
"hmac-sha2-256-etm@openssh.com"
"umac-128-etm@openssh.com"
"hmac-sha2-256"
];
};
};
netdata.enable = true;
nginx = {
enable = true;
enableReload = true;
logError = "stderr info";
recommendedTlsSettings = true;
clientMaxBodySize = "0";
serverTokens = true;
sslDhparam = config.age.secrets."dhparams.pem".path;
# Based on recommended*Settings, but probably better to be explicit about these
appendHttpConfig = ''
${baseHttpConfig}
# caching
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=512m;
'';
virtualHosts =
let
hosts = {
"_" = {
default = true;
forceSSL = true;
onlySSL = false;
locations = {
"/".root = "${pkgs.nginx}/html";
};
};
"git.${pubDomain}" = {
locations."/".proxyPass = "http://localhost:3000";
};
};
defaultsFor = mapAttrs (n: _: {
onlySSL = mkDefault true;
useACMEHost = mkDefault pubDomain;
kTLS = mkDefault true;
http2 = mkDefault true;
});
in
mkMerge [
hosts
(defaultsFor hosts)
];
};
};
virtualisation = {
@@ -104,11 +207,24 @@ in
};
my = {
secrets.key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP+KINpHLMduBuW96JzfSRDLUzkI+XaCBghu5/wHiW5R";
secrets = {
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP+KINpHLMduBuW96JzfSRDLUzkI+XaCBghu5/wHiW5R";
files = {
"dhparams.pem" = {
owner = "acme";
group = "acme";
mode = "440";
};
"middleman/cloudflare-credentials.conf" = {
owner = "acme";
group = "acme";
};
};
};
server.enable = true;
firewall = {
tcp.allowed = [ 19999 ];
tcp.allowed = [ 19999 "http" "https" ];
extraRules = ''
table inet filter {
chain forward {

View File

@@ -26,18 +26,6 @@ in
systemd = {
services = {
# TODO: Figure out a way to do this properly... redirecting localhost is awkward...
local-http-forward = {
description = "Forward local HTTP connections";
serviceConfig.ExecStart = "${pkgs.socat}/bin/socat tcp-listen:80,fork tcp:${allAssignments.middleman.internal.ipv4.address}:80";
wantedBy = [ "multi-user.target" ];
};
local-https-forward = {
description = "Forward local HTTPS connections";
serviceConfig.ExecStart = "${pkgs.socat}/bin/socat tcp-listen:443,fork tcp:${allAssignments.middleman.internal.ipv4.address}:443";
wantedBy = [ "multi-user.target" ];
};
gitea = mkMerge [
(lib.my.systemdAwaitPostgres pkgs.postgresql "colony-psql")
{
@@ -141,21 +129,6 @@ in
"gitea/minio.txt" = ownedByGit;
};
};
firewall.extraRules = ''
table inet filter {
chain input {
ip saddr ${prefixes.all.v4} tcp dport 3000 accept
ip6 saddr ${prefixes.all.v6} tcp dport 3000 accept
}
}
table inet nat {
chain prerouting {
ip daddr ${assignments.internal.ipv4.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv4.address}
ip6 daddr ${assignments.internal.ipv6.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv6.address}
}
}
'';
};
};
}

View File

@@ -7,5 +7,6 @@
./jackflix
./object.nix
./toot.nix
./waffletail.nix
];
}

View File

@@ -2,6 +2,7 @@
let
inherit (lib.my) net;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.nginx) baseHttpConfig;
inherit (lib.my.c.colony) domain prefixes;
in
{
@@ -65,6 +66,7 @@ in
owner = "nginx";
group = "nginx";
};
"librespeed.toml" = { };
};
};
@@ -121,6 +123,19 @@ in
baseURL = "https://sso.${pubDomain}";
};
};
librespeed = {
frontend.servers = [
{
name = "Amsterdam, Netherlands";
server = "//librespeed.${domain}";
}
];
backend = {
enable = true;
extraSettingsFile = config.age.secrets."librespeed.toml".path;
};
};
};
users = {
@@ -131,6 +146,10 @@ in
systemd = {
network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
services = {
# HACK: nginx seems to get stuck not being able to DNS early...
nginx = lib.my.systemdAwaitPostgres pkgs.postgresql "colony-psql";
};
};
security = {
@@ -231,43 +250,9 @@ in
# Based on recommended*Settings, but probably better to be explicit about these
appendHttpConfig = ''
# NixOS provides a logrotate config that auto-compresses :)
log_format main
'$remote_addr - $remote_user [$time_local] $scheme "$host" "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main;
${baseHttpConfig}
# optimisation
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# gzip
gzip on;
gzip_proxied any;
gzip_comp_level 5;
gzip_types
application/atom+xml
application/javascript
application/json
application/xml
application/xml+rss
image/svg+xml
text/css
text/javascript
text/plain
text/xml;
gzip_vary on;
# proxying
proxy_buffering off;
proxy_redirect off;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_http_version 1.1;
${lib.my.c.nginx.proxyHeaders}
resolver_timeout 5s;
# caching
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=4g;

View File

@@ -347,9 +347,41 @@ in
};
useACMEHost = pubDomain;
};
"public.${pubDomain}" = {
serverAliases = [ "p.${pubDomain}" ];
locations."/" = {
root = "/mnt/media/public";
extraConfig = ''
fancyindex on;
fancyindex_show_dotfiles on;
'';
};
useACMEHost = pubDomain;
};
"git.${pubDomain}" = {
locations."/".proxyPass = "http://git-vm.${domain}:3000";
"mc-map.${pubDomain}" = {
locations."/".proxyPass = "http://simpcraft-oci.${domain}:8100";
useACMEHost = pubDomain;
};
"mc-rail.${pubDomain}" = {
locations."/".proxyPass = "http://simpcraft-staging-oci.${domain}:3876";
useACMEHost = pubDomain;
};
"librespeed.${domain}" = {
locations."/".proxyPass = "http://localhost:8989";
};
"speed.${pubDomain}" = {
locations."/".proxyPass = "http://localhost:8989";
useACMEHost = pubDomain;
};
"md.${pubDomain}" = {
locations."/" = {
proxyPass = "http://object-ctr.${domain}:3000";
proxyWebsockets = true;
extraConfig = proxyHeaders;
};
useACMEHost = pubDomain;
};
};
@@ -387,7 +419,22 @@ in
"s3.${pubDomain}" = {
serverAliases = [ "*.s3.${pubDomain}" ];
inherit extraConfig;
locations."/".proxyPass = s3Upstream;
locations = {
"/".proxyPass = s3Upstream;
"/gitea/packages/" = {
proxyPass = s3Upstream;
# HACK: Docker images need the MIME type to be correct for the manifest but Gitea
# doesn't tell S3... By hiding the header we can use add_header to set Content-Type
# (normally can't be set directly)
extraConfig = ''
proxy_hide_header Content-Type;
add_header Content-Type $upstream_http_content_type always;
if ($args ~ "response-content-disposition=.+filename%3D%22manifest\.json%22") {
add_header Content-Type "application/vnd.docker.distribution.manifest.v2+json";
}
'';
};
};
useACMEHost = pubDomain;
};

View File

@@ -48,11 +48,17 @@ in
group = config.my.user.config.group;
};
"object/atticd.env" = {};
"object/hedgedoc.env" = {};
};
};
firewall = {
tcp.allowed = [ 9000 9001 config.services.sharry.config.bind.port 8069 ];
tcp.allowed = [
9000 9001
config.services.sharry.config.bind.port
8069
config.services.hedgedoc.settings.port
];
};
user.homeConfig = {
@@ -194,6 +200,26 @@ in
};
};
};
hedgedoc = {
enable = true;
environmentFile = config.age.secrets."object/hedgedoc.env".path;
settings = {
domain = "md.${pubDomain}";
protocolUseSSL = true;
db = {
dialect = "postgresql";
username = "hedgedoc";
database = "hedgedoc";
host = "colony-psql";
};
host = "::";
allowAnonymous = false;
allowAnonymousEdits = true;
email = true;
allowEmailRegister = false;
};
};
};
}
(mkIf config.my.build.isDevVM {

View File

@@ -0,0 +1,100 @@
{ lib, ... }:
let
inherit (lib.my) net;
inherit (lib.my.c.colony) domain prefixes;
in
{
nixos.systems.waffletail = { config, ... }: {
system = "x86_64-linux";
nixpkgs = "mine";
rendered = config.configuration.config.my.asContainer;
assignments = {
internal = {
name = "waffletail-ctr";
inherit domain;
ipv4.address = net.cidr.host 9 prefixes.ctrs.v4;
ipv6 = {
iid = "::9";
address = net.cidr.host 9 prefixes.ctrs.v6;
};
};
tailscale = with lib.my.c.tailscale; {
ipv4 = {
address = net.cidr.host 5 prefix.v4;
mask = 32;
gateway = null;
};
ipv6 = {
address = net.cidr.host 5 prefix.v6;
mask = 128;
};
};
};
configuration = { lib, config, assignments, ... }:
let
inherit (lib) concatStringsSep mkMerge mkIf mkForce;
inherit (lib.my) networkdAssignment;
in
{
config = {
my = {
deploy.enable = false;
server.enable = true;
secrets = {
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICZc88lcSQ9zzQzDITdE/T5ty++TxFQUAED7p9YfFBiR";
files = {
"tailscale-auth.key" = {};
};
};
firewall = {
trustedInterfaces = [ "tailscale0" ];
extraRules = ''
table inet filter {
chain forward {
iifname host0 oifname tailscale0 ip saddr ${prefixes.all.v4} accept
iifname host0 oifname tailscale0 ip6 saddr ${prefixes.all.v6} accept
}
}
table inet nat {
chain postrouting {
iifname tailscale0 ip daddr != ${prefixes.all.v4} snat to ${assignments.internal.ipv4.address}
iifname tailscale0 ip6 daddr != ${prefixes.all.v6} snat ip6 to ${assignments.internal.ipv6.address}
}
}
'';
};
};
systemd = {
network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
};
services = {
tailscale =
let
advRoutes = concatStringsSep "," (with prefixes.all; [ v4 v6 ]);
in
{
enable = true;
authKeyFile = config.age.secrets."tailscale-auth.key".path;
port = 41641;
openFirewall = true;
interfaceName = "tailscale0";
extraUpFlags = [
"--operator=${config.my.user.config.name}"
"--login-server=https://ts.nul.ie"
"--netfilter-mode=off"
"--advertise-exit-node"
"--advertise-routes=${advRoutes}"
"--accept-routes=false"
];
};
};
};
};
};
}

View File

@@ -1,7 +1,7 @@
{ lib, ... }:
let
inherit (lib.my) net;
inherit (lib.my.c.colony) domain prefixes;
inherit (lib.my) net nft;
inherit (lib.my.c.colony) domain prefixes firewallForwards;
in
{
imports = [ ./containers ];
@@ -139,6 +139,16 @@ in
ipv6PrefixConfig.Prefix = prefixes.ctrs.v6;
}
];
routes = map (r: { routeConfig = r; }) [
{
Destination = lib.my.c.tailscale.prefix.v4;
Gateway = allAssignments.waffletail.internal.ipv4.address;
}
{
Destination = lib.my.c.tailscale.prefix.v6;
Gateway = allAssignments.waffletail.internal.ipv6.address;
}
];
}
];
};
@@ -151,6 +161,7 @@ in
firewall = {
tcp.allowed = [ 19999 ];
trustedInterfaces = [ "ctrs" ];
nat.forwardPorts."${allAssignments.estuary.internal.ipv4.address}" = firewallForwards allAssignments;
extraRules = ''
table inet filter {
chain forward {
@@ -158,6 +169,17 @@ in
iifname vms oifname ctrs accept
}
}
table inet nat {
# Hack to fix our NAT situation with internal routing
# We need to snat to our public IP, otherwise on the return path from e.g. middleman it will
# try to forward packet directly with its own IP, bypassing our carefully crafted DNAT...
chain ${nft.dnatChain allAssignments.estuary.internal.ipv4.address} {
ct mark set 0x1337
}
chain postrouting {
ct mark 0x1337 snat ip to ${assignments.internal.ipv4.address}
}
}
'';
};
@@ -184,6 +206,7 @@ in
};
};
toot = {};
waffletail = {};
};
in
mkMerge [

View File

@@ -50,6 +50,8 @@ in
};
}) {
valheim-oci = 2;
simpcraft-oci = 3;
simpcraft-staging-oci = 4;
};
configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
@@ -63,6 +65,7 @@ in
"${modulesPath}/profiles/qemu-guest.nix"
./valheim.nix
./minecraft
];
config = mkMerge [

View File

@@ -0,0 +1,121 @@
{ lib, pkgs, config, allAssignments, ... }:
let
inherit (lib) concatStringsSep;
inherit (lib.my) dockerNetAssignment;
# devplayer0
op = "6d7d971b-ce10-435b-85c5-c99c0d8d288c";
whitelist = concatStringsSep "," [
op
"dcd2ecb9-2b5e-49cb-9d4f-f5a76162df56" # Elderlypug
"fcb26db2-c3ce-41aa-b588-efec79d37a8a" # Jesthral_
"1d366062-12c0-4e29-aba7-6ab5d8c6bb05" # shr3kas0ras
"703b378a-09f9-4c1d-9876-1c9305728c49" # OROURKEIRE
"f105bbe6-eda6-4a13-a8cf-894e77cab77b" # Adzerq
"1fc94979-41fb-497a-81e9-34ae24ca537a" # johnnyscrims
"d53c91df-b6e6-4463-b106-e8427d7a8d01" # BossLonus
"f439f64d-91c9-4c74-9ce5-df4d24cd8e05" # hynge_
"d6ec4c91-5da2-44eb-b89d-71dc8fe017a0" # Eefah98
"096a7348-fabe-4b2d-93fc-fd1fd5608fb0" # ToTheMoonStar
];
fastback = {
gitConfig = pkgs.writeText "git-config" ''
[user]
email = "simpcraft@nul.ie"
name = "Simpcraft bot"
'';
knownHosts = pkgs.writeText "known_hosts" ''
git.nul.ie ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBD023ECzYmLeXIpcGVaciPjq6UN/Sjmsys5HP/Nei5GkrUZqPa3OJ2uSXKLUSKGYdeNhxaFTPJe8Yx3TsZxMme8=
'';
};
in
{
config = {
virtualisation.oci-containers.containers = {
simpcraft = {
image = "ghcr.io/itzg/minecraft-server:2023.12.2-java17-alpine";
environment = {
TYPE = "MODRINTH";
EULA = "true";
ENABLE_QUERY = "true";
MOTD = "§4§k----- §9S§ai§bm§cp§dc§er§fa§6f§5t §4§k-----";
ICON = "/ext/icon.png";
EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
WHITELIST = whitelist;
EXISTING_OPS_FILE = "SYNCHRONIZE";
OPS = op;
DIFFICULTY = "normal";
SPAWN_PROTECTION = "0";
VIEW_DISTANCE = "20";
MAX_MEMORY = "6G";
MODRINTH_MODPACK = "https://cdn.modrinth.com/data/CIYf3Hk8/versions/cdj2bSKg/Simpcraft-0.1.2.mrpack";
TZ = "Europe/Dublin";
};
volumes = [
"minecraft_data:/data"
"${./icon.png}:/ext/icon.png:ro"
];
extraOptions = [
''--network=colony:${dockerNetAssignment allAssignments "simpcraft-oci"}''
];
};
simpcraft-staging = {
image = "git.nul.ie/dev/craftblock:2024.1.0-java17-alpine";
environment = {
TYPE = "MODRINTH";
EULA = "true";
ENABLE_QUERY = "true";
ENABLE_RCON = "true";
MOTD = "§4§k----- §9S§ai§bm§cp§dc§er§fa§6f§5t [staging] §4§k-----";
ICON = "/ext/icon.png";
EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
WHITELIST = whitelist;
EXISTING_OPS_FILE = "SYNCHRONIZE";
OPS = op;
DIFFICULTY = "normal";
SPAWN_PROTECTION = "0";
VIEW_DISTANCE = "20";
MAX_MEMORY = "4G";
MODRINTH_MODPACK = "https://cdn.modrinth.com/data/CIYf3Hk8/versions/Ym3sIi6H/Simpcraft-0.2.0.mrpack";
TZ = "Europe/Dublin";
};
environmentFiles = [ config.age.secrets."whale2/simpcraft.env".path ];
volumes = [
"minecraft_staging_data:/data"
"${./icon.png}:/ext/icon.png:ro"
"${fastback.gitConfig}:/data/.config/git/config:ro"
"${fastback.knownHosts}:/data/.ssh/known_hosts:ro"
"${config.age.secrets."whale2/simpcraft-git.key".path}:/data/.ssh/id_rsa"
];
extraOptions = [
''--network=colony:${dockerNetAssignment allAssignments "simpcraft-staging-oci"}''
];
};
};
my = {
secrets.files = {
"whale2/simpcraft.env" = {};
"whale2/simpcraft-git.key" = {
owner = "1000";
};
};
};
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -2,7 +2,7 @@
let
inherit (lib.my) net mkVLAN;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.home) domain vlans prefixes vips;
inherit (lib.my.c.home) domain vlans prefixes vips hiMTU;
in
{
imports = [ ./vms ];
@@ -15,15 +15,21 @@ in
assignments = {
hi = {
inherit domain;
mtu = hiMTU;
ipv4 = {
address = net.cidr.host 22 prefixes.hi.v4;
mask = 22;
gateway = vips.hi.v4;
};
ipv6 = {
iid = "::2:1";
address = net.cidr.host (65536*2+1) prefixes.hi.v6;
};
};
core = {
inherit domain;
name = "palace-core";
mtu = 1500;
ipv4 = {
address = net.cidr.host 20 prefixes.core.v4;
gateway = null;
@@ -35,6 +41,7 @@ in
let
inherit (lib) mkForce mkMerge;
inherit (lib.my) networkdAssignment;
inherit (lib.my.c) networkd;
in
{
boot = {
@@ -103,7 +110,7 @@ in
hwloc
];
networking.domain = "h.${pubDomain}";
networking = { inherit domain; };
systemd = {
tmpfiles.rules = [
@@ -113,11 +120,14 @@ in
network = {
links = {
"10-et1g0" = {
matchConfig.MACAddress = "e0:d5:5e:68:0c:6e";
matchConfig = {
PermanentMACAddress = "e0:d5:5e:68:0c:6e";
Driver = "igb";
};
linkConfig.Name = "et1g0";
};
"10-lan-core" = {
matchConfig.MACAddress = "e0:d5:5e:68:0c:70";
matchConfig.PermanentMACAddress = "e0:d5:5e:68:0c:70";
linkConfig.Name = "lan-core";
};
"10-et100g" = {
@@ -127,13 +137,20 @@ in
};
linkConfig = {
Name = "et100g";
MTUBytes = "9000";
MTUBytes = toString hiMTU;
};
};
};
netdevs = mkMerge [
(mkVLAN "lan-hi" vlans.hi)
(mkVLAN "lan-lo-phy" vlans.lo)
{
"25-lan-lo".netdevConfig = {
Name = "lan-lo";
Kind = "bridge";
};
}
];
networks = {
@@ -141,6 +158,7 @@ in
(networkdAssignment "lan-core" assignments.core)
{
matchConfig.Name = "lan-core";
vlan = [ "lan-lo-phy" ];
networkConfig.IPv6AcceptRA = mkForce false;
}
];
@@ -148,7 +166,8 @@ in
"50-et100g" = {
matchConfig.Name = "et100g";
vlan = [ "lan-hi" ];
networkConfig.IPv6AcceptRA = false;
networkConfig = networkd.noL3;
linkConfig.RequiredForOnline = "no";
extraConfig = ''
# cellar
[SR-IOV]
@@ -156,19 +175,34 @@ in
VLANId=${toString vlans.hi}
LinkState=yes
MACAddress=52:54:00:cc:3e:70
# river
[SR-IOV]
VirtualFunction=1
LinkState=yes
MACAddress=52:54:00:8a:8a:f2
# sfh
[SR-IOV]
VirtualFunction=2
VLANId=${toString vlans.hi}
LinkState=yes
MACAddress=52:54:00:ac:15:a9
'';
};
"60-lan-hi" = mkMerge [
(networkdAssignment "lan-hi" assignments.hi)
{
matchConfig.Name = "lan-hi";
linkConfig.MTUBytes = "9000";
networkConfig.DNS = [
(allAssignments.stream.hi.ipv4.address)
# (allAssignments.river.hi.ipv4.address)
];
}
];
"60-lan-hi" = networkdAssignment "lan-hi" assignments.hi;
"50-lan-lo-phy" = {
matchConfig.Name = "lan-lo-phy";
networkConfig = {
Bridge = "lan-lo";
} // networkd.noL3;
};
"60-lan-lo" = {
matchConfig.Name = "lan-lo";
linkConfig.RequiredForOnline = "no";
networkConfig = networkd.noL3;
};
};
};
};

View File

@@ -2,7 +2,7 @@
let
inherit (lib.my) net;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.home) domain prefixes vips;
inherit (lib.my.c.home) domain prefixes vips hiMTU;
in
{
nixos.systems.cellar = {
@@ -12,11 +12,16 @@ in
assignments = {
hi = {
inherit domain;
mtu = hiMTU;
ipv4 = {
address = net.cidr.host 80 prefixes.hi.v4;
mask = 22;
gateway = vips.hi.v4;
};
ipv6 = {
iid = "::4:1";
address = net.cidr.host (65536*4+1) prefixes.hi.v6;
};
};
};
@@ -24,21 +29,17 @@ in
let
inherit (lib) mkMerge;
inherit (lib.my) networkdAssignment;
spdk = pkgs.spdk.overrideAttrs (o: {
configureFlags = o.configureFlags ++ [ "--with-rdma" ];
});
in
{
imports = [
"${modulesPath}/profiles/qemu-guest.nix"
./spdk.nix
];
config = mkMerge [
{
boot = {
kernelParams = [ "console=ttyS0,115200n8" ];
blacklistedKernelModules = [ "nvme" ];
kernelParams = [ "console=ttyS0,115200n8" "intel_iommu=on" ];
};
fileSystems = {
@@ -57,58 +58,27 @@ in
};
};
networking = { inherit domain; };
environment.systemPackages = with pkgs; [
pciutils
spdk
(pkgs.writeShellScriptBin "spdk-rpc" ''
exec ${pkgs.python3}/bin/python3 ${spdk.src}/scripts/rpc.py "$@"
'')
partclone
];
services = {
netdata.enable = true;
};
systemd.services = {
spdk-nvmf = {
description = "SPDK NVMe-oF target";
path = with pkgs; [
bash
python3
kmod
gawk
util-linux
];
after = [ "systemd-networkd-wait-online@lan-hi.service" ];
preStart = ''
${spdk.src}/scripts/setup.sh
'';
serviceConfig.ExecStart = "${spdk}/bin/spdk_tgt -c ${./spdk_nvmf.json}";
wantedBy = [ "multi-user.target" ];
};
};
systemd.network = {
links = {
"10-lan-hi" = {
matchConfig.PermanentMACAddress = "52:54:00:cc:3e:70";
linkConfig = {
Name = "lan-hi";
MTUBytes = "9000";
};
linkConfig.Name = "lan-hi";
};
};
networks = {
"80-vms" = mkMerge [
(networkdAssignment "lan-hi" assignments.hi)
{
networkConfig.DNS = [
(allAssignments.stream.hi.ipv4.address)
# (allAssignments.river.hi.ipv4.address)
];
}
];
"80-lan-hi" = networkdAssignment "lan-hi" assignments.hi;
};
};

View File

@@ -0,0 +1,137 @@
{ lib, pkgs, config, assignments, ... }:
let
inherit (lib) mapAttrsToList;
in
{
config = {
boot.blacklistedKernelModules = [ "nvme" ];
systemd.services = {
spdk-tgt.after = [ "systemd-networkd-wait-online@lan-hi.service" ];
};
my = {
spdk = {
enable = true;
extraArgs = "--mem-channels 2 --cpumask 0xffff";
debugCommands = ''
spdk-rpc bdev_nvme_attach_controller -t pcie -a 02:00.0 -b NVMe0
spdk-rpc bdev_nvme_attach_controller -t pcie -a 03:00.0 -b NVMe1
spdk-rpc bdev_nvme_attach_controller -t pcie -a 04:00.0 -b NVMe2
spdk-rpc bdev_raid_create -n NVMeRaid -z 64 -r 0 -b 'NVMe0n1 NVMe1n1 NVMe2n1'
spdk-rpc ublk_create_target
spdk-rpc ublk_start_disk NVMeRaid 1
'';
config.subsystems =
let
nvmeAttaches = mapAttrsToList (name: bdf: {
method = "bdev_nvme_attach_controller";
params = {
hostnqn =
"nqn.2014-08.org.nvmexpress:uuid:2b16606f-b82c-49f8-9b20-a589dac8b775";
trtype = "PCIe";
inherit name;
traddr = bdf;
};
}) {
"NVMe0" = "02:00.0";
"NVMe1" = "03:00.0";
"NVMe2" = "04:00.0";
};
nvmfListener = nqn: {
method = "nvmf_subsystem_add_listener";
params = {
inherit nqn;
listen_address = {
adrfam = "IPv4";
traddr = assignments.hi.ipv4.address;
trsvcid = "4420";
trtype = "RDMA";
};
secure_channel = false;
};
};
nvmfBdev = { nqn, hostnqn, bdev, serial }: [
{
method = "nvmf_create_subsystem";
params = {
inherit nqn;
serial_number = serial;
};
}
(nvmfListener nqn)
{
method = "nvmf_subsystem_add_host";
params = {
inherit nqn;
host = hostnqn;
};
}
{
method = "nvmf_subsystem_add_ns";
params = {
inherit nqn;
namespace = {
bdev_name = bdev;
nsid = 1;
};
};
}
];
in
{
scheduler = [
{
method = "framework_set_scheduler";
params.name = "dynamic";
}
];
bdev = [
{
method = "bdev_set_options";
params.bdev_auto_examine = false;
}
] ++ nvmeAttaches ++ [
{
method = "bdev_raid_create";
params = {
base_bdevs = [ "NVMe0n1" "NVMe1n1" "NVMe2n1" ];
name = "NVMeRaid";
raid_level = "raid0";
strip_size_kb = 64;
};
}
{
method = "bdev_examine";
params.name = "NVMeRaid";
}
{ method = "bdev_wait_for_examine"; }
];
nvmf = [
{
method = "nvmf_create_transport";
params.trtype = "RDMA";
}
(nvmfListener "nqn.2014-08.org.nvmexpress.discovery")
] ++ (nvmfBdev {
bdev = "NVMeRaidp1";
nqn = "nqn.2016-06.io.spdk:river";
hostnqn =
"nqn.2014-08.org.nvmexpress:uuid:12b52d80-ccb6-418d-9b2e-2be34bff3cd9";
serial = "SPDK00000000000001";
}) ++ (nvmfBdev {
bdev = "NVMeRaidp2";
nqn = "nqn.2016-06.io.spdk:castle";
hostnqn =
"nqn.2014-08.org.nvmexpress:uuid:2230b066-a674-4f45-a1dc-f7727b3a9e7b";
serial = "SPDK00000000000002";
});
};
};
};
};
}

View File

@@ -1,337 +0,0 @@
{
"subsystems": [
{
"subsystem": "scheduler",
"config": [
{
"method": "framework_set_scheduler",
"params": {
"name": "static"
}
}
]
},
{
"subsystem": "vmd",
"config": []
},
{
"subsystem": "sock",
"config": [
{
"method": "sock_impl_set_options",
"params": {
"impl_name": "posix",
"recv_buf_size": 2097152,
"send_buf_size": 2097152,
"enable_recv_pipe": true,
"enable_quickack": false,
"enable_placement_id": 0,
"enable_zerocopy_send_server": true,
"enable_zerocopy_send_client": false,
"zerocopy_threshold": 0,
"tls_version": 0,
"enable_ktls": false
}
},
{
"method": "sock_impl_set_options",
"params": {
"impl_name": "ssl",
"recv_buf_size": 4096,
"send_buf_size": 4096,
"enable_recv_pipe": true,
"enable_quickack": false,
"enable_placement_id": 0,
"enable_zerocopy_send_server": true,
"enable_zerocopy_send_client": false,
"zerocopy_threshold": 0,
"tls_version": 0,
"enable_ktls": false
}
}
]
},
{
"subsystem": "iobuf",
"config": [
{
"method": "iobuf_set_options",
"params": {
"small_pool_count": 8192,
"large_pool_count": 1024,
"small_bufsize": 8192,
"large_bufsize": 135168
}
}
]
},
{
"subsystem": "accel",
"config": [
{
"method": "accel_set_options",
"params": {
"small_cache_size": 128,
"large_cache_size": 16,
"task_count": 2048,
"sequence_count": 2048,
"buf_count": 2048
}
}
]
},
{
"subsystem": "bdev",
"config": [
{
"method": "bdev_set_options",
"params": {
"bdev_io_pool_size": 65535,
"bdev_io_cache_size": 256,
"bdev_auto_examine": true
}
},
{
"method": "bdev_nvme_set_options",
"params": {
"action_on_timeout": "none",
"timeout_us": 0,
"timeout_admin_us": 0,
"keep_alive_timeout_ms": 10000,
"transport_retry_count": 4,
"arbitration_burst": 0,
"low_priority_weight": 0,
"medium_priority_weight": 0,
"high_priority_weight": 0,
"nvme_adminq_poll_period_us": 10000,
"nvme_ioq_poll_period_us": 0,
"io_queue_requests": 512,
"delay_cmd_submit": true,
"bdev_retry_count": 3,
"transport_ack_timeout": 0,
"ctrlr_loss_timeout_sec": 0,
"reconnect_delay_sec": 0,
"fast_io_fail_timeout_sec": 0,
"generate_uuids": false,
"transport_tos": 0,
"io_path_stat": false,
"allow_accel_sequence": false
}
},
{
"method": "bdev_nvme_attach_controller",
"params": {
"name": "NVMe0",
"trtype": "PCIe",
"traddr": "02:00.0",
"prchk_reftag": false,
"prchk_guard": false,
"ctrlr_loss_timeout_sec": 0,
"reconnect_delay_sec": 0,
"fast_io_fail_timeout_sec": 0,
"hostnqn": "nqn.2014-08.org.nvmexpress:uuid:2b16606f-b82c-49f8-9b20-a589dac8b775",
"hdgst": false,
"ddgst": false
}
},
{
"method": "bdev_nvme_attach_controller",
"params": {
"name": "NVMe1",
"trtype": "PCIe",
"traddr": "03.00.0",
"prchk_reftag": false,
"prchk_guard": false,
"ctrlr_loss_timeout_sec": 0,
"reconnect_delay_sec": 0,
"fast_io_fail_timeout_sec": 0,
"hostnqn": "nqn.2014-08.org.nvmexpress:uuid:2b16606f-b82c-49f8-9b20-a589dac8b775",
"hdgst": false,
"ddgst": false
}
},
{
"method": "bdev_nvme_attach_controller",
"params": {
"name": "NVMe2",
"trtype": "PCIe",
"traddr": "04.00.0",
"prchk_reftag": false,
"prchk_guard": false,
"ctrlr_loss_timeout_sec": 0,
"reconnect_delay_sec": 0,
"fast_io_fail_timeout_sec": 0,
"hostnqn": "nqn.2014-08.org.nvmexpress:uuid:2b16606f-b82c-49f8-9b20-a589dac8b775",
"hdgst": false,
"ddgst": false
}
},
{
"method": "bdev_nvme_set_hotplug",
"params": {
"period_us": 100000,
"enable": false
}
},
{
"method": "bdev_raid_create",
"params": {
"name": "Raid0",
"strip_size_kb": 64,
"raid_level": "raid0",
"base_bdevs": [
"NVMe0n1",
"NVMe1n1",
"NVMe2n1"
]
}
},
{
"method": "bdev_wait_for_examine"
}
]
},
{
"subsystem": "nvmf",
"config": [
{
"method": "nvmf_set_config",
"params": {
"discovery_filter": "match_any",
"admin_cmd_passthru": {
"identify_ctrlr": false
}
}
},
{
"method": "nvmf_set_max_subsystems",
"params": {
"max_subsystems": 1024
}
},
{
"method": "nvmf_set_crdt",
"params": {
"crdt1": 0,
"crdt2": 0,
"crdt3": 0
}
},
{
"method": "nvmf_create_transport",
"params": {
"trtype": "RDMA",
"max_queue_depth": 128,
"max_io_qpairs_per_ctrlr": 127,
"in_capsule_data_size": 4096,
"max_io_size": 131072,
"io_unit_size": 8192,
"max_aq_depth": 128,
"num_shared_buffers": 4095,
"buf_cache_size": 4294967295,
"dif_insert_or_strip": false,
"zcopy": false,
"max_srq_depth": 4096,
"no_srq": false,
"acceptor_backlog": 100,
"no_wr_batching": false,
"abort_timeout_sec": 1
}
},
{
"method": "nvmf_create_subsystem",
"params": {
"nqn": "nqn.2016-06.io.spdk:cellar",
"allow_any_host": false,
"serial_number": "SPDK00000000000001",
"model_number": "SPDK bdev Controller",
"max_namespaces": 32,
"min_cntlid": 1,
"max_cntlid": 65519,
"ana_reporting": false
}
},
{
"method": "nvmf_subsystem_add_host",
"params": {
"nqn": "nqn.2016-06.io.spdk:cellar",
"host": "nqn.2014-08.org.nvmexpress:uuid:de712327-7fc8-6e54-15af-c87f546e170f"
}
},
{
"method": "nvmf_subsystem_add_ns",
"params": {
"nqn": "nqn.2016-06.io.spdk:cellar",
"namespace": {
"nsid": 1,
"bdev_name": "Raid0",
"nguid": "FA9D43CFD8D54885BB73F038BDC31B25",
"uuid": "fa9d43cf-d8d5-4885-bb73-f038bdc31b25"
}
}
},
{
"method": "nvmf_subsystem_add_listener",
"params": {
"nqn": "nqn.2016-06.io.spdk:cellar",
"listen_address": {
"trtype": "RDMA",
"adrfam": "IPv4",
"traddr": "192.168.68.80",
"trsvcid": "4420"
},
"secure_channel": false
}
}
]
},
{
"subsystem": "nbd",
"config": []
},
{
"subsystem": "vhost_blk",
"config": []
},
{
"subsystem": "scsi",
"config": null
},
{
"subsystem": "iscsi",
"config": [
{
"method": "iscsi_set_options",
"params": {
"node_base": "iqn.2016-06.io.spdk",
"max_sessions": 128,
"max_connections_per_session": 2,
"max_queue_depth": 64,
"default_time2wait": 2,
"default_time2retain": 20,
"first_burst_length": 8192,
"immediate_data": true,
"allow_duplicated_isid": false,
"error_recovery_level": 0,
"nop_timeout": 60,
"nop_in_interval": 30,
"disable_chap": false,
"require_chap": false,
"mutual_chap": false,
"chap_group": 0,
"max_large_datain_per_connection": 64,
"max_r2t_per_connection": 4,
"pdu_pool_size": 36864,
"immediate_data_pool_size": 16384,
"data_out_pool_size": 2048
}
}
]
},
{
"subsystem": "vhost_scsi",
"config": []
}
]
}

View File

@@ -1,12 +1,14 @@
{
imports = [
./cellar
./river.nix
];
nixos.systems.palace.configuration = { lib, pkgs, config, systems, ... }:
nixos.systems.palace.configuration = { lib, pkgs, config, systems, allAssignments, ... }:
let
inherit (lib) mkMerge;
inherit (lib.my) vm;
inherit (lib.my.c) networkd;
installerDisk = {
name = "installer";
@@ -23,7 +25,49 @@
};
in
{
systemd.services = {
systemd.network = {
netdevs = {
"25-vm-et1g0" = {
netdevConfig = {
Name = "vm-et1g0";
Kind = "macvtap";
};
# TODO: Upstream this missing section
extraConfig = ''
[MACVTAP]
Mode=passthru
'';
};
};
networks = {
"75-et1g0" = {
matchConfig.Name = "et1g0";
linkConfig.RequiredForOnline = "no";
networkConfig = {
MACVTAP = "vm-et1g0";
} // networkd.noL3;
};
"75-vm-et1g0" = {
matchConfig.Name = "vm-et1g0";
linkConfig.RequiredForOnline = "no";
networkConfig = networkd.noL3;
};
};
};
systemd.services =
let
awaitCellar = {
after = [ "vm@cellar.service" ];
bindsTo = [ "vm@cellar.service" ];
preStart = ''
until ${pkgs.netcat}/bin/nc -w1 -z ${allAssignments.cellar.hi.ipv4.address} 22; do
sleep 1
done
'';
};
in
{
"vm@cellar" = {
serviceConfig = {
CPUAffinity = "numa";
@@ -31,6 +75,19 @@
NUMAMask = "1";
};
};
"vm@river" =
let
vtapUnit = "sys-subsystem-net-devices-vm\\x2det1g0.device";
in
mkMerge [
awaitCellar
{
requires = [ vtapUnit ];
after = [ vtapUnit ];
}
];
"vm@sfh" = awaitCellar;
};
my = {
@@ -43,7 +100,8 @@
cpus = 8;
threads = 2;
};
memory = 32768;
memory = 16384;
cleanShutdown.timeout = 120;
drives = [
(mkMerge [ (vm.disk "cellar" "esp") { frontendOpts.bootindex = 0; } ])
(vm.disk "cellar" "nix")
@@ -67,6 +125,64 @@
hostBDF = "43:00.0";
};
};
qemuFlags = [
"machine kernel-irqchip=split"
"device intel-iommu,caching-mode=on,device-iotlb=on,intremap=on"
];
};
river = {
uuid = "12b52d80-ccb6-418d-9b2e-2be34bff3cd9";
cpu = "host,topoext";
smp = {
cpus = 3;
threads = 2;
};
memory = 4096;
cleanShutdown.timeout = 60;
networks = {
et1g0 = {
ifname = "vm-et1g0";
bridge = null;
tapFD = 100;
# Real hardware MAC
mac = "e0:d5:5e:68:0c:6e";
waitOnline = false;
};
};
drives = [
installerDisk
(mkMerge [ (vm.disk "river" "esp") { frontendOpts.bootindex = 0; } ])
];
hostDevices = {
et100g0vf1 = {
index = 0;
hostBDF = "44:00.2";
};
};
};
sfh = {
uuid = "82ec149d-577c-421a-93e2-a9307c756cd8";
cpu = "host,topoext";
smp = {
cpus = 8;
threads = 2;
};
memory = 32768;
cleanShutdown.timeout = 120;
networks.netboot = {
bridge = "lan-lo";
waitOnline = "carrier";
mac = "52:54:00:a5:7e:93";
extraOptions.bootindex = 1;
};
hostDevices = {
et100g0vf2 = {
index = 0;
hostBDF = "44:00.3";
};
};
};
};
};

View File

@@ -0,0 +1,142 @@
{
imports = [ (import ../../routing-common 0) ];
config.nixos.systems.river = {
system = "x86_64-linux";
nixpkgs = "mine";
home-manager = "mine";
configuration = { lib, modulesPath, pkgs, config, assignments, allAssignments, ... }:
let
inherit (lib.my) networkdAssignment mkVLAN;
inherit (lib.my.c) networkd;
inherit (lib.my.c.home) vlans;
lanLink = {
matchConfig = {
Driver = "mlx5_core";
PermanentMACAddress = "52:54:00:8a:8a:f2";
};
linkConfig = {
Name = "lan";
MTUBytes = toString lib.my.c.home.hiMTU;
};
};
in
{
imports = [
"${modulesPath}/profiles/qemu-guest.nix"
];
config = {
boot = {
kernelModules = [ "kvm-intel" ];
kernelParams = [ "console=ttyS0,115200n8" ];
initrd = {
availableKernelModules = [
"virtio_pci" "ahci" "sr_mod" "virtio_blk"
"ib_core" "ib_uverbs" "mlx5_core" "mlx5_ib" "8021q"
"rdma_cm" "iw_cm" "ib_cm" "nvme_core" "nvme_rdma"
];
kernelModules = [ "dm-snapshot" "nvme-fabrics" ];
systemd = {
extraBin = with pkgs; {
dmesg = "${util-linux}/bin/dmesg";
ip = "${iproute2}/bin/ip";
};
extraConfig = ''
DefaultTimeoutStartSec=50
DefaultDeviceTimeoutSec=50
'';
network = {
enable = true;
wait-online.enable = true;
links."10-lan" = lanLink;
netdevs = mkVLAN "lan-hi" vlans.hi;
networks = {
"20-lan" = {
matchConfig.Name = "lan";
vlan = [ "lan-hi" ];
linkConfig.RequiredForOnline = "no";
networkConfig = networkd.noL3;
};
"30-lan-hi" = networkdAssignment "lan-hi" assignments.hi;
};
};
};
};
};
hardware = {
enableRedistributableFirmware = true;
cpu = {
intel.updateMicrocode = true;
};
};
fileSystems = {
"/boot" = {
device = "/dev/disk/by-partuuid/3ec6c49e-b485-40cb-8eff-315581ac6fe9";
fsType = "vfat";
};
"/nix" = {
device = "/dev/main/nix";
fsType = "ext4";
};
"/persist" = {
device = "/dev/main/persist";
fsType = "ext4";
neededForBoot = true;
};
};
services = {
lvm = {
boot.thin.enable = true;
dmeventd.enable = true;
};
};
systemd.network = {
links = {
"10-wan" = {
matchConfig = {
# Matching against MAC address seems to break VLAN interfaces
# (since they share the same MAC address)
Driver = "virtio_net";
PermanentMACAddress = "e0:d5:5e:68:0c:6e";
};
linkConfig = {
Name = "wan";
RxBufferSize = 4096;
TxBufferSize = 4096;
};
};
"10-lan" = lanLink;
};
# So we don't drop the IP we use to connect to NVMe-oF!
networks."60-lan-hi".networkConfig.KeepConfiguration = "static";
};
my = {
secrets = {
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP9uFa4z9WPuXRFVA+PClQSitQCSPckhKTxo1Hq585Oa";
};
server.enable = true;
nvme = {
uuid = "12b52d80-ccb6-418d-9b2e-2be34bff3cd9";
boot = {
nqn = "nqn.2016-06.io.spdk:river";
address = "192.168.68.80";
};
};
deploy.node.hostname = "192.168.68.1";
};
};
};
};
}

View File

@@ -3,9 +3,10 @@ let
inherit (builtins) elemAt;
inherit (lib.my) net mkVLAN;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.home) domain vlans prefixes routers routersPubV4;
inherit (lib.my.c.home) domain vlans prefixes vips routers routersPubV4;
name = elemAt routers index;
otherIndex = 1 - index;
in
{
nixos.systems."${name}" = {
@@ -19,14 +20,16 @@ in
core = {
name = "${name}-core";
inherit domain;
mtu = 1500;
ipv4 = {
address = net.cidr.host (index + 1) prefixes.core.v4;
gateway = null;
};
};
hi = {
inherit domain;
name = "${name}-hi";
inherit domain;
mtu = 9000;
ipv4 = {
address = net.cidr.host (index + 1) prefixes.hi.v4;
mask = 22;
@@ -37,6 +40,7 @@ in
lo = {
name = "${name}-lo";
inherit domain;
mtu = 1500;
ipv4 = {
address = net.cidr.host (index + 1) prefixes.lo.v4;
mask = 21;
@@ -47,6 +51,7 @@ in
untrusted = {
name = "${name}-ut";
inherit domain;
mtu = 1500;
ipv4 = {
address = net.cidr.host (index + 1) prefixes.untrusted.v4;
mask = 24;
@@ -61,20 +66,50 @@ in
};
ipv6 = {
address = net.cidr.host ((1*65536*65536*65536) + index + 1) prefixes.as211024.v6;
gateway = net.cidr.host 1 prefixes.as211024.v6;
gateway = net.cidr.host ((2*65536*65536*65536) + 1) prefixes.as211024.v6;
};
};
};
extraAssignments = {
router-hi.hi = {
name = "router-hi";
inherit domain;
ipv4 = {
address = vips.hi.v4;
mask = 22;
};
ipv6.address = vips.hi.v6;
};
router-lo.lo = {
name = "router-lo";
inherit domain;
ipv4 = {
address = vips.lo.v4;
mask = 21;
};
ipv6.address = vips.lo.v6;
};
router-ut.untrusted = {
name = "router-ut";
inherit domain;
ipv4.address = vips.untrusted.v4;
ipv6.address = vips.untrusted.v6;
};
};
configuration = { lib, pkgs, config, assignments, allAssignments, ... }:
let
inherit (lib) mkIf mkMerge mkForce;
inherit (lib.my) networkdAssignment;
inherit (lib.my.c) networkd;
in
{
imports = map (m: import m index) [
./keepalived.nix
./dns.nix
./radvd.nix
./kea.nix
];
config = {
@@ -106,8 +141,8 @@ in
onState = [ "configured" ];
script = ''
#!${pkgs.runtimeShell}
if [ $IFACE = "wan-phy-ifb" ]; then
${pkgs.iproute2}/bin/tc filter add dev wan-phy parent ffff: matchall action mirred egress redirect dev $IFACE
if [ $IFACE = "wan-ifb" ]; then
${pkgs.iproute2}/bin/tc filter add dev wan parent ffff: matchall action mirred egress redirect dev $IFACE
fi
'';
};
@@ -138,14 +173,10 @@ in
netdevs = mkMerge [
{
"25-wan-phy-ifb".netdevConfig = {
Name = "wan-phy-ifb";
"25-wan-ifb".netdevConfig = {
Name = "wan-ifb";
Kind = "ifb";
};
"25-wan".netdevConfig = {
Name = "wan";
Kind = "bridge";
};
"30-lan-core".netdevConfig = {
Name = "lan-core";
Kind = "macvlan";
@@ -156,12 +187,11 @@ in
(mkVLAN "lan-hi" vlans.hi)
(mkVLAN "lan-lo" vlans.lo)
(mkVLAN "lan-untrusted" vlans.untrusted)
(mkVLAN "wan-tunnel" vlans.wan)
];
networks =
let
mkVLANConfig = name: mtu:
mkVLANConfig = name:
let
iface = "lan-${name}";
in
@@ -169,54 +199,18 @@ in
"60-${iface}" = mkMerge [
(networkdAssignment iface assignments."${name}")
{
linkConfig.MTUBytes = toString mtu;
dns = [ "127.0.0.1" "::1" ];
domains = [ config.networking.domain ];
networkConfig = {
IPv6AcceptRA = mkForce false;
# IPv6SendRA = true;
};
ipv6SendRAConfig = {
DNS = [
(net.cidr.host 1 prefixes."${name}".v4)
(net.cidr.host 2 prefixes."${name}".v4)
(net.cidr.host 1 prefixes."${name}".v6)
(net.cidr.host 2 prefixes."${name}".v6)
];
Domains = [ config.networking.domain ];
};
ipv6Prefixes = [
{
ipv6PrefixConfig.Prefix = prefixes."${name}".v6;
}
];
networkConfig.IPv6AcceptRA = mkForce false;
}
];
};
in
mkMerge [
{
"50-wan-phy" = {
matchConfig.Name = "wan-phy";
networkConfig.Bridge = "wan";
qdiscConfig = {
Parent = "ingress";
Handle = "0xffff";
};
extraConfig = ''
[CAKE]
Parent=root
Bandwidth=24M
RTTSec=1ms
'';
};
"50-wan-phy-ifb" = {
matchConfig.Name = "wan-phy-ifb";
networkConfig = {
LinkLocalAddressing = "no";
IPv6AcceptRA = false;
LLDP = false;
EmitLLDP = false;
};
"50-wan-ifb" = {
matchConfig.Name = "wan-ifb";
networkConfig = networkd.noL3;
extraConfig = ''
[CAKE]
Bandwidth=235M
@@ -228,12 +222,6 @@ in
CompensationMode=none
'';
};
"50-wan-tunnel" = {
matchConfig.Name = "wan-tunnel";
networkConfig.Bridge = "wan";
linkConfig.MTUBytes = "1500";
};
"50-wan" = mkMerge [
(networkdAssignment "wan" assignments.modem)
{
@@ -241,12 +229,17 @@ in
DHCP = "ipv4";
dns = [ "127.0.0.1" "::1" ];
dhcpV4Config.UseDNS = false;
routes = map (r: { routeConfig = r; }) [
# {
# Destination = prefixes.ctrs.v4;
# Gateway = allAssignments.shill.routing.ipv4.address;
# }
];
qdiscConfig = {
Parent = "ingress";
Handle = "0xffff";
};
extraConfig = ''
[CAKE]
Parent=root
Bandwidth=24M
RTTSec=1ms
'';
}
];
@@ -254,12 +247,7 @@ in
matchConfig.Name = "lan";
vlan = [ "lan-hi" "lan-lo" "lan-untrusted" "wan-tunnel" ];
macvlan = [ "lan-core" ];
networkConfig = {
LinkLocalAddressing = "no";
IPv6AcceptRA = false;
LLDP = false;
EmitLLDP = false;
};
networkConfig = networkd.noL3;
};
"60-lan-core" = mkMerge [
(networkdAssignment "lan-core" assignments.core)
@@ -274,13 +262,39 @@ in
{
matchConfig.Name = "as211024";
networkConfig.IPv6AcceptRA = mkForce false;
routes = map (r: { routeConfig = r; }) [
{
Destination = lib.my.c.colony.prefixes.all.v4;
Gateway = allAssignments.estuary.as211024.ipv4.address;
}
{
Destination = lib.my.c.tailscale.prefix.v4;
Gateway = allAssignments.britway.as211024.ipv4.address;
}
{
Destination = lib.my.c.tailscale.prefix.v6;
Gateway = allAssignments.britway.as211024.ipv6.address;
}
];
}
];
}
(mkVLANConfig "hi" 9000)
(mkVLANConfig "lo" 1500)
(mkVLANConfig "untrusted" 1500)
(mkVLANConfig "hi")
(mkVLANConfig "lo")
(mkVLANConfig "untrusted")
{
"60-lan-hi" = {
routes = map (r: { routeConfig = r; }) [
{
Destination = elemAt routersPubV4 otherIndex;
Gateway = net.cidr.host (otherIndex + 1) prefixes.hi.v4;
}
];
};
}
];
};
@@ -303,23 +317,30 @@ in
nat = {
enable = true;
externalInterface = "wan";
# externalIP = assignments.internal.ipv4.address;
forwardPorts = [
# {
# port = "http";
# dst = allAssignments.middleman.internal.ipv4.address;
# }
];
};
extraRules = ''
extraRules =
let
aa = allAssignments;
in
''
table inet filter {
chain input {
${lib.my.c.as211024.nftTrust}
iifname base meta l4proto { udp, tcp } th dport domain accept
iifname lan-core meta l4proto vrrp accept
}
chain routing-tcp {
# Safe enough to allow all SSH
tcp dport ssh accept
ip daddr {
${aa.castle.hi.ipv4.address},
${aa.cellar.hi.ipv4.address},
${aa.palace.hi.ipv4.address}
} tcp dport ssh accept
ip6 daddr {
${aa.castle.hi.ipv6.address},
${aa.cellar.hi.ipv6.address},
${aa.palace.hi.ipv6.address}
} tcp dport ssh accept
return
}
@@ -338,8 +359,10 @@ in
}
chain forward {
${lib.my.c.as211024.nftTrust}
iifname lan-untrusted jump filter-untrusted
iifname { wan, lan-untrusted } oifname { lan-hi, lan-lo } jump filter-routing
iifname { wan, as211024, lan-untrusted } oifname { lan-hi, lan-lo } jump filter-routing
oifname as211024 accept
}
chain output { }
}

View File

@@ -2,6 +2,7 @@ index: { lib, pkgs, config, assignments, allAssignments, ... }:
let
inherit (builtins) attrNames elemAt;
inherit (lib.my) net;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.home) prefixes vips routers;
name = elemAt routers index;
@@ -22,6 +23,7 @@ in
owner = "pdns-recursor";
group = "pdns-recursor";
};
"home/ddclient-cloudflare.key" = {};
};
pdns.recursor = {
@@ -42,18 +44,13 @@ in
"127.0.0.0/8" "::1/128"
prefixes.hi.v4 prefixes.hi.v6
prefixes.lo.v4 prefixes.lo.v6
];
] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
};
settings = {
query-local-address = [
# TODO: IPv6
"0.0.0.0"
"::"
# TODO: Dynamic IPv4 WAN address?
# assignments.internal.ipv4.address
# assignments.internal.ipv6.address
# assignments.hi.ipv6.address
];
forward-zones = map (z: "${z}=127.0.0.1:5353") authZones;
@@ -68,14 +65,42 @@ in
};
};
systemd.services = {
# Add AF_NETLINK to allow pulling IP from network interfaces
pdns.serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
systemd = {
services = {
# Add AF_NETLINK to allow pulling IP from network interfaces
pdns.serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
ddns-update = {
description = "DNS update script";
after = [ "network.target" ];
path = [
(pkgs.python3.withPackages (ps: [ ps.cloudflare ]))
pkgs.ldns
];
serviceConfig = {
Type = "oneshot";
ExecStart =
''${./dns_update.py} -k ${config.age.secrets."home/ddclient-cloudflare.key".path} '' +
''${pubDomain} ns${toString (index + 1)}.${config.networking.domain}'';
};
wantedBy = [ "multi-user.target" ];
};
};
timers = {
ddns-update = {
description = "Periodically update DNS";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "5min";
OnUnitInactiveSec = "5min";
};
};
};
};
# For rec_control
environment.systemPackages = with pkgs; [
# For rec_control
pdns-recursor
sqlite
];
my.pdns.auth = {
@@ -98,11 +123,15 @@ in
webserver = true;
webserver-address = "::";
webserver-allow-from = [ "127.0.0.1" "::1" ];
dnsupdate = true;
launch = [ "gsqlite3" ];
gsqlite3-database = "/var/lib/pdns/dynamic.sqlite3";
};
bind.zones =
let
names = [ "core" "hi" "lo" ];
names = [ "core" "hi" "lo" "untrusted" ];
i = toString (index + 1);
in
{
@@ -136,13 +165,27 @@ in
ns1 IN ALIAS ${elemAt routers 0}.${config.networking.domain}.
ns2 IN ALIAS ${elemAt routers 1}.${config.networking.domain}.
dyn IN NS ns1.dyn.h.nul.ie.
dyn IN NS ns2.dyn.h.nul.ie.
ns1.dyn.h.nul.ie. IN ALIAS ${elemAt routers 0}.${config.networking.domain}.
ns2.dyn.h.nul.ie. IN ALIAS ${elemAt routers 1}.${config.networking.domain}.
jim-core IN A ${net.cidr.host 10 prefixes.core.v4}
jim IN A ${net.cidr.host 10 prefixes.hi.v4}
jim IN AAAA ${net.cidr.host (65536+1) prefixes.hi.v6}
jim-lo IN A ${net.cidr.host 10 prefixes.lo.v4}
jim-lo IN AAAA ${net.cidr.host (65536+1) prefixes.lo.v6}
dave-core IN A ${net.cidr.host 11 prefixes.core.v4}
dave IN A ${net.cidr.host 11 prefixes.hi.v4}
dave IN AAAA ${net.cidr.host (65536+2) prefixes.hi.v6}
dave-lo IN A ${net.cidr.host 11 prefixes.lo.v4}
dave-lo IN AAAA ${net.cidr.host (65536+2) prefixes.lo.v6}
;ap0 IN A ${net.cidr.host 12 prefixes.hi.v4}
;ap0 IN AAAA ${net.cidr.host (65536+3) prefixes.hi.v6}
vibe IN A ${net.cidr.host 13 prefixes.hi.v4}
vibe IN AAAA ${net.cidr.host (65536+4) prefixes.hi.v6}
ups IN A ${net.cidr.host 20 prefixes.lo.v4}
palace-kvm IN A ${net.cidr.host 21 prefixes.lo.v4}

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python3
import argparse
import subprocess
import CloudFlare
def main():
parser = argparse.ArgumentParser(description='Cloudflare DNS update script')
parser.add_argument('-k', '--api-token-file', help='Cloudflare API token file')
parser.add_argument('zone', help='Cloudflare Zone')
parser.add_argument('record', help='Cloudflare record name')
args = parser.parse_args()
address = subprocess.check_output(
['drill', '-Q', '-p5353', '@127.0.0.1', args.record, 'A'],
encoding='utf8').strip()
cf_token = None
if args.api_token_file:
with open(args.api_token_file) as f:
cf_token = f.readline().strip()
cf = CloudFlare.CloudFlare(token=cf_token)
zones = cf.zones.get(params={'name': args.zone})
assert zones, f'Zone {args.zone} not found'
records = cf.zones.dns_records.get(zones[0]['id'], params={'name': args.record})
assert records, f'Record {args.record} not found in zone {args.zone}'
print(f'Updating {args.record} -> {address}')
cf.zones.dns_records.patch(
zones[0]['id'], records[0]['id'],
data={'type': 'A', 'name': args.record, 'content': address})
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,149 @@
index: { lib, pkgs, assignments, ... }:
let
inherit (lib) mkForce;
inherit (lib.my) net;
inherit (lib.my.c.home) domain prefixes vips hiMTU;
dns-servers = [
{
ip-address = net.cidr.host 1 prefixes.core.v4;
port = 5353;
}
{
ip-address = net.cidr.host 2 prefixes.core.v4;
port = 5353;
}
];
in
{
users = with lib.my.c.ids; {
users.kea= {
isSystemUser = true;
uid = uids.kea;
group = "kea";
};
groups.kea.gid = gids.kea;
};
systemd.services = {
kea-dhcp4-server.serviceConfig.DynamicUser = mkForce false;
kea-dhcp-ddns-server.serviceConfig.DynamicUser = mkForce false;
};
services = {
kea = {
dhcp4 = {
enable = true;
settings = {
interfaces-config = {
interfaces = [
"lan-hi/${assignments.hi.ipv4.address}"
"lan-lo/${assignments.lo.ipv4.address}"
"lan-untrusted/${assignments.untrusted.ipv4.address}"
];
};
lease-database = {
type = "memfile";
persist = true;
name = "/var/lib/kea/dhcp.leases";
};
option-data = [
{
name = "domain-name";
data = domain;
}
{
name = "domain-search";
data = "${domain}, dyn.${domain}, ${lib.my.c.colony.domain}, ${lib.my.c.britway.domain}";
always-send = true;
}
];
subnet4 = [
{
id = 1;
subnet = prefixes.hi.v4;
interface = "lan-hi";
option-data = [
{
name = "routers";
data = vips.hi.v4;
}
{
name = "domain-name-servers";
data = "${net.cidr.host 1 prefixes.hi.v4}, ${net.cidr.host 2 prefixes.hi.v4}";
}
{
name = "interface-mtu";
data = toString hiMTU;
}
];
pools = [
{
pool = if index == 0
then "192.168.68.120 - 192.168.69.255"
else "192.168.70.0 - 192.168.71.240";
}
];
reservations = [
{
# castle
hw-address = "24:8a:07:a8:fe:3a";
ip-address = net.cidr.host 40 prefixes.hi.v4;
}
];
}
{
id = 2;
subnet = prefixes.lo.v4;
interface = "lan-lo";
option-data = [
{
name = "routers";
data = vips.lo.v4;
}
{
name = "domain-name-servers";
data = "${net.cidr.host 1 prefixes.lo.v4}, ${net.cidr.host 2 prefixes.lo.v4}";
}
];
pools = [
{
pool = if index == 0
then "192.168.72.120 - 192.168.75.255"
else "192.168.76.0 - 192.168.79.240";
}
];
reservations = [
{
# castle
hw-address = "24:8a:07:a8:fe:3a";
ip-address = net.cidr.host 40 prefixes.lo.v4;
}
];
}
];
ddns-send-updates = true;
ddns-replace-client-name = "when-not-present";
ddns-qualifying-suffix = "dyn.${domain}";
ddns-generated-prefix = "ip";
ddns-update-on-renew = true;
dhcp-ddns.enable-updates = true;
};
};
dhcp-ddns = {
enable = true;
settings = {
forward-ddns.ddns-domains = [
{
name = "dyn.${domain}.";
inherit dns-servers;
}
];
};
};
};
};
}

View File

@@ -1,20 +1,30 @@
index: { lib, pkgs, ... }:
index: { lib, pkgs, config, ... }:
let
inherit (builtins) attrNames;
inherit (builtins) attrNames concatMap;
inherit (lib) optional;
inherit (lib.my) net;
inherit (lib.my.c.home) prefixes vips;
vlanIface = vlan: if vlan == "as211024" then vlan else "lan-${vlan}";
vrrpIPs = family: map (vlan: {
addr = "${vips.${vlan}.${family}}/${toString (net.cidr.length prefixes.${vlan}.${family})}";
vrrpIPs = family: concatMap (vlan: [
{
addr = "${vips.${vlan}.${family}}/${toString (net.cidr.length prefixes.${vlan}.${family})}";
dev = vlanIface vlan;
}
] ++ (optional (family == "v6") {
addr = "fe80::1/64";
dev = vlanIface vlan;
}) (attrNames vips);
})) (attrNames vips);
mkVRRP = family: routerId: {
state = if index == 0 then "MASTER" else "BACKUP";
interface = "lan-core";
priority = 255 - index;
virtualRouterId = routerId;
virtualIps = vrrpIPs family;
extraConfig = ''
notify_master "${config.systemd.package}/bin/systemctl start radvd.service"
notify_backup "${config.systemd.package}/bin/systemctl stop radvd.service"
'';
};
in
{

View File

@@ -0,0 +1,28 @@
index: { lib, pkgs, ... }:
let
inherit (lib) mkForce concatMapStringsSep;
inherit (lib.my) net;
inherit (lib.my.c.home) domain prefixes;
mkInterface = name: ''
interface lan-${name} {
AdvSendAdvert on;
AdvRASrcAddress { fe80::1; };
AdvLinkMTU ${toString prefixes."${name}".mtu};
prefix ${prefixes."${name}".v6} {};
RDNSS ${net.cidr.host 1 prefixes."${name}".v6} ${net.cidr.host 2 prefixes."${name}".v6} {};
DNSSL ${domain} dyn.${domain} ${lib.my.c.colony.domain} ${lib.my.c.britway.domain} {};
};
'';
in
{
# To be started by keepalived
systemd.services.radvd.wantedBy = mkForce [ ];
services = {
radvd = {
enable = true;
config = concatMapStringsSep "\n" mkInterface [ "hi" "lo" "untrusted" ];
};
};
}

View File

@@ -57,7 +57,7 @@
};
};
links = {
"10-wan-phy" = {
"10-wan" = {
matchConfig = {
# Matching against MAC address seems to break VLAN interfaces
# (since they share the same MAC address)
@@ -65,7 +65,7 @@
PermanentMACAddress = "00:f0:cb:ee:ca:dd";
};
linkConfig = {
Name = "wan-phy";
Name = "wan";
RxBufferSize = 4096;
TxBufferSize = 4096;
};

View File

@@ -92,7 +92,7 @@ in
nextcloud = {
enable = true;
package = pkgs.nextcloud27;
package = pkgs.nextcloud28;
datadir = "/mnt/storage/nextcloud";
hostName = "cloud.${domain}";
https = true;

View File

@@ -2,7 +2,7 @@
let
inherit (builtins) mapAttrs;
inherit (lib) mkMerge mkIf mkDefault;
inherit (lib.my.c.nginx) proxyHeaders;
inherit (lib.my.c.nginx) baseHttpConfig proxyHeaders;
inherit (lib.my.c.kelder) domain;
in
{
@@ -39,43 +39,7 @@ in
# Based on recommended*Settings, but probably better to be explicit about these
appendHttpConfig = ''
# NixOS provides a logrotate config that auto-compresses :)
log_format main
'$remote_addr - $remote_user [$time_local] $scheme "$host" "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main;
# optimisation
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# gzip
gzip on;
gzip_proxied any;
gzip_comp_level 5;
gzip_types
application/atom+xml
application/javascript
application/json
application/xml
application/xml+rss
image/svg+xml
text/css
text/javascript
text/plain
text/xml;
gzip_vary on;
# proxying
proxy_buffering off;
proxy_redirect off;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_http_version 1.1;
${proxyHeaders}
${baseHttpConfig}
# caching
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=4g;

View File

@@ -135,12 +135,14 @@ in
samba-wsdd.enable = true;
minecraft-server = {
enable = true;
package = pkgs.minecraftServers.vanilla-1-19;
enable = false;
package = pkgs.minecraftServers.vanilla-1-20;
declarative = true;
eula = true;
whitelist = {
devplayer0 = "6d7d971b-ce10-435b-85c5-c99c0d8d288c";
Elderlypug = "dcd2ecb9-2b5e-49cb-9d4f-f5a76162df56";
shr3kas0ras = "1d366062-12c0-4e29-aba7-6ab5d8c6bb05";
};
serverProperties = {
motd = "Simpcraft";

View File

@@ -107,10 +107,19 @@
fprintd.enable = true;
blueman.enable = true;
tailscale = {
enable = true;
openFirewall = true;
};
};
programs = {
steam.enable = true;
wireshark = {
enable = true;
package = pkgs.wireshark-qt;
};
};
networking = {
@@ -166,6 +175,14 @@
packages = with pkgs; [ ];
};
programs = {
fish = {
shellAbbrs = {
tsup = "doas tailscale up --login-server=https://ts.nul.ie --accept-routes";
};
};
};
services = {
blueman-applet.enable = true;
};

View File

@@ -1,4 +1,4 @@
{ lib, pkgsFlakes, hmFlakes, inputs, pkgs', config, ... }:
{ self, lib, pkgsFlakes, hmFlakes, inputs, pkgs', config, ... }:
let
inherit (builtins) attrValues mapAttrs;
inherit (lib)
@@ -25,10 +25,14 @@ let
modules' = [ hmFlakes.${config'.home-manager}.nixosModule ] ++ (attrValues cfg.modules);
in
pkgsFlake.lib.nixosSystem {
# Import eval-config ourselves since the flake now force-sets lib
import "${pkgsFlake}/nixos/lib/eval-config.nix" {
# Gotta override lib here unforunately, eval-config.nix likes to import its own (unextended) lib. We explicitly
# don't pass pkgs so that it'll be imported with modularly applied config and overlays.
lib = pkgs.lib;
lib = pkgs.lib.extend (lib.my.versionOverlay { inherit self pkgsFlake; });
# Set to null since we pass modularly
system = null;
# Put the inputs in specialArgs to avoid infinite recursion when modules try to do imports
specialArgs = { inherit inputs pkgsFlakes pkgsFlake allAssignments; inherit (cfg) systems; };
@@ -51,7 +55,7 @@ let
pkgs' = allPkgs;
};
system.name = name;
system = { inherit name; };
networking = {
domain = let d = config'.assignments.internal.domain or null; in mkIf (d != null) (mkDefault' d);
hostName = mkDefault (config'.assignments.internal.name or name);
@@ -86,6 +90,8 @@ let
pkgsPath = toString pkgsFlakes.${config'.hmNixpkgs};
pkgs' = allPkgs;
};
home.enableNixpkgsReleaseCheck = false;
}
(homeStateVersion config'.home-manager)
];
@@ -100,6 +106,7 @@ let
altNames = mkOpt' (listOf str) [ ] "Extra names to assign.";
visible = mkBoolOpt' true "Whether or not this assignment should be visible.";
domain = mkOpt' (nullOr str) null "Domain for this assignment.";
mtu = mkOpt' (nullOr ints.unsigned) null "Interface MTU.";
ipv4 = {
address = mkOpt' net.types.ipv4 null "IPv4 address.";
mask = mkOpt' ints.u8 24 "Network mask.";

View File

@@ -32,7 +32,8 @@
};
isoImage = {
isoBaseName = "nixos-installer-devplayer0";
isoBaseName = "jackos-installer";
volumeID = "jackos-${config.system.nixos.release}-${pkgs.stdenv.hostPlatform.uname.processor}";
edition = "devplayer0";
appendToMenuLabel = " /dev/player0 Installer";
};

View File

@@ -17,5 +17,8 @@
gui = ./gui.nix;
l2mesh = ./l2mesh.nix;
borgthin = ./borgthin.nix;
nvme = ./nvme;
spdk = ./spdk.nix;
librespeed = ./librespeed;
};
}

View File

@@ -43,6 +43,16 @@ let
modules = flatten [
"${modulesPath}/installer/netboot/netboot.nix"
allHardware
({ pkgs, config, ... }: {
system.build.netbootArchive = pkgs.runCommand "netboot-${config.system.name}-archive.tar" { } ''
${pkgs.gnutar}/bin/tar -rvC "${config.system.build.kernel}" \
-f "$out" "${config.system.boot.loader.kernelFile}"
${pkgs.gnutar}/bin/tar -rvC "${config.system.build.netbootRamdisk}" \
-f "$out" initrd
${pkgs.gnutar}/bin/tar -rvC "${config.system.build.netbootIpxeScript}" \
-f "$out" netboot.ipxe
'';
})
];
};
@@ -82,6 +92,7 @@ in
};
isoImage = {
isoBaseName = dummyOption;
volumeID = dummyOption;
edition = dummyOption;
appendToMenuLabel = dummyOption;
};
@@ -99,6 +110,7 @@ in
iso = config.my.asISO.config.system.build.isoImage;
container = config.my.asContainer.config.system.build.toplevel;
kexecTree = config.my.asKexecTree.config.system.build.kexecTree;
netbootArchive = config.my.asKexecTree.config.system.build.netbootArchive;
};
};
};

View File

@@ -1,7 +1,7 @@
{ lib, pkgs, pkgs', inputs, config, ... }:
let
inherit (lib) mkIf mkDefault mkMerge;
inherit (lib.my) mkBoolOpt' dummyOption;
inherit (lib.my) mkDefault';
in
{
options = with lib.types; {
@@ -121,11 +121,15 @@ in
services.lvm.enable = mkDefault true;
};
};
system = {
nixos = {
distroName = mkDefault' "JackOS";
};
};
environment.systemPackages = with pkgs; mkMerge [
[
bash-completion
vim
git
unzip
]
@@ -138,6 +142,7 @@ in
fish.enable = mkDefault true;
# TODO: This is expecting to look up the channel for the database...
command-not-found.enable = mkDefault false;
vim.defaultEditor = true;
};
services = {
@@ -151,6 +156,7 @@ in
font-name=SauceCodePro Nerd Font Mono
'';
};
getty.greetingLine = mkDefault' ''<<< Welcome to ${config.system.nixos.distroName} ${config.system.nixos.label} (\m) - \l >>>'';
openssh = {
enable = mkDefault true;

View File

@@ -209,12 +209,16 @@ in
mkdir -p -m 0755 "$root"/sbin "$root"/etc
touch "$root"/etc/os-release
if [ -e "${containerSystem}"/prepare-root ]; then
initSource="${containerSystem}"/prepare-root
else
initSource="${containerSystem}"/init
fi
ln -sf "$initSource" "$root"/sbin/init
${if system == sysProfile then ''
if [ -e "${sysProfile}"/prepare-root ]; then
initSource="${containerSystem}"/prepare-root
else
initSource="${containerSystem}"/init
fi
ln -sf "$initSource" "$root"/sbin/init
'' else ''
ln -sf "${containerSystem}/prepare-root" "$root"/sbin/init
''}
'';
postStop =
''

View File

@@ -15,16 +15,20 @@ let
# Based on https://github.com/serokell/deploy-rs/blob/master/flake.nix
nixosActivate = cfg': base: (pkgs.deploy-rs.lib.activate.custom // {
dryActivate = "$PROFILE/bin/switch-to-configuration dry-activate";
boot = "$PROFILE/bin/switch-to-configuration boot";
boot = ''
$PROFILE/bin/switch-to-configuration boot
${keepGensSnippet "$PROFILE" cfg'.keepGenerations}
'';
}) base.config.system.build.toplevel ''
# work around https://github.com/NixOS/nixpkgs/issues/73404
cd /tmp
"$PROFILE"/bin/switch-to-configuration ${cfg'.mode}
"$PROFILE"/bin/switch-to-configuration switch
# https://github.com/serokell/deploy-rs/issues/31
${with base.config.boot.loader;
optionalString ((cfg'.mode == "switch" || cfg'.mode == "boot") && systemd-boot.enable)
optionalString systemd-boot.enable
"sed -i '/^default /d' ${efi.efiSysMountPoint}/loader/loader.conf"}
${keepGensSnippet "$PROFILE" cfg'.keepGenerations}
@@ -59,7 +63,11 @@ let
{
name = "container-${n}";
value = {
path = pkgs.deploy-rs.lib.activate.custom ctrConfig.my.buildAs.container ''
path = (pkgs.deploy-rs.lib.activate.custom // {
boot = ''
echo "Next systemd-nspawn@${n}.service restart / reload will load config"
'';
}) ctrConfig.my.buildAs.container ''
source ${systemdUtil}/bin/systemd-util.sh
${if c.hotReload then ''
if (! systemctl show -p ActiveState systemd-nspawn@${n} | grep -q "ActiveState=active") || \

View File

@@ -1,6 +1,9 @@
{ lib, options, config, ... }:
let
inherit (lib) optionalString concatStringsSep concatMapStringsSep optionalAttrs mkIf mkDefault mkMerge mkOverride;
inherit (builtins) typeOf attrNames;
inherit (lib)
optionalString concatStringsSep concatMapStringsSep mapAttrsToList optionalAttrs mkIf
mkDefault mkMerge mkOverride;
inherit (lib.my) isIPv6 mkOpt' mkBoolOpt';
allowICMP = ''
@@ -63,8 +66,8 @@ in
nat = with options.networking.nat; {
enable = mkBoolOpt' true "Whether to enable IP forwarding and NAT.";
inherit externalInterface externalIP;
forwardPorts = mkOpt' (listOf (submodule forwardOpts)) [ ] "List of port forwards.";
inherit externalInterface;
forwardPorts = mkOpt' (either (listOf (submodule forwardOpts)) (attrsOf (listOf (submodule forwardOpts)))) [ ] "IPv4 port forwards";
};
};
@@ -137,6 +140,9 @@ in
chain postrouting {
type nat hook postrouting priority srcnat;
}
chain input {
type nat hook input priority srcnat;
}
}
${cfg.extraRules}
@@ -144,11 +150,16 @@ in
};
};
}
(mkIf cfg.nat.enable {
(mkIf cfg.nat.enable (
let
iifForward = typeOf cfg.nat.forwardPorts == "list" && cfg.nat.forwardPorts != [ ];
dipForward = typeOf cfg.nat.forwardPorts == "set" && cfg.nat.forwardPorts != { };
in
{
assertions = [
{
assertion = with cfg.nat; (forwardPorts != [ ]) -> (externalInterface != null);
message = "my.firewall.nat.forwardPorts requires my.firewall.nat.external{Interface,IP}";
assertion = with cfg.nat; iifForward -> (externalInterface != null);
message = "my.firewall.nat.forwardPorts as list requires my.firewall.nat.externalInterface";
}
];
@@ -171,43 +182,75 @@ in
my.firewall.extraRules =
let
inherit (lib.my.nft) natFilterChain dnatChain;
ipK = ip: "ip${optionalString (isIPv6 ip) "6"}";
makeFilter = f:
let
v6 = isIPv6 f.dst;
in
"ip${optionalString v6 "6"} daddr ${f.dst} ${f.proto} dport ${toString f.dstPort} accept";
"${ipK f.dst} daddr ${f.dst} ${f.proto} dport ${toString f.dstPort} accept";
makeForward = f:
let
v6 = isIPv6 f.dst;
in
"${f.proto} dport ${toString f.port} dnat ip${optionalString v6 "6"} to ${f.dst}:${toString f.dstPort}";
"${f.proto} dport ${toString f.port} dnat ${ipK f.dst} to ${f.dst}:${toString f.dstPort}";
dnatJumps = ''
${optionalString
iifForward
"iifname ${cfg.nat.externalInterface} jump iif-port-forward"}
${optionalString
dipForward
(concatMapStringsSep "\n " (ip: "${ipK ip} daddr ${ip} jump ${dnatChain ip}") (attrNames cfg.nat.forwardPorts))}
'';
in
''
table inet filter {
chain filter-port-forwards {
${concatMapStringsSep "\n " makeFilter cfg.nat.forwardPorts}
return
}
${optionalString iifForward ''
chain filter-iif-port-forwards {
${concatMapStringsSep "\n " makeFilter cfg.nat.forwardPorts}
return
}
''}
${optionalString
dipForward
(concatStringsSep "\n" (mapAttrsToList (ip: fs: ''
chain ${natFilterChain ip} {
${concatMapStringsSep "\n " makeFilter fs}
return
}
'') cfg.nat.forwardPorts))}
chain forward {
${optionalString
(cfg.nat.externalInterface != null)
"iifname ${cfg.nat.externalInterface} jump filter-port-forwards"}
iifForward
"iifname ${cfg.nat.externalInterface} jump filter-iif-port-forwards"}
${optionalString
dipForward
(concatMapStringsSep "\n " (ip: "jump ${natFilterChain ip}") (attrNames cfg.nat.forwardPorts))}
}
}
table inet nat {
chain port-forward {
${concatMapStringsSep "\n " makeForward cfg.nat.forwardPorts}
return
}
${optionalString iifForward ''
chain iif-port-forward {
${concatMapStringsSep "\n " makeForward cfg.nat.forwardPorts}
return
}
''}
${optionalString
dipForward
(concatStringsSep "\n" (mapAttrsToList (ip: fs: ''
chain ${dnatChain ip} {
${concatMapStringsSep "\n " makeForward fs}
return
}
'') cfg.nat.forwardPorts))}
chain prerouting {
${optionalString
(cfg.nat.externalInterface != null)
"${if (cfg.nat.externalIP != null) then "ip daddr ${cfg.nat.externalIP}" else "iifname ${cfg.nat.externalInterface}"} jump port-forward"}
${dnatJumps}
}
chain output {
${dnatJumps}
}
}
'';
})
}))
]);
meta.buildDocsInSandbox = false;

View File

@@ -0,0 +1,76 @@
{ lib, pkgs, config, ... }:
let
inherit (builtins) toJSON;
inherit (lib) mkOption mkMerge mkIf mkDefault;
inherit (lib.my) mkOpt' mkBoolOpt';
cfg = config.my.librespeed;
serversConf = map (s: s // {
dlURL = "backend/garbage";
ulURL = "backend/empty";
pingURL = "backend/empty";
getIpURL = "backend/getIP";
}) cfg.frontend.servers;
frontendTree = pkgs.runCommand "librespeed-frontend" {
speedtestServers = toJSON serversConf;
} ''
mkdir "$out"
cp "${pkgs.librespeed-go}"/assets/* "$out"/
substitute ${./index.html} "$out"/index.html --subst-var speedtestServers
'';
backendConf = pkgs.writers.writeTOML "librespeed.toml" cfg.backend.settings;
generateBackendSettings = base: dst: if (cfg.backend.extraSettingsFile != null) then ''
oldUmask="$(umask)"
umask 006
cat "${base}" "${cfg.backend.extraSettingsFile}" > "${dst}"
umask "$oldUmask"
'' else ''
cp "${base}" "${dst}"
'';
in
{
options.my.librespeed = with lib.types; {
frontend = {
servers = mkOpt' (listOf (attrsOf unspecified)) { } "Server configs.";
webroot = mkOption {
description = "Frontend webroot.";
type = package;
readOnly = true;
};
};
backend = {
enable = mkBoolOpt' false "Whether to enable librespeed backend.";
settings = mkOpt' (attrsOf unspecified) { } "Backend settings.";
extraSettingsFile = mkOpt' (nullOr str) null "Extra settings file.";
};
};
config = mkMerge [
(mkIf (cfg.frontend.servers != { }) {
my.librespeed.frontend.webroot = frontendTree;
})
(mkIf cfg.backend.enable {
my.librespeed.backend.settings = {
assets_path = frontendTree;
database_type = mkDefault "bolt";
database_file = mkDefault "/var/lib/librespeed-go/speedtest.db";
};
systemd.services.librespeed = {
description = "LibreSpeed Go backend";
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
preStart = generateBackendSettings backendConf "/run/librespeed-go/settings.toml";
serviceConfig = {
ExecStart = "${pkgs.librespeed-go}/bin/speedtest -c /run/librespeed-go/settings.toml";
RuntimeDirectory = "librespeed-go";
StateDirectory = "librespeed-go";
};
wantedBy = [ "multi-user.target" ];
};
})
];
}

View File

@@ -0,0 +1,491 @@
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<meta charset="UTF-8" />
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
function I(i){return document.getElementById(i);}
//LIST OF TEST SERVERS. See documentation for details if needed
var SPEEDTEST_SERVERS=@speedtestServers@;
// var SPEEDTEST_SERVERS=[
// { //this server doesn't actually exist, remove it
// name:"Example Server 1", //user friendly name for the server
// server:"//test1.mydomain.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
// dlURL:"backend/garbage.php", //path to download test on this server (garbage.php or replacement)
// ulURL:"backend/empty.php", //path to upload test on this server (empty.php or replacement)
// pingURL:"backend/empty.php", //path to ping/jitter test on this server (empty.php or replacement)
// getIpURL:"backend/getIP.php" //path to getIP on this server (getIP.php or replacement)
// },
// { //this server doesn't actually exist, remove it
// name:"Example Server 2", //user friendly name for the server
// server:"//test2.example.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
// dlURL:"garbage.php", //path to download test on this server (garbage.php or replacement)
// ulURL:"empty.php", //path to upload test on this server (empty.php or replacement)
// pingURL:"empty.php", //path to ping/jitter test on this server (empty.php or replacement)
// getIpURL:"getIP.php" //path to getIP on this server (getIP.php or replacement)
// }
// //add other servers here, comma separated
// ];
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speed test object
s.setParameter("telemetry_level","basic"); //enable telemetry
//SERVER AUTO SELECTION
function initServers(){
var noServersAvailable=function(){
I("message").innerHTML="No servers available";
}
var runServerSelect=function(){
s.selectServer(function(server){
if(server!=null){ //at least 1 server is available
I("loading").className="hidden"; //hide loading message
//populate server list for manual selection
for(var i=0;i<SPEEDTEST_SERVERS.length;i++){
if(SPEEDTEST_SERVERS[i].pingT==-1) continue;
var option=document.createElement("option");
option.value=i;
option.textContent=SPEEDTEST_SERVERS[i].name;
if(SPEEDTEST_SERVERS[i]===server) option.selected=true;
I("server").appendChild(option);
}
//show test UI
I("testWrapper").className="visible";
initUI();
}else{ //no servers are available, the test cannot proceed
noServersAvailable();
}
});
}
if(typeof SPEEDTEST_SERVERS === "string"){
//need to fetch list of servers from specified URL
s.loadServerList(SPEEDTEST_SERVERS,function(servers){
if(servers==null){ //failed to load server list
noServersAvailable();
}else{ //server list loaded
SPEEDTEST_SERVERS=servers;
runServerSelect();
}
});
}else{
//hardcoded server list
s.addTestPoints(SPEEDTEST_SERVERS);
runServerSelect();
}
}
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
var dlColor="#6060AA",
ulColor="#616161";
var progColor=meterBk;
//CODE FOR GAUGES
function drawMeter(c,amount,bk,fg,progress,prog){
var ctx=c.getContext("2d");
var dp=window.devicePixelRatio||1;
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
var sizScale=ch*0.0055;
if(c.width==cw&&c.height==ch){
ctx.clearRect(0,0,cw,ch);
}else{
c.width=cw;
c.height=ch;
}
ctx.beginPath();
ctx.strokeStyle=bk;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle=fg;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
ctx.stroke();
if(typeof progress !== "undefined"){
ctx.fillStyle=prog;
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
}
}
function mbpsToAmount(s){
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
}
function format(d){
d=Number(d);
if(d<10) return d.toFixed(2);
if(d<100) return d.toFixed(1);
return d.toFixed(0);
}
//UI CODE
var uiData=null;
function startStop(){
if(s.getState()==3){
//speed test is running, abort
s.abort();
data=null;
I("startStopBtn").className="";
I("server").disabled=false;
initUI();
}else{
//test is not running, begin
I("startStopBtn").className="running";
I("shareArea").style.display="none";
I("server").disabled=true;
s.onupdate=function(data){
uiData=data;
};
s.onend=function(aborted){
I("startStopBtn").className="";
I("server").disabled=false;
updateUI(true);
if(!aborted){
//if testId is present, show sharing panel, otherwise do nothing
try{
var testId=uiData.testId;
if(testId!=null){
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
I("resultsImg").src=shareURL;
I("resultsURL").value=shareURL;
I("testId").innerHTML=testId;
I("shareArea").style.display="";
}
}catch(e){}
}
};
s.start();
}
}
//this function reads the data sent back by the test and updates the UI
function updateUI(forced){
if(!forced&&s.getState()!=3) return;
if(uiData==null) return;
var status=uiData.testState;
I("ip").textContent=uiData.clientIp;
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
I("pingText").textContent=format(uiData.pingStatus);
I("jitText").textContent=format(uiData.jitterStatus);
}
function oscillate(){
return 1+0.02*Math.sin(Date.now()/100);
}
//update the UI every frame
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
function frame(){
requestAnimationFrame(frame);
updateUI();
}
frame(); //start frame loop
//function to (re)initialize UI
function initUI(){
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
I("dlText").textContent="";
I("ulText").textContent="";
I("pingText").textContent="";
I("jitText").textContent="";
I("ip").textContent="";
}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#loading{
background-color:#FFFFFF;
color:#404040;
text-align:center;
}
span.loadCircle{
display:inline-block;
width:2em;
height:2em;
vertical-align:middle;
background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAP1BMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZyFzwnAAAAFHRSTlMAEvRFvX406baecwbf0casimhSHyiwmqgAAADpSURBVHja7dbJbQMxAENRahnN5lkc//5rDRAkDeRgHszXgACJoKiIiIiIiIiIiIiIiIiIiIj4HHspsrpAVhdVVguzrA4OWc10WcEqpwKbnBo0OU1Q5NSpsoJFTgOecrrdEag85DRgktNqfoEdTjnd7hrEHMEJvmRUYJbTYk5Agy6nau6Abp5Cm7mDBtRdPi9gyKdU7w4p1fsLvyqs8hl4z9/w3n/Hmr9WoQ65lAU4d7lMYOz//QboRR5jBZibLMZdAR6O/Vfa1PlxNr3XdS3HzK/HVPRu/KnLs8iAOh993VpRRERERMT/fAN60wwWaVyWwAAAAABJRU5ErkJggg==');
background-size:2em 2em;
margin-right:0.5em;
animation: spin 0.6s linear infinite;
}
@keyframes spin{
0%{transform:rotate(0deg);}
100%{transform:rotate(359deg);}
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#serverArea{
margin-top:1em;
}
#server{
font-size:1em;
padding:0.2em;
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:16em;
height:12.5em;
position:relative;
box-sizing:border-box;
}
div.testArea2{
display:inline-block;
width:14em;
height:7em;
position:relative;
box-sizing:border-box;
text-align:center;
}
div.testArea div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.testArea2 div.testName{
display:block;
text-align:center;
font-size:1.4em;
}
div.testArea div.meterText{
position:absolute;
bottom:1.55em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
div.testArea2 div.meterText{
display:inline-block;
font-size:2.5em;
}
div.meterText:empty:before{
content:"0.00";
}
div.testArea div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testArea2 div.unit{
display:inline-block;
}
div.testArea canvas{
position:absolute;
top:0; left:0; width:100%; height:100%;
z-index:1;
}
div.testGroup{
display:block;
margin: 0 auto;
}
#shareArea{
width:95%;
max-width:40em;
margin:0 auto;
margin-top:2em;
}
#shareArea > *{
display:block;
width:100%;
height:auto;
margin: 0.25em 0;
}
#privacyPolicy{
position:fixed;
top:2em;
bottom:2em;
left:2em;
right:2em;
overflow-y:auto;
width:auto;
height:auto;
box-shadow:0 0 3em 1em #000000;
z-index:999999;
text-align:left;
background-color:#FFFFFF;
padding:1em;
}
a.privacy{
text-align:center;
font-size:0.8em;
color:#808080;
padding: 0 3em;
}
div.closePrivacyPolicy {
width: 100%;
text-align: center;
}
div.closePrivacyPolicy a.privacy {
padding: 1em 3em;
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
}
div.visible{
animation: fadeIn 0.4s;
display:block;
}
div.hidden{
animation: fadeOut 0.4s;
display:none;
}
@keyframes fadeIn{
0%{
opacity:0;
}
100%{
opacity:1;
}
}
@keyframes fadeOut{
0%{
display:block;
opacity:1;
}
100%{
display:block;
opacity:0;
}
}
</style>
<title>/dev/player0's speedtest</title>
</head>
<body onload="initServers()">
<h1>/dev/player0's speedtest</h1>
<div id="loading" class="visible">
<p id="message"><span class="loadCircle"></span>Selecting a server...</p>
</div>
<div id="testWrapper" class="hidden">
<div id="startStopBtn" onclick="startStop()"></div><br/>
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a>
<div id="serverArea">
Server: <select id="server" onchange="s.setSelectedServer(SPEEDTEST_SERVERS[this.value])"></select>
</div>
<div id="test">
<div class="testGroup">
<div class="testArea2">
<div class="testName">Ping</div>
<div id="pingText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
<div class="testArea2">
<div class="testName">Jitter</div>
<div id="jitText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
</div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<canvas id="dlMeter" class="meter"></canvas>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbit/s</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<canvas id="ulMeter" class="meter"></canvas>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbit/s</div>
</div>
</div>
<div id="ipArea">
<span id="ip"></span>
</div>
<div id="shareArea" style="display:none">
<h3>Share results</h3>
<p>Test ID: <span id="testId"></span></p>
<input type="text" value="" id="resultsURL" readonly="readonly" onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
<img src="" id="resultsImg" />
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
</div>
<div id="privacyPolicy" style="display:none">
<h2>Privacy Policy</h2>
<p>This HTML5 speed test server is configured with telemetry enabled.</p>
<h4>What data we collect</h4>
<p>
At the end of the test, the following data is collected and stored:
<ul>
<li>Test ID</li>
<li>Time of testing</li>
<li>Test results (download and upload speed, ping and jitter)</li>
<li>IP address</li>
<li>ISP information</li>
<li>Approximate location (inferred from IP address, not GPS)</li>
<li>User agent and browser locale</li>
<li>Test log (contains no personal information)</li>
</ul>
</p>
<h4>How we use the data</h4>
<p>
Data collected through this service is used to:
<ul>
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
</ul>
No personal information is disclosed to third parties.
</p>
<h4>Your consent</h4>
<p>
By starting the test, you consent to the terms of this privacy policy.
</p>
<h4>Data removal</h4>
<p>
If you want to have your information deleted, you need to provide either the ID of the test or your IP address. This is the only way to identify your data, without this information we won't be able to comply with your request.<br/><br/>
Contact this email address for all deletion requests: <a href="mailto:dev@nul.ie">dev@nul.ie</a>.
</p>
<br/><br/>
<div class="closePrivacyPolicy">
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a>
</div>
<br/>
</div>
</body>
</html>

View File

@@ -0,0 +1,58 @@
{ lib, pkgs, config, ... }:
let
inherit (lib) mkIf;
inherit (lib.my) mkOpt';
cfg = config.my.nvme;
nvme-cli = pkgs.nvme-cli.override {
libnvme = pkgs.libnvme.overrideAttrs (o: {
patches = o.patches ++ [ ./libnvme-hostconf.patch ];
});
};
hostNQN = "nqn.2014-08.org.nvmexpress:uuid:${cfg.uuid}";
etc = prefix: {
"${prefix}nvme/hostnqn".text = hostNQN;
"${prefix}nvme/hostid".text = cfg.uuid;
};
in
{
options.my.nvme = with lib.types; {
uuid = mkOpt' (nullOr str) null "NVMe host ID";
boot = {
nqn = mkOpt' (nullOr str) null "NQN to connect to on boot";
address = mkOpt' str null "Address of NVMe-oF target.";
};
};
config = mkIf (cfg.uuid != null) {
environment = {
systemPackages = [
nvme-cli
];
etc = etc "";
};
boot.initrd.systemd = mkIf (cfg.boot.nqn != null) {
contents = etc "/etc/";
extraBin.nvme = "${nvme-cli}/bin/nvme";
services.connect-nvme = {
description = "Connect NVMe-oF";
before = [ "initrd-root-device.target" ];
after = [ "systemd-networkd-wait-online.service" ];
requires = [ "systemd-networkd-wait-online.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${nvme-cli}/bin/nvme connect -t rdma -a ${cfg.boot.address} -n ${cfg.boot.nqn}";
Restart = "on-failure";
RestartSec = 10;
};
wantedBy = [ "initrd-root-device.target" ];
};
};
};
}

View File

@@ -0,0 +1,15 @@
diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c
index 21fb292..f9090d1 100644
--- a/src/nvme/fabrics.c
+++ b/src/nvme/fabrics.c
@@ -41,8 +41,8 @@
#define NVMF_HOSTID_SIZE 37
-#define NVMF_HOSTNQN_FILE SYSCONFDIR "/nvme/hostnqn"
-#define NVMF_HOSTID_FILE SYSCONFDIR "/nvme/hostid"
+#define NVMF_HOSTNQN_FILE "/etc/nvme/hostnqn"
+#define NVMF_HOSTID_FILE "/etc/nvme/hostid"
const char *nvmf_dev = "/dev/nvme-fabrics";

View File

@@ -268,6 +268,9 @@ in
# For pdns_control etc
systemPackages = with pkgs; [
pdns
(pkgs.writeShellScriptBin "pu" ''
${pdns}/bin/pdnsutil --config-dir /run/pdns "$@"
'')
pdns-file-record
];

94
nixos/modules/spdk.nix Normal file
View File

@@ -0,0 +1,94 @@
{ lib, pkgs, config, ... }:
let
inherit (builtins) toJSON;
inherit (lib) optional optionalAttrs mapAttrsToList mkIf withFeature;
inherit (lib.my) mkOpt' mkBoolOpt';
rpcOpts = with lib.types; {
options = {
method = mkOpt' str null "RPC method name.";
params = mkOpt' (attrsOf unspecified) { } "RPC params";
};
};
cfg = config.my.spdk;
config' = {
subsystems = mapAttrsToList (subsystem: c: {
inherit subsystem;
config = map (rpc: {
inherit (rpc) method;
} // (optionalAttrs (rpc.params != { }) { inherit (rpc) params; })) c;
}) cfg.config.subsystems;
};
configJSON = pkgs.writeText "spdk-config.json" (toJSON config');
spdk = pkgs.spdk.overrideAttrs (o: {
configureFlags = o.configureFlags ++ (map (withFeature true) [ "rdma" "ublk" ]);
buildInputs = o.buildInputs ++ (with pkgs; [ liburing ]);
});
spdk-rpc = (pkgs.writeShellScriptBin "spdk-rpc" ''
exec ${pkgs.python3}/bin/python3 ${spdk.src}/scripts/rpc.py "$@"
'');
spdk-setup = (pkgs.writeShellScriptBin "spdk-setup" ''
exec ${spdk.src}/scripts/setup.sh "$@"
'');
spdk-debug = pkgs.writeShellApplication {
name = "spdk-debug";
runtimeInputs = [ spdk ];
text = ''
set -m
if [ "$(id -u)" -ne 0 ]; then
echo "I need to be root!"
exit 1
fi
spdk_tgt ${cfg.extraArgs} --wait-for-rpc &
until spdk-rpc spdk_get_version > /dev/null; do
sleep 0.5
done
spdk-rpc bdev_set_options --disable-auto-examine
spdk-rpc framework_start_init
${cfg.debugCommands}
fg %1
'';
};
in
{
options.my.spdk = with lib.types; {
enable = mkBoolOpt' false "Whether to enable SPDK target.";
extraArgs = mkOpt' str "" "Extra arguments to pass to spdk_tgt.";
debugCommands = mkOpt' lines "" "Commands to run with the spdk-debug script.";
config.subsystems = mkOpt' (attrsOf (listOf (submodule rpcOpts))) { } "Subsystem config / RPCs.";
};
config = mkIf cfg.enable {
boot.kernelModules = [ "ublk_drv" ];
environment.systemPackages = [
spdk
spdk-setup
spdk-rpc
] ++ (optional (cfg.debugCommands != "") spdk-debug);
systemd.services = {
spdk-tgt = {
description = "SPDK target";
path = with pkgs; [
bash
python3
kmod
gawk
util-linux
];
serviceConfig = {
ExecStartPre = "${spdk.src}/scripts/setup.sh";
ExecStart = "${spdk}/bin/spdk_tgt ${cfg.extraArgs} -c ${configJSON}";
};
wantedBy = [ "multi-user.target" ];
};
};
};
}

View File

@@ -466,6 +466,32 @@ in
(mkIf config.virtualisation.libvirtd.enable {
my.tmproot.persistence.config.directories = [ "/var/lib/libvirt" ];
})
(mkIf (with config.services.kea; (dhcp4.enable || dhcp6.enable || dhcp-ddns.enable)) {
my.tmproot.persistence.config.directories = [
{
directory = "/var/lib/kea";
mode = "0750";
user = "kea";
group = "kea";
}
];
})
(persistSimpleSvc "headscale")
(mkIf config.services.tailscale.enable {
my.tmproot.persistence.config.directories = [ "/var/lib/tailscale" ];
})
(mkIf config.my.librespeed.backend.enable {
my.tmproot.persistence.config.directories = [ "/var/lib/librespeed-go" ];
})
(mkIf config.services.hedgedoc.enable {
my.tmproot.persistence.config.directories = [
{
directory = "/var/lib/hedgedoc";
user = "hedgedoc";
group = "hedgedoc";
}
];
})
]))
]);

View File

@@ -37,7 +37,9 @@ in
extraGroups =
[ "wheel" "kvm" "dialout" ] ++
(optional config.networking.networkmanager.enable "networkmanager") ++
(optional config.virtualisation.libvirtd.enable "libvirtd");
(optional config.virtualisation.libvirtd.enable "libvirtd") ++
(optional config.programs.wireshark.enable "wireshark") ++
(with config.services.headscale; (optional enable group));
password = mkIf (cfg.passwordSecret == null) (mkDefault "hunter2");
shell =
let shell = cfg.homeConfig.my.shell;

View File

@@ -116,7 +116,7 @@ let
});
default = { };
};
drives = mkOpt' (listOf (submodule driveOpts)) { } "Drives to attach to VM.";
drives = mkOpt' (listOf (submodule driveOpts)) [ ] "Drives to attach to VM.";
hostDevices = mkOpt' (attrsOf (submodule hostDevOpts)) { } "Host PCI devices to pass to the VM.";
};
};
@@ -126,8 +126,8 @@ let
(map
(i: mapAttrsToList (name: c: c // { inherit name; }) i.hostDevices)
(attrValues cfg.instances));
anyVfioDevs = any (d: d.bindVFIO) allHostDevs;
vfioHostDevs = filter (d: d.bindVFIO) allHostDevs;
anyVfioDevs = any (d: d.bindVFIO);
vfioHostDevs = filter (d: d.bindVFIO);
mkQemuScript = n: i:
let
@@ -204,7 +204,7 @@ in
services.udev = {
packages =
optionals
anyVfioDevs
(anyVfioDevs allHostDevs)
[
pkgs.vfio-pci-bind
(pkgs.writeTextDir
@@ -212,7 +212,7 @@ in
(concatMapStringsSep
"\n"
(d: ''ACTION=="add", SUBSYSTEM=="pci", KERNEL=="0000:${d.hostBDF}", TAG="vfio-pci-bind"'')
vfioHostDevs))
(vfioHostDevs allHostDevs)))
];
};
@@ -261,12 +261,15 @@ in
};
preStart =
let
hostDevs = attrValues i.hostDevices;
in
''
if [ ! -e "$STATE_DIRECTORY"/ovmf_vars.bin ]; then
cp "${cfg.ovmfPackage.fd}"/FV/OVMF_VARS.fd "$STATE_DIRECTORY"/ovmf_vars.bin
fi
${optionalString anyVfioDevs ''
${optionalString (anyVfioDevs hostDevs) ''
iommu_group() {
g=/sys/bus/pci/devices/0000:$1/iommu_group
until [ -e $g ]; do
@@ -280,7 +283,7 @@ in
done
}
${concatMapStringsSep "\n" (d: "wait_vfio ${d.hostBDF}") vfioHostDevs}
${concatMapStringsSep "\n" (d: "wait_vfio ${d.hostBDF}") (vfioHostDevs hostDevs) }
''}
'';
script = mkQemuScript n i;

View File

@@ -6,4 +6,6 @@ in
# yeah turns out this is in nixpkgs now... we'll leave it as a sample i guess lol
monocraft' = callPackage ./monocraft.nix { };
vfio-pci-bind = callPackage ./vfio-pci-bind.nix { };
librespeed-go = callPackage ./librespeed-go.nix { };
modrinth-app = callPackage ./modrinth-app { };
}

26
pkgs/librespeed-go.nix Normal file
View File

@@ -0,0 +1,26 @@
{ lib, fetchFromGitHub, buildGoModule, ... }:
let
webSrc = fetchFromGitHub {
owner = "librespeed";
repo = "speedtest";
rev = "5.3.0";
hash = "sha256-OgKGLQcfWX/sBLzaHI6TcJHxX1Wol6K7obLf0+CHrC8=";
};
in
buildGoModule rec {
pname = "librespeed-go";
version = "1.1.5";
src = fetchFromGitHub {
owner = "librespeed";
repo = "speedtest-go";
rev = "v${version}";
hash = "sha256-ywGrodl/mj/WB25F0TKVvaV0PV4lgc+KEj0x/ix9HT8=";
};
vendorHash = "sha256-ev5TEv8u+tx7xIvNaK8b5iq2XXF6I37Fnrr8mb+N2WM=";
postInstall = ''
mkdir -p "$out"/assets
cp "${webSrc}"/{speedtest.js,speedtest_worker.js,favicon.ico} "$out"/assets/
'';
}

6239
pkgs/modrinth-app/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
{ lib
, fetchFromGitHub
, rustPlatform
, pkg-config
, openssl
, libsoup
, dbus
, glib
, glib-networking
, gtk3
, webkitgtk
, libayatana-appindicator
, librsvg
, wrapGAppsHook
, stdenvNoCC
, jq
, moreutils
, nodePackages
, cacert
}:
rustPlatform.buildRustPackage rec {
pname = "modrinth-app";
version = "0.6.3";
src = fetchFromGitHub {
owner = "modrinth";
repo = "theseus";
rev = "v${version}";
hash = "sha256-gFQXcTqHgSKfne6+v837ENXYYiEYu/Yks9TpnfBCPnA=";
};
cargoLock = {
lockFile = ./Cargo.lock;
outputHashes = {
"tauri-plugin-single-instance-0.0.0" = "sha256-G4h2OXKPpZMmradutdUWxGG5axL9XMz2ACAe8AQ40eg=";
};
};
nativeBuildInputs = [
pkg-config
nodePackages.pnpm
wrapGAppsHook
];
buildInputs = [
openssl
libsoup
dbus
glib
glib-networking
gtk3
webkitgtk
libayatana-appindicator
librsvg
];
pnpm-deps = stdenvNoCC.mkDerivation {
pname = "${pname}-pnpm-deps";
inherit src version;
sourceRoot = "${src.name}/theseus_gui";
nativeBuildInputs = [
jq
moreutils
nodePackages.pnpm
cacert
];
installPhase = ''
export HOME=$(mktemp -d)
pnpm config set store-dir $out
pnpm install --ignore-scripts
# Remove timestamp and sort the json files
rm -rf $out/v3/tmp
for f in $(find $out -name "*.json"); do
sed -i -E -e 's/"checkedAt":[0-9]+,//g' $f
jq --sort-keys . $f | sponge $f
done
'';
dontFixup = true;
outputHashMode = "recursive";
outputHash = "sha256-9HtTdIotG3sNIlWhd76v7Ia6P69ufp/FFqZfINXSkVc=";
};
preBuild = ''
cd theseus_gui
export HOME=$(mktemp -d)
pnpm config set store-dir ${pnpm-deps}
pnpm install --ignore-scripts --offline
chmod -R +w node_modules
pnpm rebuild
pnpm build
cd ..
'';
}

View File

@@ -0,0 +1,10 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyBJYzdr
b1d2aEtVd3lVb3NBamRwVFpTaTRjZFlCczk4MVIwQUoxWklwN0NrCmFFekpPYUlO
YlgvVlQ2WDR6amZDN0ZSY0Q3WWtTME5pUmhQeks1c3dGOVUKLT4gWDI1NTE5IHVK
bUZvUVAvL0NmQzFkY3BuYm1wMjcwbFpLRUNpZjJCaW15SEVDUDV0REkKRXFMQ2d1
NlFBejBvTlJrcUtCYWZxSDBkbmxIdExBNTU0aC8zRW5OVWllVQotPiBDLWdyZWFz
ZSBkeC4oTFUgO0FtJG9+RyB2IF1QXGhxVwpJS213MXBRMWY1cXlHZwotLS0gRUF2
ZkswNlhvcDhTc2tybCs1dldwa2l6SDZZVmNkNUNjNGlkV1ZVa09pOAp88dxHGxVU
vuFQO6JcroY9MF5Te/YV+wMc3hVxksibMnH1TWGh207prwcOWNOEz2iEkZY=
-----END AGE ENCRYPTED FILE-----

View File

@@ -0,0 +1,15 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyBLVlg2
ZUdtUlFUQXBLT3B5YmkycWJnMXJyKzltbyt6K2dJK1RBUm5ydWwwCmRUdjJFSEYz
Wnp4cGtzTXZwc0s0SUJQUjRlOUJlQUoyQ3BETXZmY0ppWG8KLT4gWDI1NTE5IGR5
QUJzeG1DQTRLUmRwNnNSRUJRSFFtUDl5VjB0clVLYUp3R1g4TEVKaTgKb09tVlhF
R0tmcmIxMHVHcG80RGxRTEhBcngvT3MrdnNPbmpCTlRyZW5xQQotPiA6RzEtZ3Jl
YXNlCldSUlN2ejB0MGpyUHYzNS9OQmJTK3MvcXRDakdBVlhuUEt6SFE4QmhnWVN0
V1JMOE1oaEp5QQotLS0gYW1OMTcxNWJrUndmR2h0ZmRDWk5CYnJjc29pSERUMnNk
d2VhTGdpOW4yUQrEeH2E9m0YycuW60QrdlRetO1kNU5FaKXRQt46iA9lACIWD4rC
Cx6WxhCBgz3hvm9x6iuYiiQxZzgJNK7qXcV2MBeQdivazeEbC7blAKVPhwD/dl+b
PzBDXRXG3c3jMjeZFT69fIBGJfZrrLGKpTALVE4dTVXmQmVVQDTp19IC+jUXHBti
Pj6Dpc7452s8zPkzZyRbasO9b4PYTwq8IHT6X7ITwbzZZm8gexDYe2SzRZ5VcPz3
El+yoULZ92WbXPSQIP/Slx4BEZjmsQS+sm0N8AnBRNZkWVbHPF9IZRg3VjDAn2i8
F3un5js=
-----END AGE ENCRYPTED FILE-----

View File

@@ -0,0 +1,13 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyAyMWox
cEFDWWUrVzJSM1o2azJqei9HV2xFY25oQXV5SzM3akxEaUJiN1J3CjkrQVhjWHY5
Uk01eGp5Q0RKNVREVXJVZytndTM0SXNZSGIvUVp1TnRiNXMKLT4gWDI1NTE5IFZn
WjAyR1RMajEyMnFSYnNGT2EyekROVWNoakFJQVZxaFc0YThOMHVyanMKWldrdlAv
cVg0OTFHL2loeGJ3RHA0MnlnckN3czF4RUgyc1NjYXVOSXF5cwotPiBvTFQtZ3Jl
YXNlIDRsSDp6eikgT1ojIGEzOFZMIFc3MUZGCkttZ3ZLNGxucnlJc01kRXFZTGpC
eCsvRzl5WnFUMUIyTWNVWGk4SjQyN3V0bXQ4VzFuM1RjSzVMcDJkaW1JYXMKQkE4
YWI1Mmg3MkpjdVpVYWJkczJQMnM1SVMvNkZhOXBDVEZPCi0tLSB3SVIyU3M5RHBE
VFRtMFU4OUFLbkNjbkJmVmhlc2VsYzdsd0pFaFkrUmkwCs+h2KlXoyZ8U++A9wmV
kh4N2YyI/a84yPGDNoFdSlXaU8jxUzolnadImXSXyB4CroqQLvGEbkZZlWqPLVfh
Iav7Ja8=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,12 +1,13 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USBlL0tm
THFkTDVWLzFjMWJFdFZOdWt5UjFIMWtVYjI4SStCTmIxbGZjL21FClRZT3NtMU1D
OEthcm8rUUs5VERVWllxZGhDd0NxM3NGbXNHRHBFbGs3ancKLT4gWDI1NTE5IE82
VzJ0MkRnZUNSZm42Q2VqQjBBWU1JTWRkOVdtTXpwcStsWkpsaGRxQkEKanNBZGUz
dUM4UFRhRXFBVDYzU09Zc3A5ck5reEJid1BHTWNrcjFYUFNEMAotPiAqWk4tZ3Jl
YXNlIDdiIGdjOko5PnU1IDY7CmZaNXN1VnZOY2VVemJhRnFyQ1ZvVVJ1WGFEOGtY
K3VZc3crZXQzdExBMU0wZWhFMzFwUGF0eS9PWW16N1VIYVgKL1MwQVQveGw0S3Z4
Ci0tLSBveS9pSFEzWFY4d3RpWnU5NXhkWGE4bEtKTjREVGk0SElndXlHWVZzejVF
Cp2+3mlaFEETvf/S1EsHszEfvvneDkHpdtyv4V6slRsAI6ieuVWXSo615ge5F/Cm
wzERcvjx4fMTSkgxmpv68o1HxiZmiCitF8Uq7qzVe+MII0keSiK1aDSnteE=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USB2WFY2
MzFnVFYvb0wzc3grRDBrUi9teW1tNmx5dVBIRVc5OUdlcjdvTDJFCmpJL2tlYXND
bVJKbzd2S3JkSFVMdG40MS84V0lPTVJSNHVBQlNXSkN1eTAKLT4gWDI1NTE5IFBM
ZGo3L2VlNUZqOEE1UHBuMHdqc1pyYlQ3R29ucE9pajU0bHMzamlXRDAKcG1Qdmw2
cUlncDFWNXBOWnpIeDNZSFA3d1E1bjNaVVpKU3lMRjRaSHNtMAotPiB2XUh8eF4t
Z3JlYXNlICUrO0cxIH4gaTRoIF81SEpTN0Q5CnpWdEZpb1hZa2t5YkE5RnJFMHVZ
WkhkQ2o0eWtyOE9ueDJkeGd2aUhmLzRUUGs1aUc1NURIOTYxczZhOEVmT0EKd2xk
TXFHN051d25PQmtNUVZkVEFGUVliZjdmZDF3RWFkaEhNTzd3ZVd5N3dlNzQKLS0t
IGZDR1Mxd24zOW05bitzQnN5WWVOOGtCNEc5aXIraEF4eXFUQm5CZUdCV2MKd44C
/Trgg0OEZ89/jqbj56z/Hia1Ka3ZsEv6bXPI/kcRvFDBFTgtvG3KWCgMBtTUHXzY
TKBPoQqrUf7plH7a/mTx3KR+4Y+yF+1i86s7TzYjD8d1xfFH3BsVtg==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,28 +1,30 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USBmNVFZ
ZTlIM1JjbE04d2VSMm5jTGlRSStHU2JMeVRFeXhwVGtBby9NK3hzCk9ZRUh3Tk1L
R2FhSVdtbzIzZDMreENJa0ExSk9LVDIxTDY1dnZEUGF0NWcKLT4gWDI1NTE5IHBC
R2tVU29BY1ZYLzgyVnpVSC9UR1NXWnFGd0N1RXJwcDdpUmFVKzdmbFEKbmVOT1My
dlBJK1pSQmtvd1BMcXZoOHY2RGhteHgrTjVFVjNaRmU3eHB3RQotPiBLJEBWLWdy
ZWFzZSBHVEEKNGpuTlp0V3lFakZaMVNzckNzd0hNZDdtNWE0R0V3Ci0tLSB0VEwv
TmYzUm5ZRmJ2eGdrM1RhWkJIWXJkMjRsNWxhRCtNUzMvbE92N3NJCmFkBVJWwyL9
zbTtBadwL+AaGqlbL/n6s9XTlRsyjaYyJNrMeRkUGBVjXUtKJY58Z7MNy2p9QM+E
EXoCtmp7htBmLaHB9vsRyno5IQ1cnOTBMzeOlFdP3IFtPCX0W6vZmbcjwqOAj26v
x4Nil/AEHPz6X5ud0+iJClZWWjVeIzQrl/cIYGi65LNNl1aeW/rHj+SGHV/7iQ9j
4USsdG/xteB4ahP//6uBoZtxMH3b5FqoCmV4N0OmHfpIfH7gSW8Uak9Bpiie/wtQ
pisXM7NU2fIgufszyFDZJfFCyk7ZGl6xZIJGrU4gqepPZ5pQhDk6TCePqTlI6hod
PHBtDsGXX5eV7SCH5KZaK4bdhR0LIi+xxGb6GDF3ygyrOfuJWHFTq3rrZgfZJe3n
JhvGTy/9EjTtqw2/Ew0Nmd2PX+ufZdVrck4/BRW0HqNA4Fq+0d4osOg6PK47eMxy
uxegE+wuNlyjV8cWqVrISZrZjU6ayzHLgGuZe+2nsKliM5dlv8FcCstNuhiQha+V
+/n1pojsJ0HqKrPUuud8Gr4g7n5j31xuWZCAzte0ci1kEqWq2/ROIFa46LGTaeha
NNLTIUr+KFmGyIoaKpwcWreRye2T8aUsjuWObZFAYwS9ML+J2/l/KdEzn5Ki641e
RTH/px25jWEOlicPXUTY/eMufL4+/41e9mrxLvOJX2BCrur5vGQnqTFvYkk1eNjv
mtu04iEMo8t/9DGG3ebQqFTiwZYs8hvq9W38thHoP75DgfyE203L8v/rdTtIasbp
cVIxQxpdRNyB9nQzVj3Epck+fo9sWIf7n/IJW4+SWr37z0/4Fih/D7mGrxJ5W9CX
9oecl6prfCnpnDeVreNb1STwDijZEkGxJqcYExn6wV+MbW+tWSpstFz/U3uuXFJQ
5luVw/Usi77D8B/yYSTFRZHi0pCWEZ1x4YLaeZHr19hRB3vpRcqmPcgo7FPHDYEP
M+XwKlLxkIkgSKWpNkyKmEm+hB+fJS9D6rJiW00BGZfafcV4eUjxYkqIJ3eZZOrw
WPaso89Iw+61gQECFAbisXpPoS0aG0tU1TUAqnGe8e7dKqzOLM+GyGjPIO71DVCj
U3pQpE4ts3C0vKfwXzoiuJynN/bYIZQ9CSsqxMepFvlJjfLMC2MQv6lc/1kCIuvn
HSZ7wUTthaodVC+q9iAX
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USBuQjBY
K1ZTUzR0SmFoYUZLdzUzNUt2M1B4RFdPZzFkcW8rMWJLUjVHOUN3Cjd3ZHdMSzdp
OWswditVWUhYNjZCdjV6M1d6U3pNak5hUlZjTHNqSkZPSk0KLT4gWDI1NTE5IGNG
ZytHazJQWTExMjNkZWV2aDUwcnZjUGcwcXRkZWl0M0F2R2JpUVlJekUKWTFlbkEz
YlN6dkgrMmFFcmlZMjQ0b2oySjlEMC85cUF5QlA4NGF3blBKRQotPiA8M1hbWS1n
cmVhc2UgOmlZJFYmJgo3UExzUHhSVi9lbVRjNW4xTnVaUTVGSGVDNzRUNlJ2TnVu
U0wrWU5kd3dyR2phcUNVUHJCYjdzeWhjNVFOV011CmZMOVN0WDk5eUg3ajhwbStQ
aHExT0EwblpreTBXVHh6Zk1HRkhzcmFQNnoyVUlaeStMUkgKLS0tIG1aY3Zadko3
V3pDMGswSDZCeit4SVhSRCsrZVRVZVkvQkNsQWN1MXFMUGcKcK74YULWqWw9VvkI
NH38VHfDPW5ueSiyHHKn8MI9YosPr/TmkwgKd/DOIMVB74ahPalo1QUeg+eaBVnq
Uncsbx5ecW3JswthkAhiktWHcdHmioGD6hCcgbWtfA3VvbAYc2gtAF2plfDVH6BD
c8veai3B15ZmDmq3b62sgVA9JUgbFaB1eRqcaPXmNgQJR4c8J+CZWXGQ/TKMqtAg
chCDuczjLX8IxhMPF1gdCggSt5GtMhY47fpZJRbBUw01l8koqjm63KvEeg2ejFGU
+tXonI4jm2JUxlDTqmNSrVpmAgtPoEPszHc+GsnyNjAz4IXMm5UrQAZyDPgxtwQW
ZAn0IdOB8rSL/AnRGUpPrecuauINQjONe8CapijjJPQK7g1AHscfxr+OJD1j2eV3
O6TNlz8vKW4t/V7CUf46ykxxExhA0mKJ53ksaXy2+HWoro2+c4nao/bEld5gt08U
uCpJtjPKB64X6vdzbY21/l87VRDyxbb3poENfrXlawqS0Z7i2gAbHN5EuiMv+35o
sBaR0BfcbTn6VagC3i8HEEOO964FrW65pkqmGJcJMgUdcZSl+Y7gHMjWyodqGPOY
evT6xj4iyeM49vXynV2vrJRu5rr02hOS/8rPphV9c9q9ju5n8xbhS6IiybAelPwt
sa+xM+w0n+fxVksiXeFj7qD1LDN4+kwqhYP9SlzbA4fT3AkYYrxthTww4IFAweyQ
IJkpVL0/IZEIEfRzpr0lWLprAaoyPc64pecl0z/gBJDgz1kSG6iEh6K4qx7ahGde
kBBpS2I2ZsdBkvmQxDSM7tYYBzPxcUNZlSFOIeUy3Xl+OGPlKgtMofbnjV8AFqUf
tOpgKpLUEkTgXbGUKBxHLj+8pbw7zOFp4sJ00i48ZzLP5D9jom+jS19wGshRc7cH
dK92CctvrfndQ85yO0vqlyOdMTqjh/z3P2KmhL5SW6P51q5mseTvj7FNM7331DTs
rq7XWaBLE61eWWQ/dZKnqh5YbkSlU1+08Rl6H/vCU5hTC8fht3KTQSWPofkrP+5f
We/Pe62LyhV/MbLRA0nmU7Sf4IAnpHfa4kLtlYeB3xiqKd0McM//qzjuk5NoIgE4
nL0T8YXdGt8K01w+nt+j5bo5gFoRz5+1/ZZ9BgN2DOo4SClYnJWQ/x80X061yJ33
0SGv4eAC3vFi6xE=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,15 +1,16 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USBqeVVR
bjlGYjl5SjVKYUhzNy8xZUZKcjJyYjlXSHl6TnppUGwvSk9POENvCitzc3g1Wmt0
SGdPakcxd09NbExMTXVjRW5YMnd6V3hUaHBXdHR2SmxiSFUKLT4gWDI1NTE5IDdI
dDduZUVtK00zQzg1cmRxMWgwcmNiQVdqN2NUeUJMMGpFa1I2MnY2MkUKWmY1V3Aw
cTlRVkMzNU1hYkRaL1A0aE5qV0lJa2lPQ0o0TGtuaUJRMUF5QQotPiBCcy1ncmVh
c2UgMUBLWXBjeyBaNidteyBpKDFEd3BzIDI/dQp6allkWkExUlVicmE5akN3UmtF
WXFRVmVXaXcydkl0d2pzdDViUEQramQ2V2srZG8zNWdJZmZVN1hTMXdMcUQrCmpK
WitqQQotLS0gMzFrZ1ZKLzhiSHV5UFhVV2xwaUMweER2MjFiZFB3THBoSmdRVmlo
TGVCYwqoZ8aMTHStyXBPSprQC1f4QkIbxYM6ThJb0xjIrPxcVFUZT6xJTfAgCNbr
TpsnIYf07r0w5HL2fYe8FpPnw9qTtf5AyvVcy6ktJ9WawFf9BmJilkMkJ7Rv7YZD
UUGWtKgXnDZg3BEcmxL1sFJVD/WtHNhXIynBKTA3hqYyIkO8ugVCNbEQN871Yuu3
xiwGEEUHrjKEFZjO2S3HyXNEoV/NiaDAE8sbI3R+ju8ssV39XdNx0gDwlPzfgmSU
4UFReW1Zv23HlYzB4C/E4YDDwZviF/oSNwemlIXuj4VH
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USA3MEFh
YURySHY5RjVQa1c0QmMvTkZtZElNd1BIeDFpR1U1YXZ5dndnclUwClA2M0ZYMk90
RmlCZHVISkxZQTZXeEhZVUROSVRGRVg4TmZKZytSL05FcTgKLT4gWDI1NTE5IFY2
V2k3S0VQdGlQZ0hkU2ZoSWdOUG9rQ0p5Ukg3ZHU3MXVvNHlWYVN5VVUKcWtoWDJh
LzRwcktWUGQ1bnJvRzVBVlpHU3NhdzYwUDBPTmx3MFNrdWNQYwotPiBKQil6Km0t
Z3JlYXNlIFdlRTlUU2cgVlxLIzUgJlVyQiJ8Cng3NzF2b3d6MnlEdURQWHgrSFJv
Y1BMUkZyelJSdDJvUUUwY1k5R3ZBMnJaa1R4NWxlUll2azNseW5MQlpvVWUKYUdN
d1ZscXVxd1dxSGpzMjBYeWhhYyt5ZlNkSjhmV1ZTTDBTCi0tLSBBTG45VUJOSXZv
N3lYNVlyZldMVkpZdUMvS21NdSswVmU3VThZK2M2eis4CjwfWWJVR9Ty5dBXEr5s
U+QrifXvyMJJvqOKEfMYYomFLpt/VtbDAUwNlqLnFIk1VZ2xPUBisXPtReiCK3gq
P+i6bUONSmPYvmF82VgiuKDuz/kmWqVGg2iSBPIXAGLNIEojndQwmhnrsN9ex4Xy
lBHkvVsN8EamUJwZ+FEZe4+PjA5yEnANWpeTELOt2gA92/jwwnNIsr07eVTlkh8X
UmQ2owGwktXP7it6//NV3C7sAdazs2bX65WSnog2E8WPNAorKWI8RCYs33CshVFt
zzclZ4hRmlAmqMHYqFY=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,13 +1,11 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGo2N0ZYUSBDd3Ix
REFzVUVsSS9VT0diTEw5c2VCYnY3VEFvZ1o5MGh0MWdydUVDbGdjCnZPUTVCZ09n
eFd2a2h4M1BOdythTlk5VzQ4V0RsL0tCNzJlcHF5ajBleDgKLT4gWDI1NTE5IGtj
VWwrTHpRRUVpbmdxM2xEVm5qdkZCcHVCRnJZb3Q5bDJvNGRMMisyUVUKMWV2emVM
a21QYlRMdHNkMjFuVDhXdmpTajE1dllubUpra0F5eTcwNXZtVQotPiAhdFNSJW9a
LWdyZWFzZQpQR3dzbjZqZ2hIRUlOT0hTcW5VQXJDZ0s0S2tONEVHRGJwU1QveFE4
eVJFd3pVamVPUWRGVi90Y0F2T2dZZlBIClFYV2ZxNlBMbGdyT3NNckZpTW9vb01V
dmkxVUZiRnRLZlV3Ci0tLSBzdzVtakx3QWtiK2FkVnlqNkJPYmpCMGFZUHNkWndW
WlorOXQxcVhWUDg4CvqG8Zngak01fTo/JU7Vh9ViXfzC0PDr3jn/j1XIXmYOAqxi
g3/rsRxhPcTWDAEu+bFd2XvkM8SZEEsLdsdPzP0VQD+UfIR5pujKmoLqEpX0oxNC
4SQusSIRxFc4uaSR6Wg=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGo2N0ZYUSBoYlRq
ckk2c21uMVZSR05SdlJpck5MT0FZeUpLTmpTRVN2WDkxWWxmVTBvCjlHZWtEQ2Jh
YUdybjJLWkNsZkxabTVIR0JnMno5YlMvVmhodDU1bktrSzgKLT4gWDI1NTE5IFZT
Um9lWXhqRFFLTWdNaTR3Sm1acmY4N0l6WE1FSW54ZEtQcEE5RHBRRHcKcE5KYmp1
WVdCVk0wMHZ2SCtUR0xKWU10N0xETXlXZmgxcmZZOFBXYWtBawotPiBlRm1gKGxU
LWdyZWFzZSAqXF8gOkU8Tm96IGA4IC1TCjY3NUgKLS0tIDhjaTNrbG1iQ05iTWRS
UzIvNzA5TmVGS2ozZmYrYjlBY3J4Z1RRUGRNeWcKUTIEhWqr0fOODu86MDll7k3U
ThgmS9nlcUY3fMgXzZLtpHIJ/4ZSI+miu8RmLMaeC61qv6xNThGdx+MvU4tMBWKA
Hv3XGi2MYL1jdHh2KYg5PgdqchYuHrFuBPS7c/tQow==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,82 +1,82 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGo2N0ZYUSA2UUhN
QTF2TUF2UXVkT096L3NqWndMbXRDd3hYWEdVaWlHMG9KemRkUnpFCk84SHc0YUNZ
QXJTN2VxL0ZsT053V1UxOVdQV2orb2c5UmF4NS8yTzBHN00KLT4gWDI1NTE5IDVC
RnVRbDVYU2lyRHJGemVvSjBTRitFUmJUQ2F5RDB5RDlCR3JOMGhzeDAKYjB2ZEg4
K1dmWmhFUUhZMXN3ZldDMnNWdnpGYktGWVNGSmhGY29nWVNqawotPiBUPjtPUyhZ
Ji1ncmVhc2UKK1pZNmRGMnlsK042dmlodUNURndSNW5hR3ZiZHpBaFhwL3VsSDdN
RlpMK3g2NjByZ25ENE5wYllEOG4wMzlsZgpxZzBkZVBKNSt2QjdxY0w4aGY0N0xp
VURYV2JPTDhDRlVPMjIKLS0tIDBGa0ppTkFtaDJkNWxhWEFLcm5sR1RjWFBLMVgr
aWdxeEpsQW5xem5ubDQK+840lJ58bsN7IWJ+CiK3dEI6DxN0VPSufstDTgvpBoT0
Xl6CHPtEKITEpOCEFtqkElx7d42PGMvhkaOyo4zs2T8m/gSJxOojG4heAkXU78gq
H6tDV7AEZhLZmuHCZb7U0mIz305i7sFW//qUJX12rt0HOmHC2qnV/PXhPIEeGhcX
Xa2YVMp5SGKPn9zKWcgPc3S3pEPYRVxmDGo0+Uf8H0RsMOmMMN6s1dApEy2JAyAO
vbDBtSNVtKPCXGxWfKj9Gbxx2Svbwv/cLephGUByny0YwQHtTPlqKaFRhjdYnyed
DY2EDqCa8uAcpDUCAHK0EPA+0kb0s9Y97y2qyYqBlBrPgThyDDUySGB2qv1AHna6
ExrsgBXgIWKNJLbzhfIk+3HlkZ+6Zlt4RuGJztCcrL1LHfft2M0nq7YBWUnCI6x+
QYmc3aSwsE+21ul2wAce7GqGxoZDE0IcxmCB+qLly5MJrWCY06wAdbMTvBvpMnkJ
PGhl86/EvQdbfRF1YfvZ/2r6a+obGs0fh3z4lhHP3aRVW76EKYSXWARaQRDbRsIP
M8gLLb5edb5J3SKgmAM6H7BDbCfddOncLZsKfAUP/scFJTszLFhaVKSNX5WyPDYI
JjWWfkm3QO1i/ueuezcAax9VI0hC6WAUsCo/2WSif9DbVMP/yHaoyvAeYoGFNjPl
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
xG01FgOaJ4w=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGo2N0ZYUSBZVkFh
RDNNZCtySlNQTTZFbzJvZmF2TEZKVUM5VjFjQWNSeHlNc1JNZ2hNClVac2pEdWdw
OVpOTmhWWklVRDA3UzZWWk9QVG1ySUFmTzRSVlFReVdFVFEKLT4gWDI1NTE5IDVD
eWN2S29aWVNVTTdldXFxZG1vWUNYK2RrajI0OGNGaklzdFByTzlPUkUKTmsvdTE3
ZFBvalZsdENxR0VnV3FVSnFxTitBRlFWR1BzcjJWd1h0U3hpYwotPiAyOkUlJC1n
cmVhc2UgIWFOMiogVDc8IFZETk9BSDVTIHEKQ01rc1ZoNXQxUDdtWGRQUlRCV3k1
djNZeEtOaUl6Tkl5TDA1S2ZXWTFQZEFiV2pWMDJpZ2dkYXdBOGhSTVA2ego4UnBz
ZGhXcklMd0NVWlhsc0Voem1wUzMyREViUllCRAotLS0gMU5GQjdJaVdlUFJGMG82
YnZCUm05ak9qcmVyUVJSS0tHaWRRTld3ZkNPMArRgojrBQvlyjMhChn8jgUNDysj
9Nh3BVqf44fiUNMKARTrFTz3wVMlioo6MmKRzJ/yj0fWkZ2h80X68Nq3rQvy+0UK
4PNPRbwY5ib0nf7n3itFKjehrYr8HnOjreQps4it52bT5re2TWIC9ogZhNKBLRvB
qv14HjcF5bGnia8TgSU/8nUZJuIaLwHvS5sc9GOtmV4lDwiSTEJQEtGh716Jzuvs
XxQLPEVVufAjZUKLp+jWUhXGkvUEeY5bxE2aOLuB8kLfHPC/5p2rl/n2sW3oEDFn
Fw+XcNnCHWBzk3DlzKZFXwIaZL6Ocqrt+p8CBpWoNhbssuKyOtEbWQOmJxX3UPMt
sBFNdKSKFhoBQ4ukqkKDhgcm0i+8wG4eBbNIMIDwzPBxK0QiVriwlPQHl7RS2M/J
LgGeS7qrKC3SgmLu57CdUVUlnogJ4oOg7FPh6x+jQBIIv7gtYCzJb040TUZWZWvi
cfKWBBwLqLa+7Y6kEhcosLUgw2c9Et5P4rvNjU598q7qrZq7uK6Mr+PMwD3Pd66O
SQyT4nYhhXBnaIsLXZfima2nRzPocaBmfsuXQwlnLJC8JB6yzqEViK0xYKfl0fIi
jxuYBw/8Y+MWQhIkF1pP8z+Kw51QdK4CIV33mlLBJnGjlizewsjj04EIgpzQ0+3I
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
sAtksQHMt1Njo1oRug3+/0iC6XWEig==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,30 +1,35 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGdTeFAwUSAyUHB0
bEI1UXExVDB4dklPNDdFeUJmR3ZZWEo3ektMcHAzNHArQWtqK0FBCjd5Vkw3V2Iw
S3dhOEtKSmpzQi9VVWpJZHcxWHBoMlV3bUZZN25VUGZONVEKLT4gc3NoLWVkMjU1
MTkgVkZjdzVnIDc0N01uYmVZbGYxdlM2TEdaMEdlODZGUDlLVUFMUzBMd21WTWFK
SEQ0MGsKcXpyMzhPTEEwWVorZEZGc0ZpVTlxL2dod0dzd1ZsV2toZXdXSWxGd0sy
WQotPiBYMjU1MTkgbWpjSE5pd1ZIdjY0eVNFRFlIUkJVWTNYS3J6RlB6bGFLb2lr
OVJsZHczYwpZOGxFTTZmTGFSZCtLWS9YWVJBRXVmZGN6QzlDb0ZmQUVMK1ZoMlQw
WEU4Ci0+IDQxOX1OLWdyZWFzZSBZZUBOOmcgZHx+biA6ZiA1VwpVb3NabW9OcGlm
dVpiaU81R0dDSGN5cnBNbnhzb1o5TGdDb3VRRVZFVWRJRmkrNkg0Rmp0U0g0MmNl
Q1ZqZy9DClRHR3E3bzRCTHdDSTBOYjdWcGwvQU1aY3pLZXJkdSttSTFNCi0tLSBM
dnhlWjEvb0JkOS9DNks0clRESGxGeDB4MU1ET0IrSzQ5Qm9RMC91WERRCnjG+n2N
bOhx+OuMHdbNoLdj9zvnNkRkx2D1imvab1/F6jZnVD4qgDzQ6/pzlkCQ98Co6/Gn
LnLps1aJuNV/eSkZv2AifXDNyIfFRza4MHcSGXnE6IdpioIFQu+/QIoOSw2MLE/p
qka6v8cOATV7Bw2s5EFYw+Vp8pl7ZJCYbWEBYGW9M9OoH9EdsA30Uz3LQO/0d2m0
8qfYJvCoTVcLooRP4fH00Hu44urMyxft5Xret+BvE8uy3+Zr/lGseh8csjQlSO2z
kVmfjYemVy1MKQhJ49ztQ11rPI+DDgQiBp1LeGX1ioNRdhSr5aut+pj3gA8tm3F+
TK2Mqs2Zg6SfVR+UGeBxmj4LlysvX9GfMbWP3B35+eVcg9oD5iqltAEGczVD6H1C
H3tijabyFniWyriN8ObcYr2XladDBMedX6r8yWXBxjk9Jm99bvyW07V5ZbiZNQVw
R/C1ZBbwbWA6nxdMHftzXC8OBpaKY0ReQ3YEZTBVHC9F9X3W+SmC4xwLNsFdWMdL
zL2cPBs1GXX7ePaEJdylw4jEePRk2uCaPuApqwqNP4i/FYbOsVAaJBQsj5FW5e42
Qdea4iZ3fSPEyGCkq9fxiuUr01rWDqg0XOwe+xkNlc37RtWxSfjzThQdp94kkSO+
PX+I5chLgQ+XXeZOWy1aUDQ+tiefvnYKd3cHYq5xyILwVZ+qimq3dUXcNuXMOJQR
oMXHD26j8vjF+F6tp0/bclP6fqj70ODnJYGfpSeqKHT7MbLQHSL9F4OMZuiJca+H
1t4NdV7dVKm2sckjNS8UbQH5GER0U46scL/7oaqxV6R5FW/GZGrXYy6w+venHFSz
FhJPvBJVyoHV5Qa8dyw/3/sqG08oaXMXoRk4doEsaC/PnoSEv4KDfU9jf4uxrFl8
6E1M7HIx3riMcs3RJDc9O9fqaQOyz8bMdQl6tC6B6JNf7/+mgIvp/dZBmGVeaGnh
w920E918ad6niZs3yf3Zl3rXRj/0CEO16B6SwgP6Uovr3uqbMkVmV3vQIyuf00QM
4kr+X4tHP9pZXYMpdqwAw72JkflD6hAvDdLWDw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyB3QTU1
TEdvbFNaUmE4U1lCNzI1dlloVDBTNXdURjZ2akRMV0R6dm5ST0FNCk9YclRSakhT
NlV2UVJwak9Fa3dQNTNBK0xKWGlkNXdwZTBEMm4xZzc3azQKLT4gc3NoLWVkMjU1
MTkgakk4UkFnIGNBMHNrdG84cUQxd1lqQmJIczlScU1jNk52Y3BtR2tXeDNWdWRX
cEFCR0UKVU5vem5MZUFPbGhoQzJTYnF4OTd3OW9jYTRkazdocVJkZ0pRRGNLek93
cwotPiBzc2gtZWQyNTUxOSBnU3hQMFEgQ2RUaEUyV1ZGbGRtZnlIUEtTQXk5MUZF
djYxZ0hBUThlV2tXTHNvdXpVSQpMdiswMy9QNUtCb1hkbGRqR0Nia3FXTzE1ajZL
UXljSTZqM2YvbzVuWUFzCi0+IHNzaC1lZDI1NTE5IFZGY3c1ZyBYL1NrRjRaRnFn
RlNLdWJ3cThteDM3WmNaY210d3RmZzhCYmNpVXBwVGlVCjBkM0IzZC9zNjhmTTZV
R25ySkVoQWxQQ252WWFlWWZFMlc5dWtUN3VvVTgKLT4gWDI1NTE5IE8yUU1pWGFr
NzUvZVpwalB6aklkWmJGWUQzTnJiRjNzdzY2MUp6MkY5M1UKR1VIWDVyTFpxem5F
TmRNWE9zZStLanRTdlU5d0NOSEJKdWhDUjBCdy9vOAotPiBTJCd2NyFYey1ncmVh
c2UgfE4mYSBXfms0TC5FPiBiYmx8IGRFV35mciNoCjVZdHRiVUtMMWxEMlJ4b1F1
TGgxY01XTlZpTEtndkg0T0hRVjlqVUJGMUpSaE5tVlZWR3VGenpkUXY2eXJtbmkK
ZCtqRVN4dnZENXdoYkpjNHRWYXkvN2laY1p4YjV0WQotLS0gOHlEVTVOSmlNemNQ
TW5ISk1DeDlEM1RoQ2JtUFlyTXRKQjdnT0hiend2VQqrUFvr+76sKn0ldBmZMlEW
U2k85DLo2KU+/+GtbkZwVXxxIZHMLpoJgghHk9ptdalUgLGcl0X15x9jVaw8aeta
hbeOHotRHY7bC3z0S74riTk3xDMR1eT0QGhDMWHjfo8SkCftOYBlFfhTftevdep3
pKMZsuQMwH9JzxgUfcxIcWE975cZzrEJ85nfWMGvdSjcg51KNxP/UUPRxDlcbCEf
9XX5apSzNsTI3ibGD1n6Qwq8bdVYDMHmy5pAhw4l8L+SdoU1tGdw7JOA16sMCJbx
T4bV0ky/PGRonjJuCyDBj8oe9vMe1ZI1O/ITtktekS+wocxBs6QXlY7pIZMlGUn2
6m59ZEEaf7R4/MdnmBDNDkQuyXaKc7SaTc6h5sKWzXdYScGUKvgUQ7U/WJ2ItUTC
N/Xq07GkZZMt5MYBlyEr+/mKWlcy+ylJPGb7EswvQWaHoeM1QF0XLZ1v+W/Xsso0
seIoz+geSu9a02kwfsa8WvWXdIAT5X2pNGPClVNzjQ23pfQfQuW8ZQrGmIFR4g5A
58T1K+vGLdShqqVGyJFMVrSuOzqX5FVmZalu7/++1IQfiRGUlrHKoPlKWnCfFEOu
AYjaPeEFX2ByxcqfMK1YVPvUufdISUQeaQOO7mXGE3FqB0oUqmRIUiWZATwhq3Pw
p5QdcySTnmMpD/w05hvwski77kCdmYuHlMlLZez/kfhTnIGXris+Vwi/V19bsZ8G
zwaZ/Xr6WNC+df5JqSfTGREnXZPFRDkaTt3ri5/eEm6BqliuYjGbuiKsDECi4+JX
bHpH6LBBoKQ6ms7jCAn0Ls4cUKF37PcjGAOuWnzCSBU+REht1EDfHzx4C7hNiP8X
87NjEqJbwE9lORho0hQJRTn8uriQcidlVoB3se2SYKbMy8UA4NNnxN9PTj0TuQjL
OD3LtqHBElqNPbGNyyEAAJmMBmmkUvPPXlGQ0D99b1+jIdHzYSRtOLshBFykqWYQ
LJD61duhGqcQqcLx4+JdQ+oVcfAI2nG7YINnHB0OmS2DOZvvwqQ7ASScSujUWIjA
LNQxu3ruMz+bw/G0tYZBBiE=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,12 +1,11 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBqVWU0
dkhad0tteUU2emZ2alJXTE52TW01dVlIZVJXdmZmc0J6RzVqYkdnCkdFTWh2Q0xh
VU5QYjlYNnY3NXBDcitBNWtXSEZwRHZQVzRvRU9vSXpoNGcKLT4gWDI1NTE5IEdy
MGdiZ3dsMnFYVms4WUxab24rSFBPdHg3MUNSczh1WkpJMWFDWDJKMHMKOUhTR3lE
OCtYYy9MRDJlTXhWcjF5eU9nUnNzYnlyUE8xWmFRWjZpYWxzWQotPiBKPDpeQS1n
cmVhc2UgL0JIJ19KCjJSNFVhYlNTQlhGZG1DZC9DUXd5ME5idC9uU0hzdHpncllm
MTBHSmQ3NVJtV0JLZjNYVXFhYjhTQ1UvSWRDdTUKR3cKLS0tIDRDeHRMK0hLbS80
NmU1R1l0bVlLeW5SWE0rTzQxdnhSblRuL0hsL3dMTjQKKbq4CiNLIiQ5hnVzqRcl
NQkwDqWV5EZgAcnOKeSwyAQUhAo/H8lW08D3CLrZWknODWuKO4oPo0aDHam12QBL
a6Q/qn0OyiDDcGVHi8I=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBEcDNm
ajc3a0gwYmVSdkowak1aakJ3VWZ1Rk50S1JIS0ExVktVSW9OVWljCjJqbUEySlNK
a0xyT3NPK1BBMjZzN0RrLzhwVitvS0pzQ25iSnJSc3FmM0EKLT4gWDI1NTE5IHk0
M2pkWHgyMHR1WHc5bE4xWTFDTndKdkhRdTg5bzZIWEU2cm02UDZBQjgKUUY3dS9p
U3h1L1ZvTkFPdURLZ2tSYXJXOGNZZ21KVGdIbXdhSUJrd2puYwotPiAoL0RtO0lH
OS1ncmVhc2UKVGthN0ZSU0ZFTTg5YW9UOXMwa3RnSzFlMjE2VTN3Ci0tLSBwMEMx
Q0tQckd3SzBwUUE4SndMV01kUjVrOTdDWmxlcWs2Zy9TZk5yMzhvCrBXyLBZGuSD
dJodNI13obTM3UvX6hSgQ8Su+J3fOKr5NibkhQ0Auvlr2tUXhhDm2WOUlHjqVTq+
jWLSyhioDlIEyBgk8Zrl7KGeDzBi
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,14 +1,15 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBXdU0z
YnpQb3EvcDZCeHp5amlNVURIOW5YaTNIbHBsdERGdVlNMVhkb25ZClljM0JCYUlp
cHM5SlAvOHNBRFRrTW1DNU51ZUtsVU1xbUZSbkNmQ3lKNFUKLT4gWDI1NTE5IEhk
NUlaUWJvb2djK2x6MGloSWdXaCtOeW9UYlUwWXllVGJtbVRuazhIa0kKRVpCNXV5
WmtYWklBcnVNYnViajBQWWd3RnFSU1E2d0paR3R5TkdMWVdGSQotPiA9Qjd9LWdy
ZWFzZSB1JVREIUwyYCBjIVozRjU6ICg4KQpvcXkyRTFTRmVqaHB2WHJuUW1Wb2I3
RlU3c0d1QXVsZHVpaTBzSVVWcHhYZ1JRKzU0bzNnQnJQZkdoOTQ0RHBJCi9aelFG
N1dqVDZIQW1YNzJLMnYrQjZZajhoN290b1FqQllqRwotLS0gTjlJMUtyS3JhWkVZ
VWRWTnlPSVBIMmFEZ0U4YkpCYUpBT3hmYnZUNng5VQqSdcZWFUKsMsL/zJ2pd/09
drHoNrGw9V/MZe5uacNXcNxZCkBdtndYuhsnkiPPM7nTY6umbB+oGKfceiVvuDjH
4i2um6GLWLPDDkH8JuYbSlB72j5vkFLJf8N5ZwquzOg8VnXjrpnBFyhod1b1KL9I
18f6M6LsNNgOHukkT8P/6e9ziRqQrvuE/3Ave4lSdI6OcDm5
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBzaEo5
RzNndHBLMUl3Z2txdVZoOVJBbWsrTVJwY01WeHQ0VTBaSm5VclY0CnJLYStYNEI5
VTN3dEQ0ZjBKaU1PZSt3d0lldkE5VC9wNHdWazNWV2F6WWMKLT4gWDI1NTE5IEJ5
amlzTDhCOFF0TllPd2RsME5Cb1lRQUZPTGNvOEZnL1J2Wlpnb29GblUKT2t1NFZy
blNZSHdxZjlHTlZmaTFYT0laQ1IwOCtDZ21vTjhxM0owdTAvawotPiBLYS1ncmVh
c2UgRX0nVGtpSCUgNVNDWCVwIDBuPjM3MwplK2cwc2htQ2RLcFhUZ0RSc21uQlFV
Y1QwSStOK3lKYmVVQ0J5RXA3Zytaa0JoMWtlWU9qMHBLNktFZWxtbFpDCnJyS0JJ
WEcwbndYbERreFhLZlRyQ3E0czB5NkREancxZk5BTGdWRkR6N2NrZmFrbnhSYlZZ
NElHNEEKLS0tIGVLdXAxU0ZaZVkxaHV4dEZNNUVuc2J4N3VRMzZzTktSMDY3bDVB
bWtmUVkKigIZ3J0s23vNzmbzJGjSMGBXK6o6xnsA9HXeQZ13VgKv5Qv+UHu+Z0g2
TeKdQSrHbDB3ydIxaiXsi2ivULdrIMCyd96rEJFxrkVuVqSZE0ehG5j+o8lKk4OU
PDe70slbZrVYDSu+OOUOCVRSopZreCURlYn2Pc4rjvrMAn5r1r+/AxjZMdkmmQZ0
l0wMBTus5zZzKg==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,14 +1,15 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBDc1cz
Q1oxbGdjRkl4S21jVWYvMVlEeUpBM1E1UUYrajAwaURVTkkwRkVVCm1lM1JueUNi
Zk5iNjR5dnNtMmRLMFI5dGNzc1crZ1ZIZHd1RTNwbTg0UVkKLT4gWDI1NTE5IHI0
STNjSDYwTlBZc0VFN2hCWlRCOWF5K0JENXVDQVJDNmVPeExBck1pQ1kKM0VEMGhG
cVRsNy9zMHpVODJrNy9Id2RuK1NRWE5KbjlaWkc0Z0RxSGs2dwotPiBuQzR7LWdy
ZWFzZSBiPSkrPXd7cApmdExmdm45eVNaWHpGeklWUWU3elZ0ZzRTN2JrZ2xDejZM
ckdOWmpSTDNRZ2JPaDAyTGliTS9mOGtPTkppdVc4CjhLRms3eVNVc1lXSkpoenNq
ZwotLS0gUFFwVlUvZ3J3bEJvZEZMMWc5V29nYkR1eW00ckJtcjNLRG1BQktaSTIv
dwqes+5a5N4cGdVozlP3LV8UgbKh72dE4rK35Els82L6669nuBOvR8irauexjjQN
Tu687x1fKdDJaxTd52+hEqhcHXPLJ80ZtTmZxRyzaZs4sc3jcCBW1O6OEm+c8JK5
CstmZW/ZiFAgtNb7TcrUsfOznRrr7GbFOcQQ0ZXP6pjP3mtyNGWzZ+jmvIJ8hQ66
qfvaDzFM
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBoZUI4
bEdWSW1pcDdMYVRJLzdQOWhsdTlZMmlyZjRVeEFwU3Z3NzVFa3lBCkxRZ1FYeU9D
L2dramp4WFFlREZ3NTFnWUs3clVEcnBhLzExclVac1M2SG8KLT4gWDI1NTE5IHVZ
bk9QYy94Tk50c1dVanNvNzhpYWNqeFMzVVR0eTQ5OXozMmp2VFlad2cKaEdvUnR5
ZjhsQ1FRaittQXFkbnRZei85MmtWb3pXRVFsc0RzNzBPMXFMWQotPiAzSXJZb0RE
LWdyZWFzZSBudCBGIDklTWIjVnwgM3YvCjRVYUd2TForc0gycnRBR05MbU90QmNu
dXlmQVB2bnZyME5heXlyMUdGTmR6SVd5SHcrTThrZEJYRlpnUmdmWnkKU1lyNjQ3
T0J6b3NPQ1FYZnhxTjFrYmN1UUJzMjEwcDBwSTJkTnlmeHl3WmFFTXB4eUVMWm9i
NExUZzM2SHlLLwpiZjQKLS0tIHdqakpMSUNOdnlBcVA4RGJHR2d5QnJNT2dVclZN
djd4WXBLSUhORktzZ2sKzMjxqL3UPrtGmXDijdfu0AwxLJooK7ZKauYvXWSuZUrR
vl5i1QPMEEBYEl+NaZIFgxAFqWpAXHQ1VxSijMWxNjKUd1Chq0tbLrpbh9wXJflK
SW19Wyqc9eTb8BnFoOSYWpDvAs2Lbyr2kJkOj2TNrwMv8nDJdOB8XIPlV5drCj1q
Dx/1zWqm6NMYxsep6eZkv4AzxA==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,12 +1,13 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBHMm9U
RjN1NFhXekFFLzRKMHhKQlEycWhTQ2VYSFdvVU54alpXL3doTFdJCkpvQWUvMkVD
bjduamVxYjluUVpmZW12eUordEhJL24vK1cyajFoaFV5QlEKLT4gWDI1NTE5IHVH
SEtKdXFoRGF6b0ZRdDM4b0ovOGlUVTlIa3RidnU1TFliVE9XUnZrR28KU2NydUVm
Z21oVWhiY0RONUJvLzRaMjUvZ2plYkowMzBmTy9EQzVBN3JROAotPiAiIiM3T0xj
LWdyZWFzZSBra3FnOyh+CjhOdVc4S2dDYjVlT3FDV2ZFUFpMTGJUZy9YQ0lwVFhD
MWJ4RlFOSE0zb0VBdWw0aXBpdkhEbXRxalpHQ1FicUkKek9SdDRCOUY0M0JvYVEK
LS0tIGJvc252UTJFcU91NmFkTVpFQ0owTHljZEp6VFRITm13QTR5bFlIY2Jub00K
AfBoa9IqRVJqI/MGSJOhraKctjDtAXQFqPtqOZtMjYS0JBwJL0Mbne8uqDBb5dTt
OjiPT3jxovReurqn9TC7fDxEfpravsCD2cPQ
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBrd0pM
TGw1anJNaGoyQ3lMUis1cHVtRWFPcFFNZk9Cdm9TMEh1QTdKc25ZCm9VNzVQcUxE
Njh2Wi80RWszSU5NczRNcHpVYXpRMzJNcDRsdGxyWVZsUDgKLT4gWDI1NTE5IFpT
MEJVUkcycVFJaVFOUURoL29VT3R0MVJCWW04NXVRVEpKY3hlY1lWRkEKcENya1Jx
VnBCMVBrZkc4VDkvMnZoTllCL09vQ0VOZytuMnRvYVQxL2FldwotPiAzLWdyZWFz
ZSBCNX0gIiB7InIsfCAkOT9uM2UKUWpSYTZ1dUo3SHNaUlFibTl0UDhTaFh5Mk1n
bFp2cjM5RGhqU0s0Qm50Zk1pUVZmT0R6ZjBoUG1EUGlKbHFzVwozQ2t1cWVDVVAv
Q21QTjF3NW5UdTBZRldnL0RmSlV3QndHcDB0d0lvZ1RHTTByS1ZwNkNVQnU3WmVn
ZwotLS0gb0Fxb2FsYzgwRjJwSUF3ei9hZVR2Vk1ORDlIMWoyZ2RTd09hUmtvMWpD
cwrEjdaYfoGZ9i/S97xL9QvA/yii+sJLeuUzzv7a3DE661eQ5ezurV8Qz1tIhxWG
RsOppaaj1podFx3U1x7QQbLO6zQbJA458RMjYgc=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,11 +1,13 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBiTUJJ
R1J2c2JuN0RKR2NxbkpFanIraU9TbjBiNGZGaVlvdmlidlNRZlNnClFESmN6MW03
c1NyUCtITUdrVmJneXhxVHdMeE4vTkJWQys4cmZMT3htSzgKLT4gWDI1NTE5IHJH
VVAwSVFmYnZsSW1aUC9GMUxMMHM2Zk9BUHFWWE4yY1FIWENRbnZFbHcKTWc3eUpD
U0psQVRCaU8xaE1xNW5tNnRaeWdRT3VXL3d1bDArZ0xPTFFDUQotPiBAXUkpLWdy
ZWFzZSByMGtJIy9LIDFeQEggOV8wXiBrKzhrZz9PCkcvNkV1UldNMDVCL3VhNmUy
QmptQnFvCi0tLSB1dWZFQXVvV2NQdVB5c0toWHppcDJtSDJJMWlsalNUTStzcjJs
ajZEZ3I4Cvuto58XMLkBmj5UQ1RRvnQGmpqtyyWgSOR1EC6BxpCUJ7UFuaJt8g5W
/ySWGj3/EJOM10hy1X2ORlkmiqyWks32vdVZ/DY0At1X0w==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBHNWg0
WGRGZnlTdEhsRm96T0ZMOWx4UUxkTitJa3hMWDE1dVkreEtEa0RVClpvR2I5NGpz
aUF0N1VZU05oWXUzTEI1TVBLYlVVang3Zzgwbi9teDVlQlEKLT4gWDI1NTE5IG4v
OXRIbzhaZEdXc1pjTnRRWHVxc2ZTcmozSlJkY3lyOGtvd1BVeGprVUkKdUNqSW94
SUIyOWtsNU83cnVOTUxNR1BvWHJPczdzUWc4aGp1MjlpZm5ESQotPiA2KSV2PVx5
LWdyZWFzZSBqezVxOHc9biA+aD4tP20mXwpwRCtMUDhmcVhGNXpCZlFmSllpdDVp
SmFZelNhZnJlR25DS2l2MlQ3ZGFtdGxkZEdEWVNrRlk1VEZBRm9GMHBFCkVlQ1hp
WnhOTGl2R2s5RDRKN0p5TmF6Y0cyN3ZlR2pDZlhMVjQ1c0FJN3hCbFEKLS0tIEFT
bjFiRStXMmJueHdsRm1nU084dDRpS0tBT21ENzZFclJXbE11NWJETm8KyMHU+tZY
QELtZCbXKWnP8QC6V84JIFAxoRslACwsIJZpogcZO/IFIV2RGunGjCJk6QBmhOPV
kJXRcGO/ndYjWfuU0U3+9HtPocnO
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,13 +1,11 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyB6cVhZ
bC9XWlI0ZlR2UXBZV2FTSTZYQmJ1WFk0RGlNb2NFVGVlTU9pVENzClhWOVQvU3FS
TjIzWlZGcTlCU3ZnMEFMR0liMmlSUFc5TlVYdmNjT29uQkEKLT4gWDI1NTE5IHk3
aWJQK21VSjVkQ3VKVkZ2V29EbW8vMUk4RUFVMGlNR3VEUzR5L0xNVGMKRjRMZ20z
dCsrN3BnV1dBSTNxMkU5QXVLbGo1TGhmVWk4WURJZUFMa1hydwotPiBQIT84UU8l
LWdyZWFzZSAzc2BWViByajU8IG9PUENud0FVCk5SQkxTM1AveHk0MlRlQS9XSmZo
RVUvR2Z1Tm9jNUE2N25DK1pZU1NVWXZNRkthcXR4MU1tdUx1czZqdENTaDUKWXZC
OEhQWHdYTktqeUJtd3ByOGdvU1FUYXdtK3c4ZGcxVGRDCi0tLSBEajZDNlVBSjJa
b3k3MmVhUEp5Z3NaeWZXdnZ1UEpLUlFzNndzNGtTOHE4CuSUBEd67OnVhX47nGhB
tRVCS+h88eK5HJD5rzh8WOW81E9Jx54QdnNUAgRhiVTo4MUT1EknoUIHXJqFpQjh
hvpf+nVCCD5AKTpjufqcATo=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBOZ1RV
VVpOZ0Jhd2x4YklMOHdkNkd0MEM4ekZiYXFKMjRIdXlZVDFkOTFZCkRreDZlK3Bo
WmJ1MDBxSU5UYzRuUDMvdnpVc0prNFF4MjM0M1FaZmg4V1EKLT4gWDI1NTE5IEkz
THNsVDVCbU9KYWpXL010OVRmNjBVVmVyVzhRZW5McVFJcnA3ZWJvZzQKOE1lQnVX
Nk1rWVAvS1lpbDEzb2ViUUE4RlB5NnJOZmNoUGdUMGNuMk1iMAotPiBuYVwtZ3Jl
YXNlIHdYXzh3MSB0TyREIGpdTjheeQpJZ2pYUyt6UC9vVmRNZU1uaDdvR2ZUNG0K
LS0tIHNCRno2V21tZU9XV1UwR2IvZDdkWEMzZDI4V25Yb0lvdmJadXNEZFV6TEEK
81uT8S3QJNe+mVadi/VpXSPEP0Ygzm0/+1pB5qqYlSQEWTHqS55gCyFCwu+sjaDq
DpYTSm1JAk5ql9NRj4fJvCS53lJZ4zo+5c0iJKmuRg==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,12 +1,11 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBIWXYz
OVRObmozM1dydmxGR1VvaGpLYjFEemFGU0luMVMrc0lCYmx3K0FvCkVQYlY1RDFo
K2cwVHVGem84VlFsZzZCOGl5WjRWQzRIOGd0SFFLczM2U2cKLT4gWDI1NTE5IHdh
eHVBcGc2czZ5WFR6cVd6ZnBCVnVvYUlabVRxYkYwalpCblhyM2E1RUUKcnkveEtp
Vkk5REZiMFRRYkpTd0VIYlBnK0cwRDEwSTdyMjJWSVo2WUc2awotPiAsVVp7Jl56
LWdyZWFzZSBNcTpCMDE9OiAsbDVtZWEkIEJXPTM/PUkKTVZmeE80V0k0RVdBMDJE
Z1ViMkN0eEZDOUlHZDZUWWFmdU0xY2U5T2pnb2NTdzExQzJkd0dhR25BOG8vVUdN
awovK2xzK0EKLS0tIGhTckhmN3ZOQSs1K0NyblBGV0paWldqOEFsMlJTWHZuSDll
VjdmcnRSZVUKqZIgJl3Kef2Vl4hTraEND7TuwI8pl+NZFec3PUY7mVxXpQxfkNtg
FZeF3b0VRvVBnA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBBOVJi
SXdGVDlXWmVGZUM0OTJPUWFYem5qZzAwZWxhNzhpT2t1VjdZU0ZrCjYxWUE2VW5o
cGFLZ3g3Y3BpUWlWOUtUYTg4MGZXVHZvdVV3eU9iZW0ybE0KLT4gWDI1NTE5IDIw
QmxaWTY0WjJFZUd6TUxqaHhRelpRQ1hGZVBEcm43d3JYUVhpTWp4aGcKVzhJdFFu
SEhUUUZVNVk1N2tzekpzUS9RazRCcFBhb2xxbkhRNEwzVys5cwotPiBkeE19PHEm
LWdyZWFzZQpwR0xsb05JVlFXQTZZQkJSWHY0akNRdjh1eXFnbmFDWUlCM0xLWXBi
QkVuanloRQotLS0gZTkrT212MXdsZy9Kb1AwMkFHU3VsTElweGNlYkZ2UWVXRzkr
dnB0SHRnYwrveLSY6SdUDO+QH7WGniLIOPcECTQ7CiTj9lwD5Hm0rYLdvizolb33
CsGX/kSEI2bD
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,10 +1,12 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyAvZUJz
RXNGUVgvUGF2ZTV6cUhzT21zcjVlUFVESkhVTEZyQ2Y4aU1NUUFJClowczVvUFJu
SmFzc3NHaFFrSm5EYmRiSkc1MVljYk9yK3pKNjFRWFRBS1kKLT4gWDI1NTE5IG1O
Um1Yd2ZxY2VGN0tHK0J6UW0xUlBVc1Joa29LOGpsNlA2aWlhL1lHaU0KZTErSW5Q
TmdpUW5tWGxwMFNZOGsvUWRQT2JUTzFBdXZhbUdRaXd5YkI3YwotPiBaLWdyZWFz
ZQoyaXdEbVljRlQ4UDdCc0NICi0tLSBqVGpDTXV3dS9YcHp5cnpZTnJYUGUvT0s3
dWhGcVpKL0wwS2VyVlFlWkxnCriPULjxyfA41HDGsmqGUQvZMmQmWZE5aFoS5p45
7I2BuDgNW9xD5gcMyADCeSDYLFQ=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBrTW1E
ZDFSRXIwbXZXUlNJbHZCVjFzMzRxTmdtbDQ5eWVOWWp3SEdSUERrClVMeFRLOGUx
U0dmT2ZUUXlCSGhJdE5ibkZLMmZ2VmZFWU9PQXpGZFRPQkkKLT4gWDI1NTE5IDIw
VXd5N2EwTVdhdkRYeVF3c201SnV3TmxnUGpOZWY5bFJaQWRWMWxQVmMKR2RNc2pE
aUs4ZW1XSGU1RzM4bHZYQks2cHZWUkhZN1hob2d1QnM3cCtlMAotPiB0XENxMSct
Z3JlYXNlIC5LIEIoJ1w6Ci93eE5lMUxDQjE3dWI4a05wUE5sV2dWN21ZN2lFRThv
YVJGNXNWaEtmbjVMaXhnemVuTXhOMXFtNkQvbGNuS3oKalZ6bEtGdHcxYnZNb0Zy
YnlGTDdoVVdyeTJpYjJjZkc3alUyV2ZGa0taeEFIYTdiRnZmYmRjR3BzNUp2Ci0t
LSBROCtSMzFNR3hTK1p5NVhGcFpqM0U0L0MwbWpzNUNTUWUyNEVXbzFFMGpjCnot
A6mYbp+jhpoyjZidXQfzLVcu6y34WqAfJZsfT6l5SJONVfSvSw+iP7XXW2T5OnE=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,13 +1,12 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBVMTZr
OGZjMlJOZVN4WUpia2VWK2lCaDN4aEdRWUFrWEFaVWdDMkRuYmcwCjQrMHVzaEc5
a2xaQWhQRXhJSGpKQjR4NHpweldvYnV5a3F5ZXhPbDdjcjgKLT4gWDI1NTE5IFZo
bDBKSnVFT3R6VllnVHA2OG5OTDZvakVXdmpMWHY3Tk5EbkVybnlRUnMKWnZsY25u
MjJ4cXJmSVdLVmx4V1lJZ0wxeWFGSk1mYkh5QnIvaGFpSzZnVQotPiBaIUtVSGhT
ay1ncmVhc2UgISYrWiFBIFxEdz9ZLGVWIHYsNGpMIDk9dk5JClBqSzNDdkhrQ0V2
MW1JMUNTT3N1VHJRUjZHWnJpQ05VcVpLOGNxM2dJdkd4QmF2dVc5TnFkalZzOUVU
OHM3dWwKNVpscS9Pb3NicksrZnFQbVNSd0lndjZTYzJLZEMrZTFDcFBVd21qMVRE
SXlLTVdoSnRpKzhBCi0tLSA1cXM4YzJtRUJPYkV5UnVkSUw1QW1TZ2lWS0R4bjhM
cXdrV1FyWE9JaU5BCozLT73zDlLthpJyWZtONXnfgnNT7ukuG7mF0d3eaevD6RYW
O8vs4vcc842JpxvSpcI=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyA3dDEx
SUw4QVh5T3QySHFFemo2N1JWTjNCSGRiS1lmRTkxVEQ3S1NKR2dNClZNM1Vwc3dF
elB0Unk1OWpUb1RQMVpSTUpJUDNrZzFMWkhKK0l1dXVBYlkKLT4gWDI1NTE5IGRF
TTZlMjdaamlwTUJzYlVkcVIxbmtybkFwakVtK2craXVBNVZraGZ1VlEKN2VvaU5r
VjNRS2I5WE9kVDhES2dWTUV2cEVJaXZxNzRUcFo5blhGTDBaawotPiAxXCJQemxa
dS1ncmVhc2UgcDphKHFVTGUgIUonYydBPgowQnc2Wk5yS0E1bVBCWmpOc25MWWs2
UTR1dVlJbnNXYUVJSkx5bWFIcmtpT1lPSVE3b2Zpd0JaTGZWcEtjelFDCitQcy83
bEVvM3FNTEhyWVVFS21tS0VQWG5OOHFza28KLS0tIEZZeUZwVGxUdEdtQTZuYk5K
SHJaUDhHZ0JqbGNFSjJCaVlQTVo0OStkMWcKz/w0SnoHxnw71gr5DbXgMl59Kgjy
SW4tzNGeRcX2j4YdRjr77TP5UAzpQE30tEcrtw==
-----END AGE ENCRYPTED FILE-----

View File

@@ -0,0 +1,13 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpOcUlvZyBNalB5
RUZRNE1CTUJsbW1kSkxBSWVIcG1RUnBKd1gvcnRQVkZCUXFOQmhvClJUN2ltbnNk
T1grdVJSTzIyNTBTTGVEckVGQXdYNHdwOU5NbW1md3lGM0kKLT4gc3NoLWVkMjU1
MTkgcytxUmZnIHZ4bFZSS0huWFBDbUhNcTd2MFhvV0lOY1l3d3ZXNU4vT3dwMmlI
emhoV0kKcDF4M0FPK0JpclI5Q3Q5WGxpZWVYbHVWbkNWdTArclZsN09XK3VJSXc1
awotPiBYMjU1MTkgRjRCNVZmcXVnQnJ4KzZoM1ZkdWxYUkJTM1JuK3ZlRWJYdkFR
WXpFSmR4NApTbU5qR3ZuN0ZmbzIvMTFsMkdNSGJXSVlrVmZPdnZvcHFiZW45SW9I
endJCi0+IDEoIjlcJi1ncmVhc2UgJUE4IWl5ODkgfGVdLihEfT4gWCAreSduPS4K
bkI2Wm9LRGJXdW11aDl2VgotLS0gTENqYjZEUUZaWVZEcWQvWW5yTzJEdHRLeDJm
QUl5aytXdDE5QVMwVHZVSQo+aDbaGNOrz+hTSUQ4IAjDC9EfNwrlXDZtBqw8HkRv
1/Rr737scjrM7Bgt9zuKn6CB0zdeHTW5u685V2hCW/3aTy1eppWMWj3r
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,11 +1,16 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IHMrcVJmZyBwb1Ra
NTAzWDhCYkUwamhoZ1d1eFFhSC9RdSswZDZUZTZuR2RLK1BUZkZjCmlXcUYxNVZ5
bnZHcEs2R3NLN09Wd0RhSGVlQmhjcWRxSE5ia3hUajI4N3MKLT4gWDI1NTE5IEhv
WU5Pc0FycUdWL3pqeG5tN0lGbXhVcnZ3YzBWYVRMQjl5SXQrd2tJbXMKZkxiWHl2
ZFJIc1dmN3VIZjFQY2o3WmpWRitFTjFFcmZ1WExGZDlEaTM0ZwotPiAzcGFZUi1n
cmVhc2UgKDAgaCAnNiYlM3UgYzFTXDEKMkFKRWRtUQotLS0gWEUvc2drOG1vNnNI
N1BWS1NXQXg0NVRMUFc0WWgraVhnbkpuMUNPOEFOdwqYr2C5El+K2gTiD9Ssnmkl
Dh/whzpy0DAl7Kk0A5FA2LOfkxB/bgm0FGHwu1pxpvZWvxTynyX7Zikhd9T9PxUs
SYQgsngQTC6Iw6s=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpOcUlvZyBFb2hL
MCt6c0I4Nm5SMFhEaWNZRTRtNkpYeVQvVGFVZzVqd0E3L2dZdzFBCiszUXZSVENo
cmxqdVFwMFA0elpFOGZoM3B6SW80MEhCNlJoRXV0WXpUeG8KLT4gc3NoLWVkMjU1
MTkgcytxUmZnIHQxR2MrakZmRFJMcjhabGFON2xQU2RBSDNvRCtuV3NwNGJ2bjZF
b2lCQVUKcFNzM3paS1ZnWk8xY1VzVmdTWndMK0JCTU14bUJvM3E2bjR2TmlTY2tF
NAotPiBYMjU1MTkgY1MrT3ZkN1pUd0JVb0JWSDByNUNRd1NUd2ZiNVJrc0JCb0J5
NENrU0MySQp0bFpwRXRZcHRVdnN3eitkNHlWc0c0a0NmUjVYSVFXSVNFVHI0b0ZB
U3kwCi0+IHQmKm9ERFdfLWdyZWFzZSBJIFkvRG5JIC9ZI002bmkgNX1hQHcKc2l4
S0N4YzgvK2xqZm1YVkl4ZlF1REVOTGRWOVZRQm80R2NnczlsdFlhTEd1RmVoNjZa
KzlkVXNpbGZsNTRybAp4RDlIWmRqR0t3VjF6WVlSeTJ4aGZBd1dDNEpMTUhZenZS
WjZCK0FZcXJORkJwc1piS1FvSlkzc3R5T2s3Vk0KLS0tIDFPODlkZ1BSWEhHUHJK
QjdZOE1KcFNvcUYxYlFkL1FLNVJETTkySVNYRTgKOipmWGTV9SvGE4KVqgQqGw4e
CLP4PYlgdSmOATTIg32G/GVTM8NlvaII3q2GNS0Enx7Y8YwnwS2dGkYKVN3Da3b2
WJwMiBZRu/PC
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,12 +1,15 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IHMrcVJmZyBvLzM0
VlpuL3I4OUYyQnhXK2pGTCtUdnVFWUw1KzVMdDJtZ3NXb3dCVXlJCjhIYzJKYXlh
blZwemVTcnFTbHY1QkViUVFZVVZ2TzVWMW1XV1FiT2Fkc2cKLT4gWDI1NTE5IHdo
NEViNE5TQ0NzUEdtc3h5YzVvdy9GN2N0Um1Ebm9iQ1BFQzFlRGVIVVkKRkd2YlNi
QkpJOEgrNjd1ZEpHd2FNSlFuZUpMS2czV2xVTDFmQjkyRFVDNAotPiAie3RkP0ot
Z3JlYXNlIHJZK3RgezogSU5iZzJECkd3akE1bHVLOFdSanEvdDRsb1pUWXRLczdj
NENMYW1MWm85VVkrbjVZVHgyTURCOFZnbmVkQTZKa1lOc1pyOW8KCi0tLSBrQzdP
WngydFlQTEZpRHJ6VEZMMDhQMVFsUTN0NmN0QU45N0FUQ1M2cnJJCjpYZlk83/mf
ZEzH+9fcVGlBOneXSlIDb8haRDO/8uqcIfaUGjIaGbWb+8XsVJB208/+wY6Eii37
Y3AMdP68LuPxNcuyc+bXSjUV5A==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpOcUlvZyBjbUF2
VXYyVkRud3JFU0tDQThjQlVMTTFaaW5uTkt3K2dmd1pleTFOQm5jCkNUeEVqSXVX
RGUxcU14Z04zMlRubVIxV0VwazhlZlFtTCtXT2dVS3l4b2MKLT4gc3NoLWVkMjU1
MTkgcytxUmZnIG5SRTFOWWVIMU5yK3VTdkVtc0VYNnFkRXFrdEpiNTJIRHBvVnky
OHRyWEUKVXVvZlBBR0dsUXFMa2dSZ1FWVWpvZGlwcHJ3YXRscnBoaU1FWlVFYTdt
dwotPiBYMjU1MTkgMWlBWCtSU0I4Q1I0T0JrZ1ErYzlHRTZsUHhZQkpYQVJGNnFy
U3ZPeU9RTQoxaGZDYnRaNjBRRGQzMGNsTmZwcjhBRXdLeEFqVWxoT3hNNHk5cU9C
Qk00Ci0+ICF8Q0EuPSIhLWdyZWFzZSBKcCp6MgpaTXQwdEllbmhRVDhOQTdpb0RU
T1VGZmdZK1VEMWdPUXduYWQ2YWx5aDFTQ3ZzRnRWbFRGN0lWUU5iQWdPakpZCnl6
MnI0SE5sS0x2MUZibW96SllDQVVOK2grRldPOWo0VSs3SkFUN1dqS3RqTTdPZG1M
eHI0T1BHK1F1cWlINAotLS0gckFnWkoydklhWHZhZHBkSkN5ZmdadVdiMU1QOUZW
VkJENWlHVWNXcEVsWQqYscIBmSi//ev3IN2ax0Ei7p8Atu4nYQui7yoY/1fiyGQL
DB5+R9Dm4YUNHt3bjrBYclLohDGdLUnOB00BXUqNmlLm4psL4Ey5Go8=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,11 +1,11 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGhNYTRudyBQdC9R
enJPZ0RLeWtrZ21XZGlTWnRMdGdDKzN5c1VteFhOV1cvQmRXVWc4Cno1M2dOVXlh
anpMTmdsK3g0eG1pcE5ISDJIb3NVOVZML0puSTlEaWtMSGsKLT4gWDI1NTE5IGxU
aWlhODY4aTVrWG9Cd1NPYzFORHFwTUlkSmVBNm00U3BtRFVBQjN3RHcKWm1PQkda
aFY2UDhyUy9SSCtkNXpxQzVrNWJUdzI0YTNrY0Y2YzB2QlltcwotPiBsLWdyZWFz
ZSA2YyBNNksxVTwgfkRvQkkxbSAsd0ZdU1BhCk1VazRBVlAwNysremkrbHoxZwot
LS0gSTd1UWoxeTJsMHZsWVBHcklOejFZdnlYZU9ndmhlWDVtSDYzdEx4VDZnOArm
nUspT8mk2F5sszqhdjGtQ+sY6fNzzeYGDiq7dDzvFIMxqpCivwF/QtBr7KYovoeH
V3Gv3CToGo3ZBO6FLxXjQ63QQdMBbhIQYZeJcQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGhNYTRudyB1N0V0
UW5ZKzQrSlFUMnR5QUE5N2Mzd0FvK3JCeFM2RVRtUklVQkNkU0dNCnJuUUxjQjcw
NURFOFRWRG5WSnBPT1dOVjFNQWZVUjJUSU9WVTExeS9XZkEKLT4gWDI1NTE5IHdq
eDhJSTZKN1lQRXNaZzNIWEx4NTZINzZpdFRPZWJGcys5SUV6bmc0Q1EKeGlqTjF6
b3Y3ZWNhcjF4WlpOcXh1OHBucmNCZmp6VTI1MXRjN1FlNlA3VQotPiBtQ01Dey8t
Z3JlYXNlCnFKKys4Y0I3RkE3bzl2NDJ2aDNMeTRTUUU4dFFwelV3SjVReExnCi0t
LSA1QSthdHR0cVE4bXhiczZqUTNJdzkzdnZ2TEpESWwwQ3BWNnoyNmp4ZXdrCl1g
oNwCvlTrPx5b5l0OUymxMo1HMCV9fsQ9zyaoJoPFN1hv7l4hjjX5oVoj/IdTJbbe
ZMs1yqa7YbR4+HG9GG8nPhU36hchSN2whoz8
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,12 +1,11 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGhNYTRudyBuZWR6
N3VBU1d1WmJ2UjFNaUgxL3dJMU1hZVlGUW54NnYyM3BsU1pOUXhFCmZpYTFTT2s2
UXVFQ3ZSVUN5dktEMXJFWk9pYWU5NEk3RGlCRkRXdHhvUkEKLT4gWDI1NTE5IC9F
WEh3MzRoSnowTTFaNW9ITkt2L3BqZ1N5dzhybytSUERnSExHNXVlbk0KSDZGd3hT
NEpSUWZwNG13OGJ5TXd5N1IzSHZta3JHd0hKVUlrZWo4ZW41OAotPiBtTl1MJC1n
cmVhc2UgPjZ+CnJXTWVXM3dNWGRXajhTOTVWK1dGRGdwOGtubG1nQmtnbU1VMlFt
dTlRUHN4dE5JREpVeTVhWDVGb3lnbEtZT1EKTkxwS0ZSeGxNeElyOEZhUmtacEhF
VVUyRmcKLS0tIFdpMmRNcWlhcDVEWWJTUExUQnJxY1BZMS9SRXNMWU9mSmVnZEhO
QUpYdlkKrNMg+0131P7eLgWVrsBL7uCblbgPq8/JrMnabnvPsevbqcqZ/sf0XHft
eP4jbM8PGKVIAyycjTR05B/Ocvjas9cE/5PpcpaqT2MVOmM=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGhNYTRudyB6dGZN
VDF3ME9IWWJMQUVrbmlKeXhZbzE1THUwVWhBc2ZBQXdUUkpod0FzCkVncGlyTXVv
bmxPN0F3ODdvUmw3Sit1cERNTXN6YWZlU2IvYUhoUThER3cKLT4gWDI1NTE5IGQ2
RzdCWUw2N1BHWVhiOGhvNEdzQVlUanR3emdDV3FUTFRXUDB3RDdrMmsKZDkvWWgv
MFZhbHZtVDVQSWVEQ2NxQUZrOXFMVmYxbEU0STFJTVBzZm16ZwotPiB+Ty1ncmVh
c2UgMnpCPlV9ClY2TzJGcnBrbUJTU3lyNVlrNDdwYTd3Ci0tLSBHaU9ZVnZoUkx5
QnE4UXhMdEg1elE1dDRoQWx4bDhBMHNwS1BlQkRaUm93CspT9YnuzfpKxC9y6SWJ
JRyT8aFEJTjoDEqN2I/DBwRikSxKyspHi7grCwFaoofylqJzsP/In7Xlf91xbMXz
njjXbBQQP9PG3Z2c0OHk
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,11 +1,12 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IDdXUTlQQSBtL2Rk
NlMzRmhHZk81b2ZvSnVQcVlVUmFOUU5MT1gyQnlzcHFZd1dmWUNrCnBRYkRZRnpE
RjJ2UXpLZ0FXZXlvbGhzaXh5MGlzeTVmM1k3MWc0M1JqVW8KLT4gWDI1NTE5IFhG
bDdrNDlWN1JyK1VWQzI4Y2RHY01qSUs0WjJiM1FsZThqTUVvRUlTbkkKV3hVcVdm
Rktmc1ZDNCtHY2JIZWJOVXQreTZmMi9tOUhXZ3NyVW1LQjArNAotPiAhSmZYZ0k0
LWdyZWFzZQowSHlzTFoxeWUwdHlnVXcrUXN2eHRzZ29rVEI3VG4wNjVaUHV4S25W
Z2VhMU56NAotLS0gczZ0NUx6eEFnSUhxTVQ5VHdUNUxXM0J0d1FuczNUN3J4RzVr
N3JFSVMrWQpOmxXeyAL3Vzx2ZQ3nTyg2frLthjvgRHqDUjD1nObOjIuGq7uaGZiP
ejuPVRJD6JIeK/uTvPlQc/D7JZocNQ4x5kcUD+S7VYXjnyilnw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IDdXUTlQQSBaUm1C
WGJDSUNtTUYxbHVnWU44VkRnY3F6cTR0Tm1EUEdDYmltWHBrL1dvCnMzSEFqZTdS
K25tMkdkNEZ1dGhBMVhSUkR2M21EY0NtbnJjb0R5RVoyTDAKLT4gWDI1NTE5IHhv
RlJOd3dCa3ZaeE5JS0ovV3ZiY0N5QThNSi9LaXQ5d1JIa1UyeVFJekUKd216RGw2
Szg3VG1PWUVweE9udFpta0gxdWx1NEU5ZmNwK3hMdHdZNlB6SQotPiB3dlxKIXxG
LWdyZWFzZSBCLGsgWCU+UWwKWXVYQTBqVkRMKzNsU3JuWmlQdVpzdWJWcVdwVUM5
aHpmZFVPbWlidHJEYlN2M3NvUWNqVgotLS0gZHhwUlE3YXJSdHFkdFpkTnh0bC9a
TytZcmtxd0pldUg2YUEzMFJ4QjR5dwqaUnjT3oaUunudOqNfh9twKyaRttf4sk9G
uiiKoEa314HbI1vgS4iCNX4vG+468SECiF9llZL9U1w+1MSF1y1BKy7XrDCsp7Xs
HiA2aA==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,13 +1,13 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IDdXUTlQQSA4K1RL
c1JEOFVGTGlhdDFJVURuU0l6NmtzNUQ1YWRkemdidnVMZmt0NkJJCmNsd1NKeEtl
OTAxMWMyUFZzV1BSdUdZcjI2Rzc2OVE0bFVSNTZyZnptbmMKLT4gWDI1NTE5IFA0
ZU5qSW5FWmFWaEttUmIzWFpBU2JlcSt3WkQxOEo3SitrZzVKZ2RSbWMKT2hITkFm
VThFZVIrdlB3aGRUR0VrajF6RGI4L2xBMTRZRjMwb1Y0MW5scwotPiBVdCFqLWdy
ZWFzZSAsCkF5OVFVTFgrN0QveWEyNkkrbXhabC9ZMjZWUXd4OEpGdXhDNCtqbFVT
dFlHQStNaTM5YmxUMGZtanNKS3YwblUKcnREQVFzcEtHYm4xcFBsTG9WYlRGeUFZ
TjRDSFdsQmZlVTZGRE1OeWRVQitYbFdsSUEKLS0tIGZTbGxid1RTTVRKeFl1V1px
RG9EdlNTc0N5OEUrMTJSbG9mZHRkT1BWczQKvp957P+EdrI0r4XdrK7+ImumCcE+
wiFpG64xBcr6h2ICQOu2EXP/qSdFO28AuxAOZ9W+8pTlGHQMgZ0ydoSmRKEZ+j56
4JOev8wbvnI=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IDdXUTlQQSBIdGI1
UVl5bVN5TDUvMTRuVFdpdG9lSkRjL2hOTHo3OVFxQ25IMDRlRGdJCm1oOEM5Rzlv
cUljejB0aUNCS0x5Qjh1Y1JWQTNmWE9kcjF1ZktJVUxLSUEKLT4gWDI1NTE5IHBN
Vm4vbC9GcUdaYjNlWEg0UUVTVVVHWG5VTnVPRFBkUXk1dm8wWlF1QU0KZEU3dXFR
YU5GalhSakF3OEduSlhuYTN3SVdFU0NrWmJBZThvN1BGU21TUQotPiBdLVQtZ3Jl
YXNlIElWPzRFcicgYVoldUFzClA3M2JUNFU4T2xSRmpyeStMQjZNa1I0bmxLSUdj
NGN6NkFvbmJEVWJXSEhCMjhkWjhyZkZPRyt5N2diZDI5SGwKczFsaEZXbDljVGQz
cnpMcHpPdTBPL0hwb0t3dE1XNURWckVEOFZmQwotLS0gbmQrNm9QQkpxTnYzTTFt
bHU3WWVDai9BY3VSaTB3NDN5bk1IdUNiMWk4NAqyrvPkq+FP+fSs9mZMgxLTJICD
5l8Ii5h9fl2APzedygOLFGQLq0qW7pjBygfmQWgG4gqsO4iKIwEjUiv30/QCUhKL
CGZJpN8AfZAcow==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,16 +1,15 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGdTeFAwUSAwa2t2
dVBqUzZOZmtRUk5Dcm9zL0cxRTZvcU5nb0xFNi9zQ3ZOeENGbldRCm5US1NoYWJX
Z2lubncvTXVjTFk3Z0tBWWZnQkxQNGV5MWs0Y0g4MGRkNUEKLT4gWDI1NTE5IElZ
VUJWdmFpOXpwampNcDVTQUllZjVBMm5VZzNOQXU0Q3k2YmJpbzJtQTQKaU9YUG81
RWZMaXpucUY3am1lbXVVVzNtbFVES3lITTZmTDQwOHp5dVdYRQotPiBbeXMyVG1Y
Yi1ncmVhc2UgIkQjIyBpClhyU3VOS3FCVG9sdFlrb0xpbVJDR1FTKzkzVkRJWUtq
aDdvTVFTVndFelphWGt6eHRDc1JlZnZNSHQ3Y1NpbEUKQnROSzFlYTYybWFpSGdh
ZGFrbEdCelEvNUdDUjFuMmFsZlBqOTFFajFkSitJcW9iUXp2dGVxT2tzTmVSSExR
Ci0tLSBhT0ZldFZ1MkJhcXdqRDIwajNZQ042K1JMS3d0Z0RjZ0F6VDNJMFZJbVJJ
Co/d2lNPILYqmod7NlFmKuTlh3GUs8pnT0HBJaWf4KHdujvFzWltAyUGJUk8Eye9
Z4OpYgkXBBzHqio5hFuvVj+EPGrA0at1ef9XrTNZIV2XTcRHbTitbAjqQX2nY/C5
u5Tt5L68xai2MQt5zEZZmyDaO3Blz2gCHNG2Nb0DZruT0cm3XIeWwPt/3tAWSDyk
FthdxxgpYYPnqN4ellzKfOG2qeyVtQahadBK+jmOxJWVOv2btcuL46nad9/WPXWG
A7d8pddiLEcKT4HNFVGhHpHztYLv/JdHIy8RjMkBpgvsjdMnIif4gPPNxQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGdTeFAwUSBSdmly
aEtUTHh3Uy95ZGhEcno5VktOcmlWYzVqUTE1MUs4NDg4WnZBT0Y4CjY2QndadEF2
TzF6TlJxall2cW4zeGltQVNabUJkcWNCUDRwZXpjYXJubVUKLT4gWDI1NTE5IGVL
N3dkVDFuSXdXZTFCVStzSCtCRUJGWUd0bnNGdnBhUlIzMExSNjBqWEEKOUdvZTlK
dzhyYWUzTmFzbnVxRTZRNHZ1NGFXSkJ3ejM0S0JCTGNpcHVzcwotPiB1dS1ncmVh
c2UgY0NxK2VxdyBdRE8vQSV1cSBcIFw/TG8jQwplZk1ZeTAzUnZJUm1qQ0VxUGpU
NU1waVZ6OXF3NXQvS08vblYvRDl6TzF4RUhvdW16anZWcXdORTVnCi0tLSB6ayth
aWRVUGgwazBMSUk0MEdETkhnbURkbEZXUGNCNnN4OUdPMXpkelcwCoil0uw2yDNc
mOUMhVzALll4DgCX/MskwCdYohSBnMpSzqtltAhkW1aqdbuU3PC9LHQElpuHqpl9
leNTu6n5nU5BHQ5qWShedL1G11SRzcblImwUcyg10d6Z0nUoCUjmw3BnGQ2wwvhC
M+GGeb9X1ORRciqprtTq1WXWGG3tYgL9SjTAEtyMhAZ3CFjh3p4BdC9pVhCAJ9TA
tbRAtqIz8VTzG86G4zPJYzBwtAse8tJDEO40GUqcOsmXhmPPpd7je1k381+GVrMj
q2g2gTCUOrMryVRX/7+H2iRxtIxmhqESXIWgY5SIUv9uRA==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,11 +1,12 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGV5cTNkZyAraUFM
MUc1c1k1V0RRTnJ0eGxLMXA0Rk5EWWozRWc1N0N4MVJ0UVFKOTF3CktndHNXRFFm
RWpFL2ZKdVcrQlR1ZTBDelhMSCt1dEhSR2Vwa0dzRDFlNmsKLT4gWDI1NTE5IFZG
WnBSN1Ara1daRkpDUWxTbkpCL0pNa1FOQTZZZWIvbkVHSmRQMk10MzQKSFlmeXR3
SDdhelM4azBMSmxLWE9TQjYvWG1BN3YvLy9lTisvT242NTc5bwotPiBNN2tfREIt
Z3JlYXNlIG4jYnR5Wz1pIFd0QSAvbEolCktnCi0tLSBFbkQ4b1BNV1NVTENpeVhz
dDFBbDlZemtQd3BVcGpTNW44Ri9sRWIweHhRCiyITgLrK+irMnL52bIHaK22Kf7O
lrKaePo6d6SkplhadDJ80s1wHtqCg1HoQG4k/uuffooEeAVQiWGlBbgyCVaTALtE
oUUz9wQ=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGV5cTNkZyB0blBa
Nlo2VGUzZzdTNW9heXhuUTJWYi9lWkl5WEp2VXcycExWd3FsLzNzCnpoZVVHaUxK
aHAxVmxQSkJ6a0JnSFpkdmRzLzl3ZktwYy9yckFSNGxzRWsKLT4gWDI1NTE5IFhl
RlR5TjJoUVdScjRKN3hDQmg4aDJpSllnd25WNmlVVTU4SzZRZEdnQ28KVGsyVHN6
TmZyV1hSbWZqWUtYNFdEQ0FLMjczRW5HSWVEaHJidHBjZzBZTQotPiA/by1ncmVh
c2UKUlJ1V2Y1eW1aNG1CTkx5VjZlREt5VkJjOVZoUno1T3p4WldSUTFpNDBXb21m
Z0l6eGZKaTBqbjRiTTRybnEyagpxQlRIZldEVGdNblRrZkMycFljdkwxSjl4VHcK
LS0tIDV2Q0NHeGRUblhCc3JUenl2bGhueER0UnFkcUZNWXR1c09QWDI0R2FkdXcK
8DfpILM67mlC23bKjt2hWfpI51JvTa2YBEvHwHDuaaZBw8FIU6E8s77iyjTysmsw
vmQwTrdoUPhfLHXspjHH1GGObwOxvdw/Mg==
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,12 +1,12 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGV5cTNkZyBNR1kw
NUtYSWxBRzRYWmdmcVU4SEQxYUx4dllOalUwS3hBb2x3b29KREdJCnBCdk5QSjhW
bU9ZRlRpSlVHWmtMTmc3ZDdreW02SitXTjM5UVVuT3hGM3cKLT4gWDI1NTE5IEp1
MnhBTVUzcjVvNkJOaTlWQmZhUzZZSzNnOUllaHlZQk5TVktQUlBmVmcKQXdPdlhQ
TTY4OGE2dTFKdnV0UDNISjBadDdxODF6SmtwSUs1S09KTXNMVQotPiBTYyJUKy1n
cmVhc2UgYWt+Z1h7TiBIIyZQeCBCCk13cU9BRU5sZGYvcVRoUW9RNDE3Vng0bGRQ
UjdueCtFVTMrTGVES2VIYnlWazJ3WTZxRUxJejhsK3NRSFZKV1kKNkd0bVEvMFFq
T2FQOUEKLS0tIG0rMEZFc2FickM0SVZBMndNUVQrS0VNYzBYSGRuejZ5dklOZHhP
MzRrMUkKa233E5gkQ4ohFfzanVMnm3zk6le0omKF05tTnESTDTeduEMcOou6SmcU
I5qzBKJdNoRBrOL2UTk6Nj9ymOoYl4lCBKYQc7ZRrYqau1g=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGV5cTNkZyAxUzdG
dG9ZNkpPNGlreWxRMFlPQUdFTk9FZ0kvVjNhbUNvMWU4a2krcmcwCnl1Vk1PUS8r
S0lveDV3OVphc3d6UDdLKzR4ZjB3RUloRzE2Zis3bjhsL00KLT4gWDI1NTE5IGVx
TEMzdDRDbFBuT0c0V1Y1d1diSUVYMEw0dmJwcG9WaWQwcUdMMEVtZ3cKZ0x0OExq
REFEdlJPU3o2WTlUQWU3b1NxcnJ1ajRRNkhxR1lxUmNpM1BLZwotPiBrMTREQ0lb
LWdyZWFzZSB6TSp5Y0knClQ3V1VFY0dzSy9iNVdkRVZYU09yWjhONXkzck9VZVpC
THh5amMvTlNLRDN2YUh1Mk1ncFcvZTZJZTRIRUlON1QKUzVDTDJJVk8KLS0tIENE
N0ZzdjNnTER6ejRqZ0Y2WTd6dUJOaHJqTk1HT2U2TlkyUnBPTFc5WmsKYcIKEURp
YcoFwU+gxq7BQlXo5LJDIcB73HPeerPnKYpfdyXFlsdm8mv3IXPEabSPwSNHXGIx
BdinoqfHgAjMwptksMA3iIOWqp1cF6E=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,13 +1,12 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGdTeFAwUSBBSUky
OENIdUpNVnNiZWhaVDVVMFFYVTh0bGgycjlUSWJqM3ZxSkJ6T1VFCklQNS9TOTlR
NThncEs4dldsV3h6NnhsbHlRcHc5R3kybExjbEZkclcyR3cKLT4gWDI1NTE5IGwx
bFQ1UEp4REJZbkZ2VHhraldZeXJwVGtrcXJVME5Vd2xYVUpxWm42U0UKS2wrTGY5
THVxRXJHalF4SzY3eWRZMXJqSXV6S3hxcVlmaWN6Z1d0Z1c1YwotPiBdXlktZ3Jl
YXNlIEUKeDBnd3RYejFkeUVER1IvczBoQ0g5TG9tOE11UlRweWpsRnBUZ2NId2Fw
S0gvSUZsT2ladWl5UkR1Z2pWS3NrWAoxMGk1L204WlNTY3RtVk1LWGRBRDNncHlH
V3d5ejB0NXdnCi0tLSBTMWMrQzlqeEI0dEtKeFJDU0hGVGxIWFdIL0pleitHVGx5
bGxkSWpwa3FjCnWQfvArLtwaAjQNtJ0bgS0Bi+bzL4xRQ9fmOsXegiKg+DW85ofI
641YVPvRkXqDI/+6PCCRxNk+KfUJeg0SvkyBjZwk3bWWMmEkN1SKMszINuQaI0Tl
a5lAKtUOr0Hy2fGF2ypFnTTjVy/Ax8FjHaJv81SqbVpkWw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGdTeFAwUSBvRWE1
Z1ZpNTFjTnluOUlPMldCQ3BzQzdVaEw4dlZjc2xuMkhGWlNDU1ZZCjVGNk9PNjNS
elNlSzMzYUNOQ0dzYkNFUDlxNlg4S3BGbXNldGN5eWYwZTgKLT4gWDI1NTE5IHp2
eDFPZ0VadjFVZFdVMXlYd3ZFRXIyeDRQU1dMV3ZEWHJEaGxOSzgxRE0KVVpvVnFQ
WHhpWjN2Mm9TV0EwajlyRTg4TVIvbm0zZGFBVkJqbkJTZEh5RQotPiB6QS1ncmVh
c2UgdycgQmJMCnVhd01JSEpUQ1U1Q3o2Wnh5UQotLS0gSkZwd0tNTGs0NkFiY250
eGR1WXRLTWhzWlZOaHlGaHQvNUh2MjNDUm8yWQpH1cWbszmSTjpqz8Wyrt6g2TNP
rtCRSnfw7UcoMh2oW3kyYcQrwf/sAFAHLNMh8oOWoxrKG1vtPxpOz251hlnee8JV
dIZ/2Gj/lPXDFTkhmX0TfABAe4wPJlM2wu9pj70UvGnI1osR6avrpYr9mMau3Ypm
Ucix6cE=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,11 +1,10 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGdTeFAwUSA4Qmgv
YmRKT3ZZR0FtRmlUQmxERnNiOGphaTBXM3B0a2NnbXVSMTE2UEhFCnVUTTB6RmVu
akxtRHR5TmtPVGlOR1NuODFlb2lTcEtnTWphbHhwT0lHMFUKLT4gWDI1NTE5IGdZ
ZE9SdU11akt2SEpvZE9XMjRnUHJzVnBCSXlocWUvQUNxekszWE5uZ2cKOS9vZFZN
Y2ErVlQwVkJQR3ljQ3JoRDVuQXd0V2hGRjIrbVhDV2htb254UQotPiBoOiZRLWdy
ZWFzZSBMVnpRUzgiIDl+OFExIDFAL342UQpycExFU1BiV09UT0NzS1N1OWJOWjdh
WkkydmwweGRrbTI5ZmRTVEtGdlBOM2tjK0lrK0xrCi0tLSBpNjYzNWUzYkxnamQ2
ejlGQzR6dlExWE1kbHhJQUM5UG5PSzhxS01mN0VvChgTMuB7wDbjXfDikKEKbd5k
gp8QdI55ueCnEl5UfFwurHn9Cd3I6EPiSN1J3rRFMTiuO5Ke
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGdTeFAwUSArMzRH
YnRFQUNJd0dRZDBEMGJZeitaS3Zaa214c2FnakxMYVVxOW1xMkh3ClpSeEprOTBW
dk1tRWhmUXRzeWpLUm13Z05pTnhsV0hCRk1YUjJQMTdDQ28KLT4gWDI1NTE5IGQ4
OXBuVkRiS0lRQitweU1TRURzK1VhY0lnWFpZRGQ0aG9yOGhsa1JnUlEKUkU2VUhr
MTc5N2tkdFYxd1RUemk3MFEvb3d4eHFaVU9ycEhBWHk3QVRwZwotPiBbXGVcI3J6
LWdyZWFzZQptTGx5SmVNM0FPMHdGY0NQK3AwCi0tLSBwbUxtKzMxYTNpdUlPc3BZ
V1N2cFlyTkZvYThES2wrZTdHTy82cXVoeStJCk0ed1c9gQUw93efGmqJDQ608cwj
PDVTyJ7erVlArctJkTKOx57QMqWzMSEGh7O196SceZEv
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,15 +1,18 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyA2VDkr
NFl3MGV4YW44TWhWVklaTW1pazVkU1ViZkNUdWdGaXBiVXJVZFdjClMyWHc3dk9W
ZFVzTnh4MnE2Q1h1MGhEVkk4c2JMVmlVZzdJeHlWaUR4OFkKLT4gc3NoLWVkMjU1
MTkgcytxUmZnIEZERng2OGhhL1dTeTFYM2d5Y3ljWk1EV1dyb2s2RHJaZ2pJN3pR
cUlPajgKWkdrVTdYRUl3N1FUVEU4elA3dU80TENVZXduRDVHeEpUVENvcW1VZ2Vs
VQotPiBYMjU1MTkgR1VEZFVHeWdxakV5NXYrYXlJaHZ0V3dLbXNIUmd6S0U2MFJP
SnhQSVh4cwp6ZFhJRXkvaUFsb0p5N1JpcHNnc2UwbmVpdVovQXdLcGNLam5WNUs2
a0NzCi0+IEleLWdyZWFzZSA7Iy9ueTUKQjlHZStJTElISmpaNERmdkxZcTNWTnlU
N2pZOGFDaGtudlUxRmhSOVYrWjd6M1lyazFlQyt5YkMvUk15eVNsaApSRlF6ZGh0
QnA2YllsK2lESC92SjltZlV6UFZzRXp3WEg0SQotLS0gY3lXNFUxQlUxQXQxdjJv
aUJWaEtrRUpNdlZqWlFwMW5MQXcvQlkzYmN6cwoFYEIL6t0rQBxOjMnSD+ySJAwI
CHu+SNUkK6gyAR+vqv5+cuaouCHT0ljrL+7e/wuBg2X+mbNi2Sa9GkfT7+U6GtuX
beimorHFaSU4KA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyBUUmlu
VkJMYVltVTZyUnh0aXdZZzduSEl0ZFAxb2lIb2F2ck4zdlBjdFZNCm51RnV0M0pi
VkVaZVdOMWpKOW43ZjhFODgzZTJ2c1F1eXc5WnJvMHVZUGMKLT4gc3NoLWVkMjU1
MTkgbjhDcFV3IDdhNjB5U1h3ellMRDRRQWVkQ3hNcVQxUnQrbkQ0V2doR3pFWFRI
RE9xMDQKTUh2bXV0eTdvRmhmTVVaRllRcEpiRStnSnpMeGFpeGt0eEhvQlZETXhi
awotPiBzc2gtZWQyNTUxOSBaTnFJb2cgUW03aXgrM3FWbURXR3o0ZkZsUE83YVk1
ZzkwZm1JdC81aHI4YVJOdWQzTQpzS1dHRFZYeHV2djVFN1Q3MHdhWVl5WVc5NExy
M2xEckFMTjFvTWI1Y3BrCi0+IHNzaC1lZDI1NTE5IHMrcVJmZyAwQ0Z0a1FHU0lV
VEFmMFpsNXF3Z0l3eTkrdzRZQ3lSQUg4MFhPaUNEbGdVCnFuVEhXWDdndnhxdUtV
TkdRZnpFTGpaZDNJalI3b1NHUld2NEV0TlphK2MKLT4gWDI1NTE5IExObHUwOEFT
bGl4S2F0YVdHaGFnRjdIQ3VDeVFDbjh5SFpkczN3d0ZuQUUKSEFvdTIwSUhvd0dz
dDdBSUxDOHZaNkNLL0x0aDRCS1ZORUsrdWpJS3EwVQotPiApcDQxLWdyZWFzZSA5
ZSA9YD4gbWMgRH18eXd0YnkKbmcKLS0tIElQa3pEcVhtN0N1bW4rSTZ5VnB3N256
bnM0OXpSc1BuNmJwZnBremRIZnMKhN29J3s+Cif3jvx63Xay77CdC6uVhjsojdbF
zhWad9vPolrrbEiNkhcdrutyTRniFBUEwxQVGmAxcEySNTr3lnWnWQFagphu3F27
zLs=
-----END AGE ENCRYPTED FILE-----

Some files were not shown because too many files have changed in this diff Show More