Commit 2981cec
Changed files (5)
modules
hosts
tribios
services
secrets
modules/hosts/tribios/networking.nix
@@ -1,8 +1,24 @@
-{
+{den, ...}: {
+ den.hosts.tribios = {
+ settings.services.proxy.dae.interfaces = {
+ wan = ["auto"];
+ lan = ["br-lan"];
+ };
+ };
+
den.aspects.tribios = {
+ includes = [
+ den.aspects.services.proxy
+ ];
+
nixos = {
boot.kernel.sysctl = {
"net.ipv4.ip_forward" = 1;
+ "net.ipv4.conf.all.send_redirects" = 0;
+ "net.ipv4.conf.default.send_redirects" = 0;
+ "net.ipv4.conf.br-lan.send_redirects" = 0;
+ "net.ipv6.conf.all.forwarding" = 1;
+ "net.ipv6.conf.br-lan.forwarding" = 1;
};
# Tribios' network interfaces:
modules/services/proxy/dae.nix
@@ -0,0 +1,220 @@
+{
+ lib,
+ den,
+ ...
+}: {
+ den.aspects.services.proxy.dae = {
+ settings = {
+ interfaces = {
+ wan = lib.mkOption {
+ description = "The WAN interface to bind. Use it if you want to proxy localhost.";
+ type = lib.types.listOf lib.types.str;
+ default = ["auto"];
+ };
+ lan = lib.mkOption {
+ description = "The LAN interface to bind. Use it if you want to proxy LAN.";
+ type = lib.types.listOf lib.types.str;
+ default = [];
+ };
+ };
+ };
+
+ nixos = {
+ host,
+ pkgs,
+ config,
+ ...
+ }: let
+ cfg = host.settings.services.proxy.dae;
+
+ allHosts = builtins.concatMap builtins.attrValues (builtins.attrValues den.hosts);
+ otherHosts = builtins.filter (h: h.name != host.name) allHosts;
+
+ hostsWithIpv4ClearText = builtins.filter (h: h.address.ipv4.clearText != null) otherHosts;
+ hostsWithIpv4Secret = builtins.filter (h: h.address.ipv4.secret.name != null && h.address.ipv4.secret.file != null) otherHosts;
+ hostsWithIpv6ClearText = builtins.filter (h: h.address.ipv6.clearText != null) otherHosts;
+ hostsWithIpv6Secret = builtins.filter (h: h.address.ipv6.secret.name != null && h.address.ipv6.secret.file != null) otherHosts;
+
+ clearTextIps =
+ (map (h: h.address.ipv4.clearText) hostsWithIpv4ClearText)
+ ++ (map (h: h.address.ipv6.clearText) hostsWithIpv6ClearText);
+
+ secretIpPlaceholders =
+ (map (h: config.vaultix.placeholder.${h.address.ipv4.secret.name}) hostsWithIpv4Secret)
+ ++ (map (h: config.vaultix.placeholder.${h.address.ipv6.secret.name}) hostsWithIpv6Secret);
+
+ allHostIps = clearTextIps ++ secretIpPlaceholders;
+
+ hostDirectRule =
+ lib.optionalString (allHostIps != [])
+ "dip(${builtins.concatStringsSep ", " allHostIps}) -> direct";
+
+ v2ray-geoip = pkgs.fetchurl rec {
+ pname = "v2ray-geoip";
+ version = "202606262300";
+ url = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/download/${version}/geoip.dat";
+ downloadToTemp = true;
+ recursiveHash = true;
+ postFetch = ''
+ install -D "$downloadedFile" "$out/share/v2ray/geoip.dat"
+ '';
+ hash = "sha256-0z0qNvvN8I5PY14DWZgk4blZcgLoWIChZefkgeuWM1c=";
+ };
+ v2ray-geosite = pkgs.fetchurl rec {
+ pname = "v2ray-geosite";
+ version = "202606262300";
+ url = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/download/${version}/geosite.dat";
+ downloadToTemp = true;
+ recursiveHash = true;
+ postFetch = ''
+ install -D "$downloadedFile" "$out/share/v2ray/geosite.dat"
+ '';
+ hash = "sha256-NytCOfetMwjKFlc8bEz31KskcSnEkvSmvTp+Y8RvVC0=";
+ };
+ in {
+ services.dae = {
+ enable = true;
+ package = pkgs.dae.overrideAttrs {
+ version = "1.1.0";
+ src = pkgs.fetchFromGitHub {
+ owner = "daeuniverse";
+ repo = "dae";
+ tag = "v1.1.0";
+ hash = "sha256-Kc51VQuqObxKXVXGv5CnDm4/3XYqjPvrpAQSVb2vxSM=";
+ fetchSubmodules = true;
+ };
+ vendorHash = "sha256-juxIsZt1T33epN8CbzDc02MmlW5PtYa4pcGxuX9OpH4=";
+ };
+ assets = [v2ray-geoip v2ray-geosite];
+ config = ''
+ include {
+ # For security reasons, dae requires included files to be under the entry config directory.
+ routing.dae
+ }
+
+ global {
+ ${
+ if cfg.interfaces.wan != []
+ then "wan_interface: ${builtins.concatStringsSep "," cfg.interfaces.wan}"
+ else ""
+ }
+ ${
+ if cfg.interfaces.lan != []
+ then "lan_interface: ${builtins.concatStringsSep "," cfg.interfaces.lan}"
+ else ""
+ }
+ log_level: info
+ allow_insecure: false
+ check_interval: 60s
+ check_tolerance: 100ms
+ dial_mode: domain
+ }
+
+ dns {
+ upstream {
+ alidns: 'udp://dns.alidns.com:53'
+ googledns: 'tcp+udp://dns.google:53'
+ }
+ routing {
+ request {
+ qname(geosite:category-ads-all) -> reject
+ qtype(https) -> reject
+ qname(geosite:cn) -> alidns
+ fallback: googledns
+ }
+ }
+ }
+
+ subscription {
+ common: "http://127.0.0.1:${toString host.settings.services.proxy.sub-store.port}/backend/download/collection/common?target=V2Ray"
+ auxiliary: "http://127.0.0.1:${toString host.settings.services.proxy.sub-store.port}/backend/download/collection/auxiliary?target=V2Ray"
+ }
+
+ group {
+ proxy {
+ filter: !subtag(auxiliary) && name(regex: '香港|台湾|美国|日本|新加坡')
+ filter: subtag(auxiliary) && name(regex: '香港|台湾|美国|日本|新加坡') [add_latency: 300ms]
+ policy: min_moving_avg
+ }
+ proxy_download {
+ filter: !subtag(auxiliary) && !name(regex: 'IEPL|家宽') && name(regex: '香港|美国|日本|新加坡|韩国|德国')
+ policy: min_avg10
+ }
+ }
+ '';
+ };
+
+ systemd.services.dae = {
+ serviceConfig.LoadCredential = ["routing.dae:${config.vaultix.templates.dae-routing.path}"];
+ };
+
+ vaultix.secrets = lib.mkMerge (
+ (map (h: {${h.address.ipv4.secret.name}.file = h.address.ipv4.secret.file;}) hostsWithIpv4Secret)
+ ++ (map (h: {${h.address.ipv6.secret.name}.file = h.address.ipv6.secret.file;}) hostsWithIpv6Secret)
+ );
+
+ vaultix.templates.dae-routing = {
+ content = ''
+ routing {
+ # == System ==
+ pname(NetworkManager, systemd-networkd, systemd-resolved,
+ dnsmasq, cloudflared) -> must_direct
+ pname(ssh) -> direct
+ dport(22) -> direct
+
+ # == DNS ==
+ dip(223.5.5.5, 223.6.6.6) -> direct
+ domain(full:dns.alidns.com) -> direct
+ dip(119.29.29.29, 119.28.28.28) -> direct
+ domain(full:doh.pub) -> direct
+ dip(8.8.8.8, 8.8.4.4) -> proxy
+ domain(full:dns.google) -> proxy
+ dip(1.1.1.1, 1.0.0.1) -> proxy
+ domain(full:one.one.one.one, full:cloudflare-dns.com) -> proxy
+
+ # == Private ==
+ dip(geoip:private) -> direct
+ domain(geosite:private) -> direct
+
+ # == My Hosts ==
+ ${hostDirectRule}
+
+ # == AI ==
+ domain(geosite:category-ai-!cn) -> proxy
+
+ # == Big Company ==
+ domain(geosite:microsoft@cn) -> direct
+ domain(geosite:microsoft) -> proxy
+ domain(geosite:apple@cn) -> direct
+ domain(geosite:apple) -> proxy
+ domain(geosite:google@cn) -> direct
+ domain(geosite:google) -> proxy
+ domain(geosite:cloudflare) -> proxy
+
+ # == Game ==
+ domain(suffix:cm.steampowered.com) -> direct
+ domain(suffix:steamserver.net) -> direct
+ domain(geosite:steam@cn) -> direct
+ domain(geosite:category-games-cn) -> direct
+ domain(geosite:category-game-platforms-download@cn) -> direct
+
+ # == Download ==
+ domain(geosite:mega) -> proxy_download
+ domain(keyword:dl-a10b-, dl-z01a-, dl-b07-) -> proxy_download
+
+ # == China ==
+ domain(geosite:tld-cn, geosite:geolocation-cn, geosite:cn) -> direct
+ dip(geoip:cn) -> direct
+ domain(geosite:gfw) -> proxy
+
+ # == Other ==
+ domain(suffix: kagi.com, suffix: codeberg.org, suffix: mxrouting.net) -> direct
+
+ # == Fallback ==
+ fallback: proxy
+ }
+ '';
+ };
+ };
+ };
+}
modules/services/proxy/default.nix
@@ -0,0 +1,8 @@
+{den, ...}: {
+ den.aspects.services.proxy = {
+ includes = [
+ den.aspects.services.proxy.dae
+ den.aspects.services.proxy.sub-store
+ ];
+ };
+}
modules/services/proxy/sub-store.nix
@@ -0,0 +1,44 @@
+{
+ lib,
+ inputs,
+ ...
+}: {
+ den.aspects.services.proxy.sub-store = {
+ settings = {
+ port = lib.mkOption {
+ default = 3000;
+ type = lib.types.port;
+ description = "Port the sub-store frontend listen on";
+ };
+ };
+
+ persist = {
+ directories = [
+ {
+ directory = "/var/lib/private/sub-store";
+ user = "nobody";
+ group = "nogroup";
+ mode = "0755";
+ }
+ ];
+ };
+
+ nixos = {host, ...}: let
+ cfg = host.settings.services.proxy.sub-store;
+ in {
+ imports = [inputs.nur-hpcesia.nixosModules.sub-store];
+
+ services.sub-store = {
+ enable = true;
+ port = cfg.port;
+ frontend = {
+ enable = true;
+ port = cfg.port;
+ # sub-store uses the URL path for authentication.
+ # Since I only access it locally, I've made this path public.
+ backendPath = "/backend";
+ };
+ };
+ };
+ };
+}
secrets/cache/tribios/933dc774c4b9926ee79cc113303524f3872b2da03f5572ffb2dc6e2d900102fe
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> ssh-ed25519 1YGZAA TPMeCzIQkFN6nXjYD6v/7GMnK6q6HEIm9Kw5iq+10Xg
+C4RxyLuQ+MYTF7Qc9v243mkx1p12tfhnMvzy8eihAHk
+-> *Z-grease SW Ea'*@~s $h:&KAsK xKq
+uu8hbA
+--- DJkoXZ8Vrs/nOKODiGBhmnYZAwLKCUliir2imm+ou/A
+�Ǯq���y�1Z��D�Õ|�/˨�]3�1�z�_Dr��:�k�~�
\ No newline at end of file