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