nixpkgs/nixos/tests/tinc/default.nix

140 lines
4.2 KiB
Nix

import ../make-test-python.nix ({ lib, ... }:
let
snakeoil-keys = import ./snakeoil-keys.nix;
hosts = lib.attrNames snakeoil-keys;
subnetOf = name: config:
let
subnets = config.services.tinc.networks.myNetwork.hostSettings.${name}.subnets;
in
(builtins.head subnets).address;
makeTincHost = name: { subnet, extraConfig ? { } }: lib.mkMerge [
{
subnets = [{ address = subnet; }];
settings = {
Ed25519PublicKey = snakeoil-keys.${name}.ed25519Public;
};
rsaPublicKey = snakeoil-keys.${name}.rsaPublic;
}
extraConfig
];
makeTincNode = { config, ... }: name: extraConfig: lib.mkMerge [
{
services.tinc.networks.myNetwork = {
inherit name;
rsaPrivateKeyFile =
builtins.toFile "rsa.priv" snakeoil-keys.${name}.rsaPrivate;
ed25519PrivateKeyFile =
builtins.toFile "ed25519.priv" snakeoil-keys.${name}.ed25519Private;
hostSettings = lib.mapAttrs makeTincHost {
static = {
subnet = "10.0.0.11";
# Only specify the addresses in the node's vlans, Tinc does not
# seem to try each one, unlike the documentation suggests...
extraConfig.addresses = map
(vlan: { address = "192.168.${toString vlan}.11"; port = 655; })
config.virtualisation.vlans;
};
dynamic1 = { subnet = "10.0.0.21"; };
dynamic2 = { subnet = "10.0.0.22"; };
};
};
networking.useDHCP = false;
networking.interfaces."tinc.myNetwork" = {
virtual = true;
virtualType = "tun";
ipv4.addresses = [{
address = subnetOf name config;
prefixLength = 24;
}];
};
# Prevents race condition between NixOS service and tinc creating the
# interface.
# See: https://github.com/NixOS/nixpkgs/issues/27070
systemd.services."tinc.myNetwork" = {
after = [ "network-addresses-tinc.myNetwork.service" ];
requires = [ "network-addresses-tinc.myNetwork.service" ];
};
networking.firewall.allowedTCPPorts = [ 655 ];
networking.firewall.allowedUDPPorts = [ 655 ];
}
extraConfig
];
in
{
name = "tinc";
meta.maintainers = with lib.maintainers; [ minijackson ];
nodes = {
static = { ... } @ args:
makeTincNode args "static" {
virtualisation.vlans = [ 1 2 ];
networking.interfaces.eth1.ipv4.addresses = [{
address = "192.168.1.11";
prefixLength = 24;
}];
networking.interfaces.eth2.ipv4.addresses = [{
address = "192.168.2.11";
prefixLength = 24;
}];
};
dynamic1 = { ... } @ args:
makeTincNode args "dynamic1" {
virtualisation.vlans = [ 1 ];
};
dynamic2 = { ... } @ args:
makeTincNode args "dynamic2" {
virtualisation.vlans = [ 2 ];
};
};
testScript = ''
start_all()
static.wait_for_unit("tinc.myNetwork.service")
dynamic1.wait_for_unit("tinc.myNetwork.service")
dynamic2.wait_for_unit("tinc.myNetwork.service")
# Static is accessible by the other hosts
dynamic1.succeed("ping -c5 192.168.1.11")
dynamic2.succeed("ping -c5 192.168.2.11")
# The other hosts are in separate vlans
dynamic1.fail("ping -c5 192.168.2.11")
dynamic2.fail("ping -c5 192.168.1.11")
# Each host can ping themselves through Tinc
static.succeed("ping -c5 10.0.0.11")
dynamic1.succeed("ping -c5 10.0.0.21")
dynamic2.succeed("ping -c5 10.0.0.22")
# Static is accessible by the other hosts through Tinc
dynamic1.succeed("ping -c5 10.0.0.11")
dynamic2.succeed("ping -c5 10.0.0.11")
# Static can access the other hosts through Tinc
static.succeed("ping -c5 10.0.0.21")
static.succeed("ping -c5 10.0.0.22")
# The other hosts in separate vlans can access each other through Tinc
dynamic1.succeed("ping -c5 10.0.0.22")
dynamic2.succeed("ping -c5 10.0.0.21")
'';
})