about summary refs log tree commit diff
path: root/hosts/carmel/networking.nix
blob: fed5f80ad40e078dc0218d3d2a3fcf5ceb4754c0 (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
{ lib, ... }:
let
  ethLink = (name:
    (mac: {
      matchConfig = {
        Type = "ether";
        MACAddress = mac;
      };
      linkConfig.Name = name;
    }));

  vlanNetdev = (name:
    (id: {
      netdevConfig = {
        Name = name;
        Kind = "vlan";
      };
      vlanConfig.Id = id;
    }));

  vlanNetwork = (name:
    (id: {
      matchConfig.Name = name;

      # Embed ID directly in IPv4 address for clarity.
      address = [ "192.168.${toString id}.1/24" ];
    }));
in
{
  systemd.network = {
    enable = true;

    links."10-wan0" = ethLink "wan0" "a8:a1:59:43:95:36";
    networks."10-wan0" = {
      matchConfig.Name = "wan0";
      networkConfig.DHCP = "ipv4";
      dhcpV4Config = {
        UseDNS = true;
        UseDomains = true;
      };
    };

    links."15-mgmt0" = ethLink "mgmt0" "a0:36:9f:fa:5d:6c";
    networks."15-mgmt0" = {
      matchConfig.Name = "mgmt0";
      address = [ "192.168.0.1/24" ];
      vlan = [ "iot" "guest" ];
      networkConfig = {
        DHCP = "no";
        Domains = "home";
      };
    };

    # unused interface
    links."16-mgmt1" = ethLink "mgmt1" "a0:36:9f:fa:5d:6d";

    # IoT VLAN.
    netdevs."25-iot" = vlanNetdev "iot" 10;
    networks."25-iot" = vlanNetwork "iot" 10;

    # Guest VLAN.
    netdevs."30-guest" = vlanNetdev "guest" 20;
    networks."30-guest" = vlanNetwork "guest" 20;

    # ignore these interfaces, as they are not used
    wait-online.ignoredInterfaces = [ "mgmt1" "wlp8s0" ];
  };

  # don't use systemd-resolved on the router
  services.resolved.enable = false;

  networking.hostName = "carmel";
  networking.useDHCP = false;

  networking.firewall = {
    enable = true;
    allowPing = true;
    # If rejectPackets = true, refused packets are rejected rather than dropped (ignored). This
    # means that an ICMP "port unreachable" error message is sent back to the client (or a TCP RST
    # packet in case of an existing connection). Rejecting packets makes port scanning somewhat
    # easier.
    rejectPackets = false;

    trustedInterfaces = [ "mgmt0" "iot" "guest" "wg0" ];

    logRefusedConnections = true;
    logRefusedPackets = false;
    logReversePathDrops = true;

    interfaces = {
      "wan0" = {
        allowedTCPPorts = [
          22 # ssh
          51413 # transmission
        ];
        allowedUDPPorts = [
          35947 # wireguard
          51413 # transmission
        ];
      };
    };
  };

  networking.nat = {
    enable = true;
    externalInterface = "wan0";
    internalInterfaces = [ "mgmt0" "guest" "iot" ];
  };

  networking.private-wireguard.enable = true;
  my.services.tailscale.enable = true;
}