python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / networking / sslh.nix
blobdaf2f2f3668ee3cb32b167f316d2d5b4eb871b4f
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.sslh;
7   user = "sslh";
8   configFile = pkgs.writeText "sslh.conf" ''
9     verbose: ${boolToString cfg.verbose};
10     foreground: true;
11     inetd: false;
12     numeric: false;
13     transparent: ${boolToString cfg.transparent};
14     timeout: "${toString cfg.timeout}";
16     listen:
17     (
18       ${
19         concatMapStringsSep ",\n"
20         (addr: ''{ host: "${addr}"; port: "${toString cfg.port}"; }'')
21         cfg.listenAddresses
22       }
23     );
25     ${cfg.appendConfig}
26   '';
27   defaultAppendConfig = ''
28     protocols:
29     (
30       { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; probe: "builtin"; },
31       { name: "openvpn"; host: "localhost"; port: "1194"; probe: "builtin"; },
32       { name: "xmpp"; host: "localhost"; port: "5222"; probe: "builtin"; },
33       { name: "http"; host: "localhost"; port: "80"; probe: "builtin"; },
34       { name: "tls"; host: "localhost"; port: "443"; probe: "builtin"; },
35       { name: "anyprot"; host: "localhost"; port: "443"; probe: "builtin"; }
36     );
37   '';
40   imports = [
41     (mkRenamedOptionModule [ "services" "sslh" "listenAddress" ] [ "services" "sslh" "listenAddresses" ])
42   ];
44   options = {
45     services.sslh = {
46       enable = mkEnableOption (lib.mdDoc "sslh");
48       verbose = mkOption {
49         type = types.bool;
50         default = false;
51         description = lib.mdDoc "Verbose logs.";
52       };
54       timeout = mkOption {
55         type = types.int;
56         default = 2;
57         description = lib.mdDoc "Timeout in seconds.";
58       };
60       transparent = mkOption {
61         type = types.bool;
62         default = false;
63         description = lib.mdDoc "Will the services behind sslh (Apache, sshd and so on) see the external IP and ports as if the external world connected directly to them";
64       };
66       listenAddresses = mkOption {
67         type = types.coercedTo types.str singleton (types.listOf types.str);
68         default = [ "0.0.0.0" "[::]" ];
69         description = lib.mdDoc "Listening addresses or hostnames.";
70       };
72       port = mkOption {
73         type = types.port;
74         default = 443;
75         description = lib.mdDoc "Listening port.";
76       };
78       appendConfig = mkOption {
79         type = types.str;
80         default = defaultAppendConfig;
81         description = lib.mdDoc "Verbatim configuration file.";
82       };
83     };
84   };
86   config = mkMerge [
87     (mkIf cfg.enable {
88       systemd.services.sslh = {
89         description = "Applicative Protocol Multiplexer (e.g. share SSH and HTTPS on the same port)";
90         after = [ "network.target" ];
91         wantedBy = [ "multi-user.target" ];
93         serviceConfig = {
94           DynamicUser          = true;
95           User                 = "sslh";
96           PermissionsStartOnly = true;
97           Restart              = "always";
98           RestartSec           = "1s";
99           ExecStart            = "${pkgs.sslh}/bin/sslh -F${configFile}";
100           KillMode             = "process";
101           AmbientCapabilities  = "CAP_NET_BIND_SERVICE CAP_NET_ADMIN CAP_SETGID CAP_SETUID";
102           PrivateTmp           = true;
103           PrivateDevices       = true;
104           ProtectSystem        = "full";
105           ProtectHome          = true;
106         };
107       };
108     })
110     # code from https://github.com/yrutschle/sslh#transparent-proxy-support
111     # the only difference is using iptables mark 0x2 instead of 0x1 to avoid conflicts with nixos/nat module
112     (mkIf (cfg.enable && cfg.transparent) {
113       # Set route_localnet = 1 on all interfaces so that ssl can use "localhost" as destination
114       boot.kernel.sysctl."net.ipv4.conf.default.route_localnet" = 1;
115       boot.kernel.sysctl."net.ipv4.conf.all.route_localnet"     = 1;
117       systemd.services.sslh = let
118         iptablesCommands = [
119           # DROP martian packets as they would have been if route_localnet was zero
120           # Note: packets not leaving the server aren't affected by this, thus sslh will still work
121           { table = "raw";    command = "PREROUTING  ! -i lo -d 127.0.0.0/8 -j DROP"; }
122           { table = "mangle"; command = "POSTROUTING ! -o lo -s 127.0.0.0/8 -j DROP"; }
123           # Mark all connections made by ssl for special treatment (here sslh is run as user ${user})
124           { table = "nat";    command = "OUTPUT -m owner --uid-owner ${user} -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x02/0x0f"; }
125           # Outgoing packets that should go to sslh instead have to be rerouted, so mark them accordingly (copying over the connection mark)
126           { table = "mangle"; command = "OUTPUT ! -o lo -p tcp -m connmark --mark 0x02/0x0f -j CONNMARK --restore-mark --mask 0x0f"; }
127         ];
128         ip6tablesCommands = [
129           { table = "raw";    command = "PREROUTING  ! -i lo -d ::1/128     -j DROP"; }
130           { table = "mangle"; command = "POSTROUTING ! -o lo -s ::1/128     -j DROP"; }
131           { table = "nat";    command = "OUTPUT -m owner --uid-owner ${user} -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x02/0x0f"; }
132           { table = "mangle"; command = "OUTPUT ! -o lo -p tcp -m connmark --mark 0x02/0x0f -j CONNMARK --restore-mark --mask 0x0f"; }
133         ];
134       in {
135         path = [ pkgs.iptables pkgs.iproute2 pkgs.procps ];
137         preStart = ''
138           # Cleanup old iptables entries which might be still there
139           ${concatMapStringsSep "\n" ({table, command}: "while iptables -w -t ${table} -D ${command} 2>/dev/null; do echo; done") iptablesCommands}
140           ${concatMapStringsSep "\n" ({table, command}:       "iptables -w -t ${table} -A ${command}"                           ) iptablesCommands}
142           # Configure routing for those marked packets
143           ip rule  add fwmark 0x2 lookup 100
144           ip route add local 0.0.0.0/0 dev lo table 100
146         '' + optionalString config.networking.enableIPv6 ''
147           ${concatMapStringsSep "\n" ({table, command}: "while ip6tables -w -t ${table} -D ${command} 2>/dev/null; do echo; done") ip6tablesCommands}
148           ${concatMapStringsSep "\n" ({table, command}:       "ip6tables -w -t ${table} -A ${command}"                           ) ip6tablesCommands}
150           ip -6 rule  add fwmark 0x2 lookup 100
151           ip -6 route add local ::/0 dev lo table 100
152         '';
154         postStop = ''
155           ${concatMapStringsSep "\n" ({table, command}: "iptables -w -t ${table} -D ${command}") iptablesCommands}
157           ip rule  del fwmark 0x2 lookup 100
158           ip route del local 0.0.0.0/0 dev lo table 100
159         '' + optionalString config.networking.enableIPv6 ''
160           ${concatMapStringsSep "\n" ({table, command}: "ip6tables -w -t ${table} -D ${command}") ip6tablesCommands}
162           ip -6 rule  del fwmark 0x2 lookup 100
163           ip -6 route del local ::/0 dev lo table 100
164         '';
165       };
166     })
167   ];