The newedge.house site adopts the 10.1.<vlanId>.0/24 convention: mgmt 10 (the old untagged LAN), lan 20, iot 40, voip 50, dmz 60, unit1-5 110-150. PPPoE is untagged at this site. Static leases move to a new per-VLAN dhcp.reservations option rendered into Kea host reservations.
85 lines
2.3 KiB
Nix
85 lines
2.3 KiB
Nix
# LAN DHCP (Kea) and DNS (Blocky). Fully declarative: one Kea subnet per VLAN
|
|
# with dhcp.enable, Blocky as the blocklist resolver every DHCP lease points
|
|
# at. Blocky's HTTP listener (:4000) serves Prometheus metrics, scraped by
|
|
# control over the mesh (firewall.nix scopes it to the mesh subnet).
|
|
{
|
|
config,
|
|
lib,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.cnx.router;
|
|
dhcpVlans = lib.filterAttrs (_: vlan: vlan.dhcp.enable) cfg.vlans;
|
|
in
|
|
{
|
|
config = lib.mkIf cfg.enable {
|
|
services.kea.dhcp4 = {
|
|
enable = true;
|
|
settings = {
|
|
interfaces-config.interfaces = lib.mapAttrsToList (name: _: "vlan-${name}") dhcpVlans;
|
|
lease-database = {
|
|
type = "memfile";
|
|
persist = true;
|
|
name = "/var/lib/kea/dhcp4.leases";
|
|
};
|
|
valid-lifetime = 86400;
|
|
subnet4 = lib.mapAttrsToList (name: vlan: {
|
|
id = vlan.id;
|
|
subnet = vlan.subnet;
|
|
interface = "vlan-${name}";
|
|
valid-lifetime = vlan.dhcp.leaseTime;
|
|
pools = [ { pool = "${vlan.dhcp.pool.from} - ${vlan.dhcp.pool.to}"; } ];
|
|
reservations = lib.mapAttrsToList (host: res: {
|
|
hostname = host;
|
|
hw-address = res.hwAddress;
|
|
ip-address = res.ipAddress;
|
|
}) vlan.dhcp.reservations;
|
|
option-data = [
|
|
{
|
|
name = "routers";
|
|
data = vlan.address;
|
|
}
|
|
{
|
|
name = "domain-name-servers";
|
|
data = vlan.address;
|
|
}
|
|
];
|
|
}) dhcpVlans;
|
|
};
|
|
};
|
|
|
|
services.blocky = {
|
|
enable = true;
|
|
settings = {
|
|
ports = {
|
|
dns = 53;
|
|
http = 4000;
|
|
};
|
|
upstreams.groups.default = [
|
|
"9.9.9.9"
|
|
"149.112.112.112"
|
|
"2620:fe::fe"
|
|
];
|
|
blocking = {
|
|
denylists.ads = [
|
|
"https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
|
|
];
|
|
clientGroupsBlock.default = [ "ads" ];
|
|
};
|
|
caching = {
|
|
minTime = "5m";
|
|
prefetching = true;
|
|
};
|
|
prometheus.enable = true;
|
|
};
|
|
};
|
|
|
|
# The router itself resolves via public resolvers, not via Blocky, so DNS
|
|
# for deploys/updates survives a broken local resolver.
|
|
networking.nameservers = [
|
|
"9.9.9.9"
|
|
"1.1.1.1"
|
|
];
|
|
};
|
|
}
|