summary refs log tree commit diff
path: root/nixos/tests/tinc/default.nix
blob: 31b675ad35c067c96f26d7da2fe49f49c78ee158 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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")
    '';
  })