Better addressing?

This commit is contained in:
Yaro Kasear 2026-05-01 13:07:30 -05:00
parent b5c1a43863
commit f35e402b4d
3 changed files with 394 additions and 261 deletions

View file

@ -10,67 +10,48 @@
outputs = { self, nixpkgs, deploy-rs, disko, nixos-anywhere, ... }: outputs = { self, nixpkgs, deploy-rs, disko, nixos-anywhere, ... }:
let let
# Default architecture if a system doesnt override it
defaultSystem = "x86_64-linux"; defaultSystem = "x86_64-linux";
# pkgs per-system so cross-arch doesnt explode later
pkgsFor = system: import nixpkgs { inherit system; }; pkgsFor = system: import nixpkgs { inherit system; };
lib = nixpkgs.lib; lib = nixpkgs.lib;
# World spec & addressing
meta = import ./meta.nix; meta = import ./meta.nix;
addressing = import ./lib/addressing { inherit lib; }; addressing = import ./lib/addressing { inherit lib; };
# Optional for now; meta.systems can be {} until the systems submodule lands
systemsFromMeta = meta.systems or { }; systemsFromMeta = meta.systems or { };
# Precomputed full network view
network = addressing.mkNetworkFromSpec meta; network = addressing.mkNetworkFromSpec meta;
in in
{ {
########################
# Library exports
########################
lib.metanix = { lib.metanix = {
inherit meta addressing network; inherit meta addressing network;
}; };
########################
# NixOS configurations
########################
nixosConfigurations = nixosConfigurations =
lib.mapAttrs lib.mapAttrs
(name: sysCfg: (name: sysCfg:
let let
# System for this host, fallback to default
system = sysCfg.system or defaultSystem; system = sysCfg.system or defaultSystem;
pkgs = pkgsFor system;
in in
lib.nixosSystem { lib.nixosSystem {
inherit system; inherit system;
# Make meta/addressing/world visible to modules
specialArgs = { specialArgs = {
inherit lib pkgs meta addressing system; inherit lib meta addressing system network;
modulesPath = builtins.toString <nixpkgs/nixos/modules>; modulesPath = "${nixpkgs}/nixos/modules";
}; };
modules = modules =
(sysCfg.modules or [ ]) ++ [ (sysCfg.modules or [ ]) ++ [
# Core Metanix wiring
./modules/metanix/core.nix ./modules/metanix/core.nix
./modules/metanix/networkd.nix ./modules/metanix/networkd.nix
# Identity binding: “this box is <name> in Metanix”
{ {
networking.hostName = sysCfg.hostName or name; networking.hostName = sysCfg.hostName or name;
metanix.thisHost = sysCfg.metanixName or name; metanix.thisHost = sysCfg.metanixName or name;
} }
# Optional Disko integration per host
(if sysCfg ? diskoConfig then (if sysCfg ? diskoConfig then
{ {
imports = [ imports = [
@ -84,10 +65,6 @@
}) })
systemsFromMeta; systemsFromMeta;
########################
# deploy-rs
########################
deploy = { deploy = {
nodes = nodes =
lib.mapAttrs lib.mapAttrs
@ -97,7 +74,10 @@
hostInfo = if hasNetworkHost then network.hosts.${name} else null; hostInfo = if hasNetworkHost then network.hosts.${name} else null;
defaultHostname = defaultHostname =
if hasNetworkHost then hostInfo.fqdn else "${name}.${meta.domain}"; if hasNetworkHost && hostInfo ? fqdn then
hostInfo.fqdn
else
name;
in in
{ {
hostname = sysCfg.deployHost or defaultHostname; hostname = sysCfg.deployHost or defaultHostname;
@ -112,12 +92,10 @@
systemsFromMeta; systemsFromMeta;
}; };
checks.${defaultSystem}.deploy = checks =
deploy-rs.lib.${defaultSystem}.deployChecks self.deploy; builtins.mapAttrs
(system: deployLib: deployLib.deployChecks self.deploy)
######################## deploy-rs.lib;
# nixos-anywhere helper
########################
apps.${defaultSystem}.nixos-anywhere = { apps.${defaultSystem}.nixos-anywhere = {
type = "app"; type = "app";

View file

@ -1,4 +1,4 @@
{ lib ? import <nixpkgs/lib> { } }: { lib, ... }:
let let
inherit (lib) inherit (lib)
@ -6,27 +6,26 @@ let
attrNames attrNames
concatMapAttrs concatMapAttrs
concatStringsSep concatStringsSep
filterAttrs
listToAttrs listToAttrs
mapAttrs'
nameValuePair nameValuePair
optionalAttrs optionalAttrs
imap1 imap1
mapAttrs'
imap0 imap0
length length
filter filter
findFirst findFirst
toLower;# toLower
unique;
mkInitials = mkInitials =
name: name:
let let
lower = toLower name; # was builtins.toLower lower = toLower name;
noApos = builtins.replaceStrings [ "'" ] [ " " ] lower; noApos = builtins.replaceStrings [ "'" ] [ " " ] lower;
words = filter (w: w != "") (builtins.split " +" noApos); words = filter (w: w != "") (builtins.split " +" noApos);
letters = letters = concatStringsSep "" (builtins.map (w: builtins.substring 0 1 w) words);
concatStringsSep ""
(builtins.map (w: builtins.substring 0 1 w) words);
in in
if letters == "" then "loc" else builtins.substring 0 3 letters; if letters == "" then "loc" else builtins.substring 0 3 letters;
@ -38,7 +37,7 @@ let
in in
"${base}-${hash}"; "${base}-${hash}";
# Manual elemIndex so we don't care what nixpkgs version you're on # Manual elemIndex so we do not care what nixpkgs version you are on.
elemIndex = elemIndex =
name: list: name: list:
let let
@ -180,9 +179,9 @@ let
mkRoleRangeNamed = mkRoleRangeNamed =
{ location, typeName, roleName }: { location, typeName, roleName }:
let let
_ = assertMsg (subnetTypes ? typeName) _ = assertMsg (builtins.hasAttr typeName subnetTypes)
"metatron-addressing: unknown subnet type '${typeName}'"; "metatron-addressing: unknown subnet type '${typeName}'";
__ = assertMsg (roles ? roleName) __ = assertMsg (builtins.hasAttr roleName roles)
"metatron-addressing: unknown role '${roleName}'"; "metatron-addressing: unknown role '${roleName}'";
type = subnetTypes.${typeName}; type = subnetTypes.${typeName};
@ -193,9 +192,9 @@ let
mkIpNamed = mkIpNamed =
{ location, typeName, roleName, host }: { location, typeName, roleName, host }:
let let
_ = assertMsg (subnetTypes ? typeName) _ = assertMsg (builtins.hasAttr typeName subnetTypes)
"metatron-addressing: unknown subnet type '${typeName}'"; "metatron-addressing: unknown subnet type '${typeName}'";
__ = assertMsg (roles ? roleName) __ = assertMsg (builtins.hasAttr roleName roles)
"metatron-addressing: unknown role '${roleName}'"; "metatron-addressing: unknown role '${roleName}'";
type = subnetTypes.${typeName}; type = subnetTypes.${typeName};
@ -217,7 +216,7 @@ let
mkSubnetNamed = mkSubnetNamed =
{ location, typeName }: { location, typeName }:
let let
_ = assertMsg (subnetTypes ? typeName) _ = assertMsg (builtins.hasAttr typeName subnetTypes)
"metatron-addressing: unknown subnet type '${typeName}'"; "metatron-addressing: unknown subnet type '${typeName}'";
type = subnetTypes.${typeName}; type = subnetTypes.${typeName};
in in
@ -236,18 +235,59 @@ let
mkVlanNamed = mkVlanNamed =
{ location, typeName }: { location, typeName }:
let let
_ = assertMsg (subnetTypes ? typeName) _ = assertMsg (builtins.hasAttr typeName subnetTypes)
"metatron-addressing: unknown subnet type '${typeName}'"; "metatron-addressing: unknown subnet type '${typeName}'";
type = subnetTypes.${typeName}; type = subnetTypes.${typeName};
in in
mkVlan { inherit location type; }; mkVlan { inherit location type; };
# locationName → numeric id (0, 1, 2, …) asList = value:
if value == null then [ ]
else if builtins.isList value then value
else [ value ];
scopeFromCfg = cfg: {
owners =
asList (cfg.owners or null)
++ asList (cfg.owner or null);
admins =
asList (cfg.admins or null)
++ asList (cfg.admin or null);
users = asList (cfg.users or null);
domain = cfg.domain or null;
};
mergeScopes = parent: child:
let
c = scopeFromCfg child;
in
{
owners = unique (parent.owners ++ c.owners);
admins = unique (parent.admins ++ c.admins);
users = unique (parent.users ++ c.users);
domain = if c.domain != null then c.domain else parent.domain;
};
emptyScope = {
owners = [ ];
admins = [ ];
users = [ ];
domain = null;
};
materializeScope = scope:
{
inherit (scope) owners admins users;
}
// optionalAttrs (scope.domain != null) {
inherit (scope) domain;
};
# locationName -> numeric id (0, 1, 2, ...)
locationIdForSpec = locationIdForSpec =
spec: spec:
let let
locations = locations = spec.locations or (throw "metatron-addressing: spec.locations is required");
spec.locations or(throw "metatron-addressing: spec.locations is required");
locationNames = attrNames locations; locationNames = attrNames locations;
in in
name: name:
@ -259,42 +299,29 @@ let
else else
idx; idx;
# Just the host map: { deimos = { ip-address = "..."; fqdn = "..."; ... }; ... } hostRole = path: hostCfg:
mkHostsFromSpec = hostCfg.role or (throw "metatron-addressing: host '${path}' is missing required field 'role' for address generation");
spec:
let
locations =
spec.locations or (throw "metatron-addressing: spec.locations is required");
locationId = locationIdForSpec spec;
domain =
spec.domain or (throw "metatron-addressing: spec.domain is required for FQDN generation");
in
concatMapAttrs
(locationName: locationCfg:
let
loc = locationId locationName;
locCode = mkLocationCode locationName;
# Only treat attributes that are attrsets with a `hosts` attr as subnets hostMapForSubnet =
subnets = { loc, locCode, locationName, networkName, typeName, subnetCfg, scope }:
lib.filterAttrs (_: v: builtins.isAttrs v && v ? hosts) locationCfg;
in
concatMapAttrs
(typeName: subnetCfg:
let let
hostsForSubnet = subnetCfg.hosts or { }; hostsForSubnet = subnetCfg.hosts or { };
hostNames = filter (hn: builtins.substring 0 1 hn != "_") (attrNames hostsForSubnet);
# Only treat non-underscore-prefixed keys as hosts subnetSlug =
hostNames = if builtins.hasAttr typeName subnetSlugs
filter (hn: builtins.substring 0 1 hn != "_") (attrNames hostsForSubnet); then subnetSlugs.${typeName}
else typeName;
in in
listToAttrs (imap1 listToAttrs (imap1
(idx: hostName: (idx: hostName:
let let
path = "${locationName}.${networkName}.${typeName}.${hostName}";
hostCfg = hostsForSubnet.${hostName}; hostCfg = hostsForSubnet.${hostName};
roleName = hostCfg.role; hostScope = mergeScopes scope hostCfg;
roleName = hostRole path hostCfg;
# Count how many hosts of this role exist up to *and including* this one # Count how many hosts of this role exist up to and including this one.
roleIndex = roleIndex =
let let
prefix = lib.lists.sublist 0 idx hostNames; prefix = lib.lists.sublist 0 idx hostNames;
@ -308,15 +335,10 @@ let
ip = mkIpNamed { ip = mkIpNamed {
location = loc; location = loc;
inherit typeName; inherit typeName;
roleName = hostCfg.role; roleName = roleName;
host = hostId; host = hostId;
}; };
subnetSlug =
if builtins.hasAttr typeName subnetSlugs
then subnetSlugs.${typeName}
else typeName;
roleSlug = roleSlug =
if builtins.hasAttr roleName roleSlugs if builtins.hasAttr roleName roleSlugs
then roleSlugs.${roleName} then roleSlugs.${roleName}
@ -324,19 +346,21 @@ let
hostnameBase = "${roleSlug}-${builtins.toString hostId}"; hostnameBase = "${roleSlug}-${builtins.toString hostId}";
hostname = hostCfg.hostname or hostnameBase; hostname = hostCfg.hostname or hostnameBase;
fqdn = "${hostname}.${subnetSlug}.${locCode}.${domain}";
in in
nameValuePair hostName ( nameValuePair hostName (
{ {
ip-address = ip; ip-address = ip;
inherit hostname fqdn; inherit hostname;
# New context fields:
location = locationName; location = locationName;
network = networkName;
subnetType = typeName; subnetType = typeName;
subnetKey = "${locationName}-${typeName}"; subnetKey = "${locationName}-${networkName}-${typeName}";
} }
// optionalAttrs (hostScope.domain != null) {
fqdn = "${hostname}.${subnetSlug}.${locCode}.${hostScope.domain}";
}
// materializeScope hostScope
// optionalAttrs (hostCfg ? hw-address) { // optionalAttrs (hostCfg ? hw-address) {
inherit (hostCfg) hw-address; inherit (hostCfg) hw-address;
} }
@ -349,35 +373,70 @@ let
// optionalAttrs (hostCfg ? interface) { // optionalAttrs (hostCfg ? interface) {
inherit (hostCfg) interface; inherit (hostCfg) interface;
} }
) // optionalAttrs (hostCfg ? tags) {
) inherit (hostCfg) tags;
hostNames)) }
subnets) ))
locations; hostNames);
# Subnet map: { "home-dmz" = "10.1.0.0/19"; "home-main" = "..."; ... } mkHostsFromSpec =
mkSubnetsFromSpec =
spec: spec:
let let
locations = locations = spec.locations or (throw "metatron-addressing: spec.locations is required");
spec.locations or (throw "metatron-addressing: spec.locations is required");
locationId = locationIdForSpec spec; locationId = locationIdForSpec spec;
domain =
spec.domain or (throw "metatron-addressing: spec.domain is required");
in in
concatMapAttrs concatMapAttrs
(locationName: locationCfg: (locationName: locationCfg:
let let
loc = locationId locationName; loc = locationId locationName;
locCode = mkLocationCode locationName; locCode = mkLocationCode locationName;
locationScope = mergeScopes emptyScope locationCfg;
networks = locationCfg.networks or { };
in
concatMapAttrs
(networkName: networkCfg:
let
networkScope = mergeScopes locationScope networkCfg;
subnets = networkCfg.subnets or { };
in
concatMapAttrs
(typeName: subnetCfg:
let
subnetScope = mergeScopes networkScope subnetCfg;
in
hostMapForSubnet {
inherit loc locCode locationName networkName typeName subnetCfg;
scope = subnetScope;
})
subnets)
networks)
locations;
# Only attributes with `hosts` are subnets mkSubnetsFromSpec =
subnets = spec:
lib.filterAttrs (_: v: builtins.isAttrs v && v ? hosts) locationCfg; let
locations = spec.locations or (throw "metatron-addressing: spec.locations is required");
locationId = locationIdForSpec spec;
in
concatMapAttrs
(locationName: locationCfg:
let
loc = locationId locationName;
locCode = mkLocationCode locationName;
locationScope = mergeScopes emptyScope locationCfg;
networks = locationCfg.networks or { };
in
concatMapAttrs
(networkName: networkCfg:
let
networkScope = mergeScopes locationScope networkCfg;
subnets = networkCfg.subnets or { };
in in
mapAttrs' mapAttrs'
(typeName: subnetCfg: (typeName: subnetCfg:
let let
subnetScope = mergeScopes networkScope subnetCfg;
cidr = mkSubnetNamed { location = loc; inherit typeName; }; cidr = mkSubnetNamed { location = loc; inherit typeName; };
subnetSlug = subnetSlug =
@ -385,8 +444,6 @@ let
then subnetSlugs.${typeName} then subnetSlugs.${typeName}
else typeName; else typeName;
zone = "${subnetSlug}.${locCode}.${domain}";
vlan = vlan =
subnetCfg.vlan or subnetCfg.vlan or
subnetCfg._vlan or subnetCfg._vlan or
@ -411,28 +468,25 @@ let
}; };
in in
nameValuePair nameValuePair
"${locationName}-${typeName}" "${locationName}-${networkName}-${typeName}"
( (
{ {
inherit cidr locationName typeName zone vlan; inherit cidr locationName networkName typeName vlan;
} }
// optionalAttrs (subnetScope.domain != null) {
zone = "${subnetSlug}.${locCode}.${subnetScope.domain}";
}
// materializeScope subnetScope
// optionalAttrs (dhcpCfg != null) { // optionalAttrs (dhcpCfg != null) {
dhcp = dhcpCfg; dhcp = dhcpCfg;
dhcpRange = dhcpRange; dhcpRange = dhcpRange;
} }
)) ))
subnets) subnets)
networks)
locations; locations;
# Combined view, if you want both mkNetworkFromSpec = spec: {
mkNetworkFromSpec =
spec:
let
domain =
spec.domain or (throw "metatron-addressing: spec.domain is required");
in
{
inherit domain;
hosts = mkHostsFromSpec spec; hosts = mkHostsFromSpec spec;
subnets = mkSubnetsFromSpec spec; subnets = mkSubnetsFromSpec spec;
}; };
@ -448,12 +502,15 @@ in
mkIpNamed mkIpNamed
mkSubnet mkSubnet
mkSubnetNamed mkSubnetNamed
mkVlan
mkVlanNamed
mkHostsFromSpec mkHostsFromSpec
mkSubnetsFromSpec mkSubnetsFromSpec
mkNetworkFromSpec mkNetworkFromSpec
mkRoleRange mkRoleRange
mkRoleRangeNamed; mkRoleRangeNamed
mergeScopes;
# Shorthand; you were calling mkHosts before # Shorthand; you were calling mkHosts before.
mkHosts = mkNetworkFromSpec; mkHosts = mkNetworkFromSpec;
} }

224
meta.nix
View file

@ -3,22 +3,23 @@
locations = { locations = {
cloud = { cloud = {
owner = "yaro"; domain = "kasear.net";
dmz = {
hosts = { networks.default.subnets = {
dmz.hosts = {
eris = { eris = {
role = "router"; role = "router";
aliases = [ "frontend.kasear.net" ]; aliases = [
"frontend.kasear.net"
];
}; };
deimos-cloud = { deimos-cloud = {
role = "server"; role = "server";
}; };
}; };
};
infra = { infra.hosts = {
hosts = {
metatron = { metatron = {
role = "coreServer"; role = "coreServer";
}; };
@ -26,15 +27,28 @@
loki-cloud = { loki-cloud = {
role = "adminWorkstation"; role = "adminWorkstation";
}; };
io-cloud = {
role = "router";
};
europa-cloud = {
role = "router";
};
vpn-container = {
role = "server";
dns = false;
};
}; };
}; };
}; };
home = { norfolk = {
dmz = { domain = "kasear.net";
vlan = 1;
hosts = { networks.default.subnets = {
dmz.hosts = {
io = { io = {
role = "router"; role = "router";
aliases = [ "external.kasear.net" ]; aliases = [ "external.kasear.net" ];
@ -58,7 +72,6 @@
"test.kasear.net" "test.kasear.net"
"vault.kasear.net" "vault.kasear.net"
"vikali.kasear.net" "vikali.kasear.net"
"vpn.kasear.net"
"www.kasear.net" "www.kasear.net"
"yaro.kasear.net" "yaro.kasear.net"
]; ];
@ -69,27 +82,60 @@
dns = false; dns = false;
}; };
cloud-container = { role = "server"; dns = false; }; cloud-container = {
default-container = { role = "server"; dns = false; }; role = "server";
foregejo-container = { role = "server"; dns = false; }; dns = false;
majike-container = { role = "server"; dns = false; }; };
media-container = { role = "server"; dns = false; };
vault-container = { role = "server"; dns = false; }; default-container = {
vikali-container = { role = "server"; dns = false; }; role = "server";
vpn-container = { role = "server"; dns = false; }; dns = false;
yaro-container = { role = "server"; dns = false; }; };
foregejo-container = {
role = "server";
dns = false;
};
majike-container = {
role = "server";
dns = false;
};
media-container = {
role = "server";
dns = false;
};
vault-container = {
role = "server";
dns = false;
};
vikali-container = {
role = "server";
dns = false;
};
yaro-container = {
role = "server";
dns = false;
};
norfolk-dmz-dhcp-start = {
role = "pool";
hostId = 1;
dns = false;
};
norfolk-dmz-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
}; };
}; };
main = { main.hosts = {
vlan = 10;
dhcp = {
start = 1;
end = 250;
};
hosts = {
europa = { europa = {
role = "router"; role = "router";
aliases = [ "internal.kasear.net" ]; aliases = [ "internal.kasear.net" ];
@ -106,6 +152,11 @@
hw-address = "54:af:97:02:2f:15"; hw-address = "54:af:97:02:2f:15";
}; };
loki = {
role = "adminWorkstation";
hw-address = "70:85:c2:f4:1a:58";
};
luna = { luna = {
role = "infraDevice"; role = "infraDevice";
hw-address = "30:23:03:48:4c:75"; hw-address = "30:23:03:48:4c:75";
@ -114,7 +165,6 @@
phobos = { phobos = {
role = "server"; role = "server";
hw-address = "10:98:36:a9:4a:26"; hw-address = "10:98:36:a9:4a:26";
interface = "eno2";
aliases = [ aliases = [
"pbx.kasear.net" "pbx.kasear.net"
"private.kasear.net" "private.kasear.net"
@ -137,28 +187,39 @@
role = "phone"; role = "phone";
hw-address = "80:5e:c0:de:3d:66"; hw-address = "80:5e:c0:de:3d:66";
}; };
norfolk-main-dhcp-start = {
role = "pool";
hostId = 1;
dns = false;
};
norfolk-main-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
}; };
}; };
guest = { guest.hosts = {
vlan = 20;
dhcp = {
start = 1;
end = 250;
};
hosts = {
europa-guest = { europa-guest = {
role = "router"; role = "router";
}; };
norfolk-guest-dhcp-start = {
role = "pool";
hostId = 1;
dns = false;
};
norfolk-guest-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
}; };
}; };
iot = { iot.hosts = {
vlan = 30;
hosts = {
europa-iot = { europa-iot = {
role = "router"; role = "router";
}; };
@ -183,6 +244,11 @@
hw-address = "08:84:9d:74:4d:c6"; hw-address = "08:84:9d:74:4d:c6";
}; };
loki-iot = {
role = "adminWorkstation";
hw-address = "70:85:c2:f4:1a:58";
};
camera1 = { camera1 = {
role = "camera"; role = "camera";
hw-address = "9c:8e:cd:38:95:1f"; hw-address = "9c:8e:cd:38:95:1f";
@ -204,18 +270,26 @@
role = "appliance"; role = "appliance";
hw-address = "04:e4:b6:23:81:fc"; hw-address = "04:e4:b6:23:81:fc";
}; };
mercury-iot = {
role = "mobile";
hw-address = "ac:3e:b1:77:65:2e";
};
norfolk-iot-dhcp-start = {
role = "pool";
hostId = 1;
dns = false;
};
norfolk-iot-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
}; };
}; };
storage = { storage.hosts = {
vlan = 40;
dhcp = {
start = 1;
end = 250;
};
hosts = {
europa-storage = { europa-storage = {
role = "router"; role = "router";
}; };
@ -224,13 +298,30 @@
role = "nas"; role = "nas";
aliases = [ "storage.kasear.net" ]; aliases = [ "storage.kasear.net" ];
}; };
loki-storage = {
role = "adminWorkstation";
hw-address = "00:07:43:13:c4:90";
};
norfolk-storage-dhcp-start = {
role = "pool";
hostId = 1;
dns = false;
};
norfolk-storage-dhcp-end = {
role = "pool";
hostId = 250;
dns = false;
}; };
}; };
management = { management.hosts = {
vlan = 70; europa-management = {
role = "router";
};
hosts = {
deimos-idrac = { deimos-idrac = {
role = "oobMgmt"; role = "oobMgmt";
hw-address = "10:98:36:a0:2c:b3"; hw-address = "10:98:36:a0:2c:b3";
@ -245,13 +336,20 @@
role = "oobMgmt"; role = "oobMgmt";
hw-address = "14:18:77:51:4b:b5"; hw-address = "14:18:77:51:4b:b5";
}; };
};
}; norfolk-management-dhcp-start = {
}; role = "pool";
hostId = 1;
dns = false;
}; };
# You can add these later if you want to match the bigger design: norfolk-management-dhcp-end = {
# systems = { }; role = "pool";
# consumers = { }; hostId = 250;
# policy = { }; dns = false;
};
};
};
};
};
} }