1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.endlessh;
9in
10{
11 options.services.endlessh = {
12 enable = lib.mkEnableOption "endlessh service";
13
14 port = lib.mkOption {
15 type = lib.types.port;
16 default = 2222;
17 example = 22;
18 description = ''
19 Specifies on which port the endlessh daemon listens for SSH
20 connections.
21
22 Setting this to `22` may conflict with {option}`services.openssh`.
23 '';
24 };
25
26 extraOptions = lib.mkOption {
27 type = with lib.types; listOf str;
28 default = [ ];
29 example = [
30 "-6"
31 "-d 9000"
32 "-v"
33 ];
34 description = ''
35 Additional command line options to pass to the endlessh daemon.
36 '';
37 };
38
39 openFirewall = lib.mkOption {
40 type = lib.types.bool;
41 default = false;
42 description = ''
43 Whether to open a firewall port for the SSH listener.
44 '';
45 };
46 };
47
48 config = lib.mkIf cfg.enable {
49 systemd.services.endlessh = {
50 description = "SSH tarpit";
51 documentation = [ "man:endlessh(1)" ];
52 requires = [ "network.target" ];
53 wantedBy = [ "multi-user.target" ];
54 serviceConfig =
55 let
56 needsPrivileges = cfg.port < 1024;
57 capabilities = [ "" ] ++ lib.optionals needsPrivileges [ "CAP_NET_BIND_SERVICE" ];
58 rootDirectory = "/run/endlessh";
59 in
60 {
61 Restart = "always";
62 ExecStart =
63 with cfg;
64 lib.concatStringsSep " " (
65 [
66 "${pkgs.endlessh}/bin/endlessh"
67 "-p ${toString port}"
68 ]
69 ++ extraOptions
70 );
71 DynamicUser = true;
72 RootDirectory = rootDirectory;
73 BindReadOnlyPaths = [ builtins.storeDir ];
74 InaccessiblePaths = [ "-+${rootDirectory}" ];
75 RuntimeDirectory = baseNameOf rootDirectory;
76 RuntimeDirectoryMode = "700";
77 AmbientCapabilities = capabilities;
78 CapabilityBoundingSet = capabilities;
79 UMask = "0077";
80 LockPersonality = true;
81 MemoryDenyWriteExecute = true;
82 NoNewPrivileges = true;
83 PrivateDevices = true;
84 PrivateTmp = true;
85 PrivateUsers = !needsPrivileges;
86 ProtectClock = true;
87 ProtectControlGroups = true;
88 ProtectHome = true;
89 ProtectHostname = true;
90 ProtectKernelLogs = true;
91 ProtectKernelModules = true;
92 ProtectKernelTunables = true;
93 ProtectSystem = "strict";
94 ProtectProc = "noaccess";
95 ProcSubset = "pid";
96 RemoveIPC = true;
97 RestrictAddressFamilies = [
98 "AF_INET"
99 "AF_INET6"
100 ];
101 RestrictNamespaces = true;
102 RestrictRealtime = true;
103 RestrictSUIDSGID = true;
104 SystemCallArchitectures = "native";
105 SystemCallFilter = [
106 "@system-service"
107 "~@resources"
108 "~@privileged"
109 ];
110 };
111 };
112
113 networking.firewall.allowedTCPPorts = with cfg; lib.optionals openFirewall [ port ];
114 };
115
116 meta.maintainers = with lib.maintainers; [ azahi ];
117}