+2
nixos/doc/manual/release-notes/rl-2405.section.md
+2
nixos/doc/manual/release-notes/rl-2405.section.md
···
16
16
17
17
- [maubot](https://github.com/maubot/maubot), a plugin-based Matrix bot framework. Available as [services.maubot](#opt-services.maubot.enable).
18
18
19
+
- [GNS3](https://www.gns3.com/), a network software emulator. Available as [services.gns3-server](#opt-services.gns3-server.enable).
20
+
19
21
- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable).
20
22
21
23
## Backward Incompatibilities {#sec-release-24.05-incompatibilities}
+1
nixos/modules/module-list.nix
+1
nixos/modules/module-list.nix
···
939
939
./services/networking/ghostunnel.nix
940
940
./services/networking/git-daemon.nix
941
941
./services/networking/globalprotect-vpn.nix
942
+
./services/networking/gns3-server.nix
942
943
./services/networking/gnunet.nix
943
944
./services/networking/go-autoconfig.nix
944
945
./services/networking/go-neb.nix
+31
nixos/modules/services/networking/gns3-server.md
+31
nixos/modules/services/networking/gns3-server.md
···
1
+
# GNS3 Server {#module-services-gns3-server}
2
+
3
+
[GNS3](https://www.gns3.com/), a network software emulator.
4
+
5
+
## Basic Usage {#module-services-gns3-server-basic-usage}
6
+
7
+
A minimal configuration looks like this:
8
+
9
+
```nix
10
+
{
11
+
services.gns3-server = {
12
+
enable = true;
13
+
14
+
auth = {
15
+
enable = true;
16
+
user = "gns3";
17
+
passwordFile = "/var/lib/secrets/gns3_password";
18
+
};
19
+
20
+
ssl = {
21
+
enable = true;
22
+
certFile = "/var/lib/gns3/ssl/cert.pem";
23
+
keyFile = "/var/lib/gns3/ssl/key.pem";
24
+
};
25
+
26
+
dynamips.enable = true;
27
+
ubridge.enable = true;
28
+
vpcs.enable = true;
29
+
};
30
+
}
31
+
```
+263
nixos/modules/services/networking/gns3-server.nix
+263
nixos/modules/services/networking/gns3-server.nix
···
1
+
{ config, lib, pkgs, ... }:
2
+
3
+
let
4
+
cfg = config.services.gns3-server;
5
+
6
+
settingsFormat = pkgs.formats.ini { };
7
+
configFile = settingsFormat.generate "gns3-server.conf" cfg.settings;
8
+
9
+
in {
10
+
meta = {
11
+
doc = ./gns3-server.md;
12
+
maintainers = [ lib.maintainers.anthonyroussel ];
13
+
};
14
+
15
+
options = {
16
+
services.gns3-server = {
17
+
enable = lib.mkEnableOption (lib.mdDoc "GNS3 Server daemon");
18
+
19
+
package = lib.mkPackageOptionMD pkgs "gns3-server" { };
20
+
21
+
auth = {
22
+
enable = lib.mkEnableOption (lib.mdDoc "password based HTTP authentication to access the GNS3 Server");
23
+
24
+
user = lib.mkOption {
25
+
type = lib.types.nullOr lib.types.str;
26
+
default = null;
27
+
example = "gns3";
28
+
description = lib.mdDoc ''Username used to access the GNS3 Server.'';
29
+
};
30
+
31
+
passwordFile = lib.mkOption {
32
+
type = lib.types.nullOr lib.types.path;
33
+
default = null;
34
+
example = "/run/secrets/gns3-server-password";
35
+
description = lib.mdDoc ''
36
+
A file containing the password to access the GNS3 Server.
37
+
38
+
::: {.warning}
39
+
This should be a string, not a nix path, since nix paths
40
+
are copied into the world-readable nix store.
41
+
:::
42
+
'';
43
+
};
44
+
};
45
+
46
+
settings = lib.mkOption {
47
+
type = lib.types.submodule { freeformType = settingsFormat.type; };
48
+
default = {};
49
+
example = { host = "127.0.0.1"; port = 3080; };
50
+
description = lib.mdDoc ''
51
+
The global options in `config` file in ini format.
52
+
53
+
Refer to <https://docs.gns3.com/docs/using-gns3/administration/gns3-server-configuration-file/>
54
+
for all available options.
55
+
'';
56
+
};
57
+
58
+
log = {
59
+
file = lib.mkOption {
60
+
type = lib.types.nullOr lib.types.path;
61
+
default = "/var/log/gns3/server.log";
62
+
description = lib.mdDoc ''Path of the file GNS3 Server should log to.'';
63
+
};
64
+
65
+
debug = lib.mkEnableOption (lib.mdDoc "debug logging");
66
+
};
67
+
68
+
ssl = {
69
+
enable = lib.mkEnableOption (lib.mdDoc "SSL encryption");
70
+
71
+
certFile = lib.mkOption {
72
+
type = lib.types.nullOr lib.types.path;
73
+
default = null;
74
+
example = "/var/lib/gns3/ssl/server.pem";
75
+
description = lib.mdDoc ''
76
+
Path to the SSL certificate file. This certificate will
77
+
be offered to, and may be verified by, clients.
78
+
'';
79
+
};
80
+
81
+
keyFile = lib.mkOption {
82
+
type = lib.types.nullOr lib.types.path;
83
+
default = null;
84
+
example = "/var/lib/gns3/ssl/server.key";
85
+
description = lib.mdDoc "Private key file for the certificate.";
86
+
};
87
+
};
88
+
89
+
dynamips = {
90
+
enable = lib.mkEnableOption (lib.mdDoc ''Whether to enable Dynamips support.'');
91
+
package = lib.mkPackageOptionMD pkgs "dynamips" { };
92
+
};
93
+
94
+
ubridge = {
95
+
enable = lib.mkEnableOption (lib.mdDoc ''Whether to enable uBridge support.'');
96
+
package = lib.mkPackageOptionMD pkgs "ubridge" { };
97
+
};
98
+
99
+
vpcs = {
100
+
enable = lib.mkEnableOption (lib.mdDoc ''Whether to enable VPCS support.'');
101
+
package = lib.mkPackageOptionMD pkgs "vpcs" { };
102
+
};
103
+
};
104
+
};
105
+
106
+
config = let
107
+
flags = {
108
+
enableDocker = config.virtualisation.docker.enable;
109
+
enableLibvirtd = config.virtualisation.libvirtd.enable;
110
+
};
111
+
112
+
in lib.mkIf cfg.enable {
113
+
assertions = [
114
+
{
115
+
assertion = cfg.ssl.enable -> cfg.ssl.certFile != null;
116
+
message = "Please provide a certificate to use for SSL encryption.";
117
+
}
118
+
{
119
+
assertion = cfg.ssl.enable -> cfg.ssl.keyFile != null;
120
+
message = "Please provide a private key to use for SSL encryption.";
121
+
}
122
+
{
123
+
assertion = cfg.auth.enable -> cfg.auth.user != null;
124
+
message = "Please provide a username to use for HTTP authentication.";
125
+
}
126
+
{
127
+
assertion = cfg.auth.enable -> cfg.auth.passwordFile != null;
128
+
message = "Please provide a password file to use for HTTP authentication.";
129
+
}
130
+
];
131
+
132
+
users.groups.ubridge = lib.mkIf cfg.ubridge.enable { };
133
+
134
+
security.wrappers.ubridge = lib.mkIf cfg.ubridge.enable {
135
+
capabilities = "cap_net_raw,cap_net_admin=eip";
136
+
group = "ubridge";
137
+
owner = "root";
138
+
permissions = "u=rwx,g=rx,o=r";
139
+
source = lib.getExe cfg.ubridge.package;
140
+
};
141
+
142
+
services.gns3-server.settings = lib.mkMerge [
143
+
{
144
+
Server = {
145
+
appliances_path = lib.mkDefault "/var/lib/gns3/appliances";
146
+
configs_path = lib.mkDefault "/var/lib/gns3/configs";
147
+
images_path = lib.mkDefault "/var/lib/gns3/images";
148
+
projects_path = lib.mkDefault "/var/lib/gns3/projects";
149
+
symbols_path = lib.mkDefault "/var/lib/gns3/symbols";
150
+
};
151
+
}
152
+
(lib.mkIf (cfg.ubridge.enable) {
153
+
Server.ubridge_path = lib.mkDefault (lib.getExe cfg.ubridge.package);
154
+
})
155
+
(lib.mkIf (cfg.auth.enable) {
156
+
Server = {
157
+
auth = lib.mkDefault (lib.boolToString cfg.auth.enable);
158
+
user = lib.mkDefault cfg.auth.user;
159
+
password = lib.mkDefault "@AUTH_PASSWORD@";
160
+
};
161
+
})
162
+
(lib.mkIf (cfg.vpcs.enable) {
163
+
VPCS.vpcs_path = lib.mkDefault (lib.getExe cfg.vpcs.package);
164
+
})
165
+
(lib.mkIf (cfg.dynamips.enable) {
166
+
Dynamips.dynamips_path = lib.mkDefault (lib.getExe cfg.dynamips.package);
167
+
})
168
+
];
169
+
170
+
systemd.services.gns3-server = let
171
+
commandArgs = lib.cli.toGNUCommandLineShell { } {
172
+
config = "/etc/gns3/gns3_server.conf";
173
+
pid = "/run/gns3/server.pid";
174
+
log = cfg.log.file;
175
+
ssl = cfg.ssl.enable;
176
+
# These are implicitly not set if `null`
177
+
certfile = cfg.ssl.certFile;
178
+
certkey = cfg.ssl.keyFile;
179
+
};
180
+
in
181
+
{
182
+
description = "GNS3 Server";
183
+
184
+
after = [ "network.target" "network-online.target" ];
185
+
wantedBy = [ "multi-user.target" ];
186
+
wants = [ "network-online.target" ];
187
+
188
+
# configFile cannot be stored in RuntimeDirectory, because GNS3
189
+
# uses the `--config` base path to stores supplementary configuration files at runtime.
190
+
#
191
+
preStart = ''
192
+
install -m660 ${configFile} /etc/gns3/gns3_server.conf
193
+
194
+
${lib.optionalString cfg.auth.enable ''
195
+
${pkgs.replace-secret}/bin/replace-secret \
196
+
'@AUTH_PASSWORD@' \
197
+
"''${CREDENTIALS_DIRECTORY}/AUTH_PASSWORD" \
198
+
/etc/gns3/gns3_server.conf
199
+
''}
200
+
'';
201
+
202
+
path = lib.optional flags.enableLibvirtd pkgs.qemu;
203
+
204
+
reloadTriggers = [ configFile ];
205
+
206
+
serviceConfig = {
207
+
ConfigurationDirectory = "gns3";
208
+
ConfigurationDirectoryMode = "0750";
209
+
DynamicUser = true;
210
+
Environment = "HOME=%S/gns3";
211
+
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
212
+
ExecStart = "${lib.getExe cfg.package} ${commandArgs}";
213
+
Group = "gns3";
214
+
LimitNOFILE = 16384;
215
+
LoadCredential = lib.mkIf cfg.auth.enable [ "AUTH_PASSWORD:${cfg.auth.passwordFile}" ];
216
+
LogsDirectory = "gns3";
217
+
LogsDirectoryMode = "0750";
218
+
PIDFile = "/run/gns3/server.pid";
219
+
Restart = "on-failure";
220
+
RestartSec = 5;
221
+
RuntimeDirectory = "gns3";
222
+
StateDirectory = "gns3";
223
+
StateDirectoryMode = "0750";
224
+
SupplementaryGroups = lib.optional flags.enableDocker "docker"
225
+
++ lib.optional flags.enableLibvirtd "libvirtd"
226
+
++ lib.optional cfg.ubridge.enable "ubridge";
227
+
User = "gns3";
228
+
WorkingDirectory = "%S/gns3";
229
+
230
+
# Hardening
231
+
DeviceAllow = lib.optional flags.enableLibvirtd "/dev/kvm";
232
+
DevicePolicy = "closed";
233
+
LockPersonality = true;
234
+
MemoryDenyWriteExecute = true;
235
+
NoNewPrivileges = true;
236
+
PrivateTmp = true;
237
+
PrivateUsers = true;
238
+
# Don't restrict ProcSubset because python3Packages.psutil requires read access to /proc/stat
239
+
# ProcSubset = "pid";
240
+
ProtectClock = true;
241
+
ProtectControlGroups = true;
242
+
ProtectHome = true;
243
+
ProtectHostname = true;
244
+
ProtectKernelLogs = true;
245
+
ProtectKernelModules = true;
246
+
ProtectKernelTunables = true;
247
+
ProtectProc = "invisible";
248
+
ProtectSystem = "strict";
249
+
RestrictAddressFamilies = [
250
+
"AF_INET"
251
+
"AF_INET6"
252
+
"AF_NETLINK"
253
+
"AF_UNIX"
254
+
"AF_PACKET"
255
+
];
256
+
RestrictNamespaces = true;
257
+
RestrictRealtime = true;
258
+
RestrictSUIDSGID = true;
259
+
UMask = "0077";
260
+
};
261
+
};
262
+
};
263
+
}