feat: switch to avahi for mdns and mdns reflection

This commit is contained in:
oddlama 2025-04-27 11:08:40 +02:00
parent 919ce9fc6a
commit 3f3573a1e2
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
12 changed files with 30 additions and 195 deletions

View file

@ -7,6 +7,18 @@
systemd.network.enable = true;
systemd.network.wait-online.enable = false;
services.avahi = {
enable = true;
ipv4 = true;
ipv6 = true;
nssmdns4 = true;
nssmdns6 = true;
publish = {
enable = true;
addresses = true;
};
};
networking = {
useDHCP = lib.mkForce false;
useNetworkd = true;
@ -16,5 +28,10 @@
renameInterfacesByMac = lib.mapAttrs (_: v: v.mac) (
config.repo.secrets.local.networking.interfaces or { }
);
nftables.chains.input.mdns = {
after = [ "conntrack" ];
rules = [ "udp dport 5353 accept" ];
};
};
}

View file

@ -1,12 +1,7 @@
{
config,
lib,
...
}:
{
services.resolved = {
enable = true;
dnssec = "false"; # wake me up in 20 years when DNSSEC is at least partly working
dnssec = "false"; # NOTE: wake me up in 20 years when DNSSEC is at least partially working
fallbackDns = [
"1.1.1.1"
"2606:4700:4700::1111"
@ -16,50 +11,6 @@
llmnr = "false";
extraConfig = ''
Domains=~.
MulticastDNS=true
'';
};
system.nssDatabases.hosts = lib.mkMerge [
(lib.mkBefore [ "mdns_minimal [NOTFOUND=return]" ])
(lib.mkAfter [ "mdns" ])
];
# Open port 5353 for any interfaces that have MulticastDNS enabled
networking.nftables.firewall =
let
# Determine all networks that have MulticastDNS enabled
networksWithMulticast = lib.filter (
n: config.systemd.network.networks.${n}.networkConfig.MulticastDNS or false
) (lib.attrNames config.systemd.network.networks);
# Determine all known mac addresses and the corresponding link name
# based on the renameInterfacesByMac option.
knownMacs = lib.mapAttrs' (k: v: lib.nameValuePair v k) config.networking.renameInterfacesByMac;
# A helper that returns the link name for the given mac address,
# or null if it doesn't exist or the given mac was null.
linkNameFor = mac: if mac == null then null else knownMacs.${mac} or null;
# Calls the given function for each network that has MulticastDNS enabled,
# and collects all non-null values.
mapNetworks = f: lib.filter (v: v != null) (map f networksWithMulticast);
# All interfaces on which MulticastDNS is used
mdnsInterfaces = lib.unique (
# For each network that is matched by MAC, lookup the link name
# and if map the definition name to the link name.
mapNetworks (x: linkNameFor (config.systemd.network.networks.${x}.matchConfig.MACAddress or null))
# For each network that is matched by name, map the definition
# name to the link name.
++ mapNetworks (x: config.systemd.network.networks.${x}.matchConfig.Name or null)
);
in
lib.mkIf (mdnsInterfaces != [ ]) {
zones.mdns.interfaces = mdnsInterfaces;
rules.mdns-to-local = {
from = [ "mdns" ];
to = [ "local" ];
allowedUDPPorts = [ 5353 ];
};
};
}

View file

@ -45,5 +45,6 @@
tss = uidGid 966;
firefly-iii = uidGid 965;
firefly-pico = uidGid 964;
avahi = uidGid 963;
};
}

View file

@ -15,20 +15,14 @@
"10-lan1" = {
DHCP = "yes";
matchConfig.MACAddress = config.repo.secrets.local.networking.interfaces.lan1.mac;
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
networkConfig.IPv6PrivacyExtensions = "yes";
dhcpV4Config.RouteMetric = 10;
dhcpV6Config.RouteMetric = 10;
};
"10-wlan1" = {
DHCP = "yes";
matchConfig.MACAddress = config.repo.secrets.local.networking.interfaces.wlan1.mac;
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
networkConfig.IPv6PrivacyExtensions = "yes";
dhcpV4Config.RouteMetric = 40;
dhcpV6Config.RouteMetric = 40;
};

View file

@ -16,20 +16,14 @@
"10-lan1" = {
DHCP = "yes";
matchConfig.MACAddress = config.repo.secrets.local.networking.interfaces.lan1.mac;
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
networkConfig.IPv6PrivacyExtensions = true;
dhcpV4Config.RouteMetric = 10;
dhcpV6Config.RouteMetric = 10;
};
"10-wlan1" = {
DHCP = "yes";
matchConfig.MACAddress = config.repo.secrets.local.networking.interfaces.wlan1.mac;
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
networkConfig.IPv6PrivacyExtensions = true;
dhcpV4Config.RouteMetric = 40;
dhcpV6Config.RouteMetric = 40;
};

View file

@ -40,10 +40,7 @@ in
];
gateway = [ globals.net.home-lan.vlans.services.hosts.ward.ipv4 ];
matchConfig.Name = "vlan-services";
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
networkConfig.IPv6PrivacyExtensions = "yes";
linkConfig.RequiredForOnline = "routable";
};
};
@ -83,10 +80,7 @@ in
];
gateway = lib.optionals (vlanName == "services") [ vlanCfg.hosts.ward.ipv4 ];
matchConfig.Name = "vlan-${vlanName}";
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = vlanName == "services";
};
networkConfig.IPv6PrivacyExtensions = "yes";
linkConfig.RequiredForOnline = "routable";
};
}

View file

@ -40,10 +40,7 @@ in
];
gateway = [ globals.net.home-lan.vlans.home.hosts.ward.ipv4 ];
matchConfig.Name = "vlan-home";
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
networkConfig.IPv6PrivacyExtensions = "yes";
linkConfig.RequiredForOnline = "routable";
};
};
@ -110,10 +107,7 @@ in
];
gateway = lib.optionals (vlanName == "services") [ vlanCfg.hosts.ward.ipv4 ];
matchConfig.Name = "me-${vlanName}";
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = vlanName == "services";
};
networkConfig.IPv6PrivacyExtensions = "yes";
linkConfig.RequiredForOnline = "routable";
};
}

View file

@ -36,7 +36,6 @@ in
./fs.nix
./net.nix
./kea.nix
./mdns-repeater.nix
];
topology.self.hardware.image = ../../topology/images/odroid-h3.png;

View file

@ -1,78 +0,0 @@
{
pkgs,
lib,
...
}:
let
interfaces = [
"me-services"
"me-devices"
"me-iot"
"wan"
];
interfacesRegex = "(${lib.concatStringsSep "|" (interfaces ++ [ "me-home" ])})";
cfg = {
interfaces = interfacesRegex;
rules =
[
{
from = interfacesRegex;
to = "me-home";
allow_answers = ".*";
}
]
++ lib.forEach interfaces (to: {
from = "me-home";
inherit to;
allow_questions = ".*";
});
};
in
{
systemd.services.mdns-repeater = {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment.RUST_LOG = "info";
serviceConfig = {
Restart = "on-failure";
ExecStart = "${lib.getExe pkgs.mdns-repeater} --config ${pkgs.writeText "config.json" (builtins.toJSON cfg)}";
# Hardening
DynamicUser = true;
CapabilityBoundingSet = "";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateUsers = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateMounts = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
];
UMask = "0027";
};
};
}

View file

@ -14,6 +14,9 @@
network = "home-lan.vlans.services";
};
# Reflect mDNS packets between our networks
services.avahi.reflector = true;
boot.initrd.availableKernelModules = [ "8021q" ];
boot.initrd.systemd.network = {
enable = true;
@ -50,7 +53,6 @@
networkConfig = {
IPv4Forwarding = "yes";
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
linkConfig.RequiredForOnline = "routable";
};
@ -102,7 +104,6 @@
gateway = [ globals.net.home-wan.hosts.fritzbox.ipv4 ];
matchConfig.Name = "wan";
networkConfig.IPv6PrivacyExtensions = "yes";
networkConfig.MulticastDNS = true;
# dhcpV6Config.PrefixDelegationHint = "::/64";
# FIXME: This should not be needed, but for some reason part of networkd
# isn't seeing the RAs and not triggering DHCPv6. Even though some other
@ -140,7 +141,6 @@
IPv6SendRA = true;
IPv6AcceptRA = false;
# DHCPPrefixDelegation = true;
MulticastDNS = vlanName == "services";
};
# dhcpPrefixDelegationConfig.UplinkInterface = "wan";
# dhcpPrefixDelegationConfig.Token = "::ff";

View file

@ -18,7 +18,6 @@ _inputs: [
# })
# ];
mdns-repeater = prev.callPackage ./mdns-repeater.nix { };
firefly-pico = prev.callPackage ./firefly-pico.nix { };
formats = prev.formats // {

View file

@ -1,30 +0,0 @@
{
lib,
fetchFromGitHub,
rustPlatform,
}:
rustPlatform.buildRustPackage {
pname = "mdns-repeater";
version = "unstable-git";
src = fetchFromGitHub {
owner = "PatrickDaG";
repo = "mdns-repeater";
rev = "5178041edbd0382bdeac462223549e093b26fe12";
hash = "sha256-cIrHSzdzFqfArE2bqWPm+CULuQU/KajkRN+i0b+seD0=";
};
cargoHash = "sha256-lGeOwszMkVGJZT7V8b3COPgKNFo+jW/zDf4D3OoF5uY=";
meta = {
description = "mDNS packet relayer";
homepage = "https://github.com/PatrickDaG/mdns-repeater";
license = lib.licenses.asl20;
maintainers = with lib.maintainers; [
oddlama
patrickdag
];
mainProgram = "mdns-repeater";
platforms = lib.platforms.linux;
};
}