Now maps to config (json compatible) to a recursive attrset that is more ergonomic (not json compatible)
parent
fcb8a4d0f8
commit
60ac560c64
@ -0,0 +1,99 @@
|
||||
{lib}: wirenix-config:
|
||||
let
|
||||
# Math
|
||||
# extract-key :: string -> list -> attrSet
|
||||
# Example:
|
||||
# listOfSetsToSetByKey "primary" [ {primary = "foo"; secondary = 1; tertiary = "one"} {primary = "bar"; secondary = 2; tertiary = "two"} ]
|
||||
# {foo = {secondary = 1; tertiary = "one"}; bar = {secondary = 2; tertiary = "two"};}
|
||||
listOfSetsToSetByKey = key: list:
|
||||
builtins.listToAttrs (
|
||||
lib.lists.forEach list (elem: {
|
||||
name = elem."${key}";
|
||||
value = lib.attrsets.filterAttrs (n: v: n != key) elem;
|
||||
})
|
||||
);
|
||||
# returns true if `elem` is in `list`
|
||||
inList = elem: list: builtins.any (e: e == elem) list;
|
||||
# adds colons to a string every 4 characters for IPv6 shenanigans
|
||||
add-colons = string:
|
||||
if ((builtins.stringLength string) > 4)
|
||||
then
|
||||
((builtins.substring 0 4 string) + ":" + (add-colons (builtins.substring 4 32 string)))
|
||||
else string;
|
||||
|
||||
# Peer Information
|
||||
# Helper functions for querying data about peers from the config
|
||||
peerInfo = {
|
||||
# last 20 (hardcoded atm) characters (80 bits) of the peer's IPv6 address
|
||||
IPSuffix = peerName: builtins.substring 0 20 (builtins.hashString "sha256" peerName);
|
||||
# list of subnets (as subnet attrset in wirenix config) the peer belongs to
|
||||
subnets = peer: builtins.filter (subnet: inList subnet.name peer.subnets) wirenix-config.subnets;
|
||||
# list of groups the peer connects to
|
||||
groupConnections = peer: builtins.catAttrs "group" peer.connections;
|
||||
# list of peers the peer connects to
|
||||
directConnections = peer: builtins.catAttrs "peer" peer.connections;
|
||||
# gets the peer (as peer attrset in wirenix config) from a name
|
||||
peerFromName = peerName: builtins.head (builtins.filter (peer: peer.name == peerName) wirenix-config.peers);
|
||||
# gets all peers (as peer attrset in wirenix config) the are in a group
|
||||
peersInGroup = groupName: builtins.filter (peer: inList groupName peer.groups) wirenix-config.peers;
|
||||
# gets all peers (as peer attrset in wirenix config) that the given peer connects to, may contain the peer itself and duplicates
|
||||
connectionsUnfiltered = peer: (builtins.map (peerInfo.peerFromName) (peerInfo.directConnections peer)) ++ (builtins.concatMap (group: peerInfo.peersInGroup group) (peerInfo.groupConnections peer));
|
||||
# gets all peers (as peer attrset in wirenix config) that the given peer connects to, will not contain the peer itself or duplicates
|
||||
connections = peer: lib.lists.remove peer (lib.lists.unique (peerInfo.connectionsUnfiltered peer));
|
||||
# returns the peer's IP when given the peer's name and subnet name
|
||||
IP = subnetName: PeerName: (add-colons ((subnetInfo.prefix subnetName) + (peerInfo.IPSuffix PeerName))) + "/80";
|
||||
};
|
||||
# Subnet Information
|
||||
# Helper functions for querying data about subnets from the config
|
||||
subnetInfo = {
|
||||
# gets the subnet (as subnet attrset in wirenix config) from a name
|
||||
subnetFromName = subnetName: builtins.head (builtins.filter (subnet: subnet.name == subnetName) wirenix-config.subnets);
|
||||
# gets the first 10 characters of the IPV6 address for the subnet
|
||||
prefix = subnetName: "fd" + (builtins.substring 0 10 (builtins.hashString "sha256" subnetName));
|
||||
# gets all peers (as peer attrset in wirenix config) that belong to the subnet
|
||||
peers = subnet: builtins.filter (peer: inList subnet.name peer.subnets) wirenix-config.peers;
|
||||
};
|
||||
|
||||
# Mappers take a peer or subnet from the config and convert it
|
||||
# into a recursive attrset that is better suited for nix configs
|
||||
mappers = rec {
|
||||
|
||||
# Maps a wirenix config subnet to a recursive attrset, structure is as follows:
|
||||
# peers: a set of peers (as similar recursive attrsets), keyed by name
|
||||
# ip: the subnet ip in CIDR notation
|
||||
subnetMap = subnet: {
|
||||
name = subnet.name;
|
||||
peers = listOfSetsToSetByKey "name" (builtins.map (peerMap) (subnetInfo.peers subnet));
|
||||
ip = (add-colons (subnetInfo.prefix subnet.name)) + "::/80";
|
||||
};
|
||||
|
||||
# Maps a wirenix config peer to a recursive attrset, structure is as follows:
|
||||
# subnets: a set of subnets (as similar recursive attrsets), keyed by name, with the following structure:
|
||||
# subnet: the subnet as described in the subnetMap function's description
|
||||
# ip: the peer's ip on the subnet (can only be one IP at the moment)
|
||||
# peers: peers (as recursive attrset) on the subnet that the current peer has connections with
|
||||
# connections: a set of all peers (as recursive attrset) which the current peer connects to, keyed by name
|
||||
# publicKey: the peer's public key
|
||||
# privateKeyFile: the location of the peer's private key
|
||||
peerMap = peer: {
|
||||
name = peer.name;
|
||||
subnets = listOfSetsToSetByKey "name" (
|
||||
builtins.map (subnet: {
|
||||
name = subnet.name;
|
||||
subnet = lib.attrsets.filterAttrs (n: v: n != "name") (subnetMap subnet);
|
||||
ip = peerInfo.IP subnet.name peer.name;
|
||||
peers = listOfSetsToSetByKey "name" (builtins.map (peerMap) (builtins.filter (otherPeer: inList subnet.name otherPeer.subnets) (peerInfo.connections peer)));
|
||||
}) (peerInfo.subnets peer)
|
||||
);
|
||||
connections = listOfSetsToSetByKey "name" (builtins.map (peerMap) (peerInfo.connections peer));
|
||||
publicKey = peer.publicKey;
|
||||
privateKeyFile = peer.privateKeyFile;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
peerFromName = lib.attrsets.filterAttrs (n: v: n != "name") (mappers.peerMap peerInfo.peerFromName);
|
||||
subnetFromName = lib.attrsets.filterAttrs (n: v: n != "name") (mappers.subnetMap subnetInfo.subnetFromName);
|
||||
peers = listOfSetsToSetByKey "name" (builtins.map (mappers.peerMap) (wirenix-config.peers));
|
||||
subnets = listOfSetsToSetByKey "name" (builtins.map (mappers.subnetMap) (wirenix-config.subnets));
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
{lib}: wirenix-config:
|
||||
let
|
||||
# Math
|
||||
inList = elem: list: builtins.any (e: e == elem) list;
|
||||
# IP
|
||||
add-colons = string:
|
||||
if ((builtins.stringLength string) > 4)
|
||||
then
|
||||
((builtins.substring 0 4 string) + ":" + (add-colons (builtins.substring 4 32 string)))
|
||||
else string;
|
||||
|
||||
# Peer Information
|
||||
peerInfo = {
|
||||
peerSuffix = peerName: builtins.substring 0 20 (builtins.hashString "sha256" peerName);
|
||||
peerSubnets = peer: builtins.filter (subnet: inList subnet.name peer.subnets) wirenix-config.subnets;
|
||||
peerGroups = peer: builtins.catAttrs "group" peer.peers;
|
||||
directPeers = peer: builtins.catAttrs "peer" peer.peers;
|
||||
peerFromName = peerName: builtins.head (builtins.filter (peer: peer.name == peerName) wirenix-config.peers);
|
||||
peersInGroup = groupName: builtins.filter (peer: inList groupName peer.groups) wirenix-config.peers;
|
||||
peerPeersUnfiltered = peer: (builtins.map (peerInfo.peerFromName) (peerInfo.directPeers peer)) ++ (builtins.concatMap (group: peerInfo.peersInGroup group) (peerInfo.peerGroups peer));
|
||||
peerIP = subnetName: PeerName: (add-colons ((subnetInfo.subnetPrefix subnetName) + (peerInfo.peerSuffix PeerName))) + "/80";
|
||||
};
|
||||
# Subnet Information
|
||||
subnetInfo = {
|
||||
subnetPrefix = subnetName: "fd" + (builtins.substring 0 10 (builtins.hashString "sha256" subnetName));
|
||||
subnetPeers = subnet: builtins.filter (peer: inList subnet.name peer.subnets) wirenix-config.peers;
|
||||
};
|
||||
in
|
||||
{
|
||||
peer = peer:
|
||||
rec {
|
||||
subnets = peerInfo.peerSubnets peer;
|
||||
peers = lib.lists.remove peer (lib.lists.unique (peerInfo.peerPeersUnfiltered peer));
|
||||
ip = subnet: peerInfo.peerIP subnet.name peer.name;
|
||||
peersOnSubnet = subnet: builtins.filter (otherPeer: inList subnet.name otherPeer.subnets) peers;
|
||||
publicKey = peer.publicKey;
|
||||
privateKeyFile = peer.privateKeyFile;
|
||||
};
|
||||
subnet = subnet:
|
||||
{
|
||||
peers = subnetInfo.subnetPeers subnet;
|
||||
ip = (add-colons (subnetInfo.subnetPrefix subnet.name)) + "::/80";
|
||||
};
|
||||
}
|
||||
# subnets:
|
||||
# networkOne:
|
||||
# prefix: "auto" or "none" or canonicalized ipv6
|
||||
# ipv4: canonicalized ipv4 or "none"
|
||||
# ipv6: canonicalized ipv6 or "auto" or "none"
|
||||
# peers:
|
||||
# peerOne:
|
||||
# pubKey: "ABC..." Or "auto"
|
||||
# subnets:
|
||||
# networkOne:
|
||||
# - ipv4: ip
|
||||
# - ipv6: "auto" or "none" or ip
|
||||
# groups:
|
||||
# - "groupOne"
|
||||
# peers:
|
||||
# - peer: "peerTwo"
|
||||
# - group: "groupOne"
|
Loading…
Reference in New Issue