at 21.11-pre 14 kB view raw
1{ config, lib, pkgs, ... }: 2with lib; 3let 4 pkg = pkgs._3proxy; 5 cfg = config.services._3proxy; 6 optionalList = list: if list == [ ] then "*" else concatMapStringsSep "," toString list; 7in { 8 options.services._3proxy = { 9 enable = mkEnableOption "3proxy"; 10 confFile = mkOption { 11 type = types.path; 12 example = "/var/lib/3proxy/3proxy.conf"; 13 description = '' 14 Ignore all other 3proxy options and load configuration from this file. 15 ''; 16 }; 17 usersFile = mkOption { 18 type = types.nullOr types.path; 19 default = null; 20 example = "/var/lib/3proxy/3proxy.passwd"; 21 description = '' 22 Load users and passwords from this file. 23 24 Example users file with plain-text passwords: 25 26 <literal> 27 test1:CL:password1 28 test2:CL:password2 29 </literal> 30 31 Example users file with md5-crypted passwords: 32 33 <literal> 34 test1:CR:$1$tFkisVd2$1GA8JXkRmTXdLDytM/i3a1 35 test2:CR:$1$rkpibm5J$Aq1.9VtYAn0JrqZ8M.1ME. 36 </literal> 37 38 You can generate md5-crypted passwords via https://unix4lyfe.org/crypt/ 39 Note that htpasswd tool generates incompatible md5-crypted passwords. 40 Consult <link xlink:href="https://github.com/z3APA3A/3proxy/wiki/How-To-(incomplete)#USERS">documentation</link> for more information. 41 ''; 42 }; 43 services = mkOption { 44 type = types.listOf (types.submodule { 45 options = { 46 type = mkOption { 47 type = types.enum [ 48 "proxy" 49 "socks" 50 "pop3p" 51 "ftppr" 52 "admin" 53 "dnspr" 54 "tcppm" 55 "udppm" 56 ]; 57 example = "proxy"; 58 description = '' 59 Service type. The following values are valid: 60 61 <itemizedlist> 62 <listitem><para> 63 <literal>"proxy"</literal>: HTTP/HTTPS proxy (default port 3128). 64 </para></listitem> 65 <listitem><para> 66 <literal>"socks"</literal>: SOCKS 4/4.5/5 proxy (default port 1080). 67 </para></listitem> 68 <listitem><para> 69 <literal>"pop3p"</literal>: POP3 proxy (default port 110). 70 </para></listitem> 71 <listitem><para> 72 <literal>"ftppr"</literal>: FTP proxy (default port 21). 73 </para></listitem> 74 <listitem><para> 75 <literal>"admin"</literal>: Web interface (default port 80). 76 </para></listitem> 77 <listitem><para> 78 <literal>"dnspr"</literal>: Caching DNS proxy (default port 53). 79 </para></listitem> 80 <listitem><para> 81 <literal>"tcppm"</literal>: TCP portmapper. 82 </para></listitem> 83 <listitem><para> 84 <literal>"udppm"</literal>: UDP portmapper. 85 </para></listitem> 86 </itemizedlist> 87 ''; 88 }; 89 bindAddress = mkOption { 90 type = types.str; 91 default = "[::]"; 92 example = "127.0.0.1"; 93 description = '' 94 Address used for service. 95 ''; 96 }; 97 bindPort = mkOption { 98 type = types.nullOr types.int; 99 default = null; 100 example = 3128; 101 description = '' 102 Override default port used for service. 103 ''; 104 }; 105 maxConnections = mkOption { 106 type = types.int; 107 default = 100; 108 example = 1000; 109 description = '' 110 Maximum number of simulationeous connections to this service. 111 ''; 112 }; 113 auth = mkOption { 114 type = types.listOf (types.enum [ "none" "iponly" "strong" ]); 115 example = [ "iponly" "strong" ]; 116 description = '' 117 Authentication type. The following values are valid: 118 119 <itemizedlist> 120 <listitem><para> 121 <literal>"none"</literal>: disables both authentication and authorization. You can not use ACLs. 122 </para></listitem> 123 <listitem><para> 124 <literal>"iponly"</literal>: specifies no authentication. ACLs authorization is used. 125 </para></listitem> 126 <listitem><para> 127 <literal>"strong"</literal>: authentication by username/password. If user is not registered their access is denied regardless of ACLs. 128 </para></listitem> 129 </itemizedlist> 130 131 Double authentication is possible, e.g. 132 133 <literal> 134 { 135 auth = [ "iponly" "strong" ]; 136 acl = [ 137 { 138 rule = "allow"; 139 targets = [ "192.168.0.0/16" ]; 140 } 141 { 142 rule = "allow" 143 users = [ "user1" "user2" ]; 144 } 145 ]; 146 } 147 </literal> 148 In this example strong username authentication is not required to access 192.168.0.0/16. 149 ''; 150 }; 151 acl = mkOption { 152 type = types.listOf (types.submodule { 153 options = { 154 rule = mkOption { 155 type = types.enum [ "allow" "deny" ]; 156 example = "allow"; 157 description = '' 158 ACL rule. The following values are valid: 159 160 <itemizedlist> 161 <listitem><para> 162 <literal>"allow"</literal>: connections allowed. 163 </para></listitem> 164 <listitem><para> 165 <literal>"deny"</literal>: connections not allowed. 166 </para></listitem> 167 </itemizedlist> 168 ''; 169 }; 170 users = mkOption { 171 type = types.listOf types.str; 172 default = [ ]; 173 example = [ "user1" "user2" "user3" ]; 174 description = '' 175 List of users, use empty list for any. 176 ''; 177 }; 178 sources = mkOption { 179 type = types.listOf types.str; 180 default = [ ]; 181 example = [ "127.0.0.1" "192.168.1.0/24" ]; 182 description = '' 183 List of source IP range, use empty list for any. 184 ''; 185 }; 186 targets = mkOption { 187 type = types.listOf types.str; 188 default = [ ]; 189 example = [ "127.0.0.1" "192.168.1.0/24" ]; 190 description = '' 191 List of target IP ranges, use empty list for any. 192 May also contain host names instead of addresses. 193 It's possible to use wildmask in the begginning and in the the end of hostname, e.g. *badsite.com or *badcontent*. 194 Hostname is only checked if hostname presents in request. 195 ''; 196 }; 197 targetPorts = mkOption { 198 type = types.listOf types.int; 199 default = [ ]; 200 example = [ 80 443 ]; 201 description = '' 202 List of target ports, use empty list for any. 203 ''; 204 }; 205 }; 206 }); 207 default = [ ]; 208 example = literalExample '' 209 [ 210 { 211 rule = "allow"; 212 users = [ "user1" ]; 213 } 214 { 215 rule = "allow"; 216 sources = [ "192.168.1.0/24" ]; 217 } 218 { 219 rule = "deny"; 220 } 221 ] 222 ''; 223 description = '' 224 Use this option to limit user access to resources. 225 ''; 226 }; 227 extraArguments = mkOption { 228 type = types.nullOr types.str; 229 default = null; 230 example = "-46"; 231 description = '' 232 Extra arguments for service. 233 Consult "Options" section in <link xlink:href="https://github.com/z3APA3A/3proxy/wiki/3proxy.cfg">documentation</link> for available arguments. 234 ''; 235 }; 236 extraConfig = mkOption { 237 type = types.nullOr types.lines; 238 default = null; 239 description = '' 240 Extra configuration for service. Use this to configure things like bandwidth limiter or ACL-based redirection. 241 Consult <link xlink:href="https://github.com/z3APA3A/3proxy/wiki/3proxy.cfg">documentation</link> for available options. 242 ''; 243 }; 244 }; 245 }); 246 default = [ ]; 247 example = literalExample '' 248 [ 249 { 250 type = "proxy"; 251 bindAddress = "192.168.1.24"; 252 bindPort = 3128; 253 auth = [ "none" ]; 254 } 255 { 256 type = "proxy"; 257 bindAddress = "10.10.1.20"; 258 bindPort = 3128; 259 auth = [ "iponly" ]; 260 } 261 { 262 type = "socks"; 263 bindAddress = "172.17.0.1"; 264 bindPort = 1080; 265 auth = [ "strong" ]; 266 } 267 ] 268 ''; 269 description = '' 270 Use this option to define 3proxy services. 271 ''; 272 }; 273 denyPrivate = mkOption { 274 type = types.bool; 275 default = true; 276 description = '' 277 Whether to deny access to private IP ranges including loopback. 278 ''; 279 }; 280 privateRanges = mkOption { 281 type = types.listOf types.str; 282 default = [ 283 "0.0.0.0/8" 284 "127.0.0.0/8" 285 "10.0.0.0/8" 286 "100.64.0.0/10" 287 "172.16.0.0/12" 288 "192.168.0.0/16" 289 "::" 290 "::1" 291 "fc00::/7" 292 ]; 293 example = [ 294 "0.0.0.0/8" 295 "127.0.0.0/8" 296 "10.0.0.0/8" 297 "100.64.0.0/10" 298 "172.16.0.0/12" 299 "192.168.0.0/16" 300 "::" 301 "::1" 302 "fc00::/7" 303 ]; 304 description = '' 305 What IP ranges to deny access when denyPrivate is set tu true. 306 ''; 307 }; 308 resolution = mkOption { 309 type = types.submodule { 310 options = { 311 nserver = mkOption { 312 type = types.listOf types.str; 313 default = [ ]; 314 example = [ "127.0.0.53" "192.168.1.3:5353/tcp" ]; 315 description = '' 316 List of nameservers to use. 317 318 Up to 5 nservers may be specified. If no nserver is configured, 319 default system name resolution functions are used. 320 ''; 321 }; 322 nscache = mkOption { 323 type = types.int; 324 default = 65535; 325 example = 65535; 326 description = "Set name cache size for IPv4."; 327 }; 328 nscache6 = mkOption { 329 type = types.int; 330 default = 65535; 331 example = 65535; 332 description = "Set name cache size for IPv6."; 333 }; 334 nsrecord = mkOption { 335 type = types.attrsOf types.str; 336 default = { }; 337 example = literalExample '' 338 { 339 "files.local" = "192.168.1.12"; 340 "site.local" = "192.168.1.43"; 341 } 342 ''; 343 description = "Adds static nsrecords."; 344 }; 345 }; 346 }; 347 default = { }; 348 description = '' 349 Use this option to configure name resolution and DNS caching. 350 ''; 351 }; 352 extraConfig = mkOption { 353 type = types.nullOr types.lines; 354 default = null; 355 description = '' 356 Extra configuration, appended to the 3proxy configuration file. 357 Consult <link xlink:href="https://github.com/z3APA3A/3proxy/wiki/3proxy.cfg">documentation</link> for available options. 358 ''; 359 }; 360 }; 361 362 config = mkIf cfg.enable { 363 services._3proxy.confFile = mkDefault (pkgs.writeText "3proxy.conf" '' 364 # log to stdout 365 log 366 367 ${concatMapStringsSep "\n" (x: "nserver " + x) cfg.resolution.nserver} 368 369 nscache ${toString cfg.resolution.nscache} 370 nscache6 ${toString cfg.resolution.nscache6} 371 372 ${concatMapStringsSep "\n" (x: "nsrecord " + x) 373 (mapAttrsToList (name: value: "${name} ${value}") 374 cfg.resolution.nsrecord)} 375 376 ${optionalString (cfg.usersFile != null) 377 ''users $"${cfg.usersFile}"'' 378 } 379 380 ${concatMapStringsSep "\n" (service: '' 381 auth ${concatStringsSep " " service.auth} 382 383 ${optionalString (cfg.denyPrivate) 384 "deny * * ${optionalList cfg.privateRanges}"} 385 386 ${concatMapStringsSep "\n" (acl: 387 "${acl.rule} ${ 388 concatMapStringsSep " " optionalList [ 389 acl.users 390 acl.sources 391 acl.targets 392 acl.targetPorts 393 ] 394 }") service.acl} 395 396 maxconn ${toString service.maxConnections} 397 398 ${optionalString (service.extraConfig != null) service.extraConfig} 399 400 ${service.type} -i${toString service.bindAddress} ${ 401 optionalString (service.bindPort != null) 402 "-p${toString service.bindPort}" 403 } ${ 404 optionalString (service.extraArguments != null) service.extraArguments 405 } 406 407 flush 408 '') cfg.services} 409 ${optionalString (cfg.extraConfig != null) cfg.extraConfig} 410 ''); 411 systemd.services."3proxy" = { 412 description = "Tiny free proxy server"; 413 documentation = [ "https://github.com/z3APA3A/3proxy/wiki" ]; 414 after = [ "network.target" ]; 415 wantedBy = [ "multi-user.target" ]; 416 serviceConfig = { 417 DynamicUser = true; 418 StateDirectory = "3proxy"; 419 ExecStart = "${pkg}/bin/3proxy ${cfg.confFile}"; 420 Restart = "on-failure"; 421 }; 422 }; 423 }; 424 425 meta.maintainers = with maintainers; [ misuzu ]; 426}