2019-10-10 12:56:05 +01:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
|
|
pkg = pkgs._3proxy;
|
|
|
|
cfg = config.services._3proxy;
|
|
|
|
optionalList = list: if list == [ ] then "*" else concatMapStringsSep "," toString list;
|
|
|
|
in {
|
|
|
|
options.services._3proxy = {
|
|
|
|
enable = mkEnableOption "3proxy";
|
|
|
|
confFile = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
example = "/var/lib/3proxy/3proxy.conf";
|
|
|
|
description = ''
|
|
|
|
Ignore all other 3proxy options and load configuration from this file.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
usersFile = mkOption {
|
|
|
|
type = types.nullOr types.path;
|
|
|
|
default = null;
|
|
|
|
example = "/var/lib/3proxy/3proxy.passwd";
|
|
|
|
description = ''
|
|
|
|
Load users and passwords from this file.
|
|
|
|
|
|
|
|
Example users file with plain-text passwords:
|
|
|
|
|
2019-12-19 22:17:49 +00:00
|
|
|
<literal>
|
2019-10-10 12:56:05 +01:00
|
|
|
test1:CL:password1
|
|
|
|
test2:CL:password2
|
2019-12-19 22:17:49 +00:00
|
|
|
</literal>
|
2019-10-10 12:56:05 +01:00
|
|
|
|
|
|
|
Example users file with md5-crypted passwords:
|
|
|
|
|
2019-12-19 22:17:49 +00:00
|
|
|
<literal>
|
2019-11-27 09:01:48 +00:00
|
|
|
test1:CR:$1$tFkisVd2$1GA8JXkRmTXdLDytM/i3a1
|
|
|
|
test2:CR:$1$rkpibm5J$Aq1.9VtYAn0JrqZ8M.1ME.
|
2019-12-19 22:17:49 +00:00
|
|
|
</literal>
|
2019-10-10 12:56:05 +01:00
|
|
|
|
|
|
|
You can generate md5-crypted passwords via https://unix4lyfe.org/crypt/
|
2019-11-27 09:01:48 +00:00
|
|
|
Note that htpasswd tool generates incompatible md5-crypted passwords.
|
2019-10-10 12:56:05 +01:00
|
|
|
Consult <link xlink:href="https://github.com/z3APA3A/3proxy/wiki/How-To-(incomplete)#USERS">documentation</link> for more information.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
services = mkOption {
|
|
|
|
type = types.listOf (types.submodule {
|
|
|
|
options = {
|
|
|
|
type = mkOption {
|
|
|
|
type = types.enum [
|
|
|
|
"proxy"
|
|
|
|
"socks"
|
|
|
|
"pop3p"
|
|
|
|
"ftppr"
|
|
|
|
"admin"
|
|
|
|
"dnspr"
|
|
|
|
"tcppm"
|
|
|
|
"udppm"
|
|
|
|
];
|
|
|
|
example = "proxy";
|
|
|
|
description = ''
|
|
|
|
Service type. The following values are valid:
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"proxy"</literal>: HTTP/HTTPS proxy (default port 3128).
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"socks"</literal>: SOCKS 4/4.5/5 proxy (default port 1080).
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"pop3p"</literal>: POP3 proxy (default port 110).
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"ftppr"</literal>: FTP proxy (default port 21).
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"admin"</literal>: Web interface (default port 80).
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"dnspr"</literal>: Caching DNS proxy (default port 53).
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"tcppm"</literal>: TCP portmapper.
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"udppm"</literal>: UDP portmapper.
|
|
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
bindAddress = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "[::]";
|
|
|
|
example = "127.0.0.1";
|
|
|
|
description = ''
|
|
|
|
Address used for service.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
bindPort = mkOption {
|
|
|
|
type = types.nullOr types.int;
|
|
|
|
default = null;
|
|
|
|
example = 3128;
|
|
|
|
description = ''
|
|
|
|
Override default port used for service.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
maxConnections = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 100;
|
|
|
|
example = 1000;
|
|
|
|
description = ''
|
|
|
|
Maximum number of simulationeous connections to this service.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
auth = mkOption {
|
|
|
|
type = types.listOf (types.enum [ "none" "iponly" "strong" ]);
|
|
|
|
example = [ "iponly" "strong" ];
|
|
|
|
description = ''
|
|
|
|
Authentication type. The following values are valid:
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"none"</literal>: disables both authentication and authorization. You can not use ACLs.
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"iponly"</literal>: specifies no authentication. ACLs authorization is used.
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
2020-06-23 14:59:14 +01:00
|
|
|
<literal>"strong"</literal>: authentication by username/password. If user is not registered their access is denied regardless of ACLs.
|
2019-10-10 12:56:05 +01:00
|
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
Double authentication is possible, e.g.
|
2019-12-19 22:17:49 +00:00
|
|
|
|
|
|
|
<literal>
|
2019-10-10 12:56:05 +01:00
|
|
|
{
|
|
|
|
auth = [ "iponly" "strong" ];
|
|
|
|
acl = [
|
|
|
|
{
|
|
|
|
rule = "allow";
|
|
|
|
targets = [ "192.168.0.0/16" ];
|
|
|
|
}
|
|
|
|
{
|
|
|
|
rule = "allow"
|
|
|
|
users = [ "user1" "user2" ];
|
|
|
|
}
|
|
|
|
];
|
|
|
|
}
|
2019-12-19 22:17:49 +00:00
|
|
|
</literal>
|
2019-10-10 12:56:05 +01:00
|
|
|
In this example strong username authentication is not required to access 192.168.0.0/16.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
acl = mkOption {
|
|
|
|
type = types.listOf (types.submodule {
|
|
|
|
options = {
|
|
|
|
rule = mkOption {
|
|
|
|
type = types.enum [ "allow" "deny" ];
|
|
|
|
example = "allow";
|
|
|
|
description = ''
|
|
|
|
ACL rule. The following values are valid:
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"allow"</literal>: connections allowed.
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
<literal>"deny"</literal>: connections not allowed.
|
|
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
users = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [ ];
|
|
|
|
example = [ "user1" "user2" "user3" ];
|
|
|
|
description = ''
|
|
|
|
List of users, use empty list for any.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
sources = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [ ];
|
|
|
|
example = [ "127.0.0.1" "192.168.1.0/24" ];
|
|
|
|
description = ''
|
|
|
|
List of source IP range, use empty list for any.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
targets = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [ ];
|
|
|
|
example = [ "127.0.0.1" "192.168.1.0/24" ];
|
|
|
|
description = ''
|
|
|
|
List of target IP ranges, use empty list for any.
|
|
|
|
May also contain host names instead of addresses.
|
|
|
|
It's possible to use wildmask in the begginning and in the the end of hostname, e.g. *badsite.com or *badcontent*.
|
|
|
|
Hostname is only checked if hostname presents in request.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
targetPorts = mkOption {
|
|
|
|
type = types.listOf types.int;
|
|
|
|
default = [ ];
|
|
|
|
example = [ 80 443 ];
|
|
|
|
description = ''
|
|
|
|
List of target ports, use empty list for any.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
default = [ ];
|
2021-10-03 17:06:03 +01:00
|
|
|
example = literalExpression ''
|
2019-10-10 12:56:05 +01:00
|
|
|
[
|
|
|
|
{
|
|
|
|
rule = "allow";
|
|
|
|
users = [ "user1" ];
|
|
|
|
}
|
|
|
|
{
|
|
|
|
rule = "allow";
|
|
|
|
sources = [ "192.168.1.0/24" ];
|
|
|
|
}
|
|
|
|
{
|
|
|
|
rule = "deny";
|
|
|
|
}
|
|
|
|
]
|
|
|
|
'';
|
|
|
|
description = ''
|
|
|
|
Use this option to limit user access to resources.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
extraArguments = mkOption {
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
default = null;
|
|
|
|
example = "-46";
|
|
|
|
description = ''
|
|
|
|
Extra arguments for service.
|
|
|
|
Consult "Options" section in <link xlink:href="https://github.com/z3APA3A/3proxy/wiki/3proxy.cfg">documentation</link> for available arguments.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
|
|
type = types.nullOr types.lines;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
Extra configuration for service. Use this to configure things like bandwidth limiter or ACL-based redirection.
|
|
|
|
Consult <link xlink:href="https://github.com/z3APA3A/3proxy/wiki/3proxy.cfg">documentation</link> for available options.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
default = [ ];
|
2021-10-03 17:06:03 +01:00
|
|
|
example = literalExpression ''
|
2019-10-10 12:56:05 +01:00
|
|
|
[
|
|
|
|
{
|
|
|
|
type = "proxy";
|
|
|
|
bindAddress = "192.168.1.24";
|
|
|
|
bindPort = 3128;
|
|
|
|
auth = [ "none" ];
|
|
|
|
}
|
|
|
|
{
|
|
|
|
type = "proxy";
|
|
|
|
bindAddress = "10.10.1.20";
|
|
|
|
bindPort = 3128;
|
|
|
|
auth = [ "iponly" ];
|
|
|
|
}
|
|
|
|
{
|
|
|
|
type = "socks";
|
|
|
|
bindAddress = "172.17.0.1";
|
|
|
|
bindPort = 1080;
|
|
|
|
auth = [ "strong" ];
|
|
|
|
}
|
|
|
|
]
|
|
|
|
'';
|
|
|
|
description = ''
|
|
|
|
Use this option to define 3proxy services.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
denyPrivate = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = ''
|
|
|
|
Whether to deny access to private IP ranges including loopback.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
privateRanges = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [
|
|
|
|
"0.0.0.0/8"
|
|
|
|
"127.0.0.0/8"
|
|
|
|
"10.0.0.0/8"
|
|
|
|
"100.64.0.0/10"
|
|
|
|
"172.16.0.0/12"
|
|
|
|
"192.168.0.0/16"
|
|
|
|
"::"
|
|
|
|
"::1"
|
|
|
|
"fc00::/7"
|
|
|
|
];
|
|
|
|
description = ''
|
|
|
|
What IP ranges to deny access when denyPrivate is set tu true.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
resolution = mkOption {
|
|
|
|
type = types.submodule {
|
|
|
|
options = {
|
|
|
|
nserver = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [ ];
|
|
|
|
example = [ "127.0.0.53" "192.168.1.3:5353/tcp" ];
|
|
|
|
description = ''
|
|
|
|
List of nameservers to use.
|
|
|
|
|
|
|
|
Up to 5 nservers may be specified. If no nserver is configured,
|
|
|
|
default system name resolution functions are used.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
nscache = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 65535;
|
|
|
|
description = "Set name cache size for IPv4.";
|
|
|
|
};
|
|
|
|
nscache6 = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 65535;
|
|
|
|
description = "Set name cache size for IPv6.";
|
|
|
|
};
|
|
|
|
nsrecord = mkOption {
|
|
|
|
type = types.attrsOf types.str;
|
|
|
|
default = { };
|
2021-10-03 17:06:03 +01:00
|
|
|
example = literalExpression ''
|
2020-04-02 06:39:04 +01:00
|
|
|
{
|
|
|
|
"files.local" = "192.168.1.12";
|
|
|
|
"site.local" = "192.168.1.43";
|
|
|
|
}
|
|
|
|
'';
|
2019-10-10 12:56:05 +01:00
|
|
|
description = "Adds static nsrecords.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
default = { };
|
|
|
|
description = ''
|
|
|
|
Use this option to configure name resolution and DNS caching.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
|
|
type = types.nullOr types.lines;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
Extra configuration, appended to the 3proxy configuration file.
|
|
|
|
Consult <link xlink:href="https://github.com/z3APA3A/3proxy/wiki/3proxy.cfg">documentation</link> for available options.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
services._3proxy.confFile = mkDefault (pkgs.writeText "3proxy.conf" ''
|
|
|
|
# log to stdout
|
|
|
|
log
|
|
|
|
|
|
|
|
${concatMapStringsSep "\n" (x: "nserver " + x) cfg.resolution.nserver}
|
|
|
|
|
|
|
|
nscache ${toString cfg.resolution.nscache}
|
|
|
|
nscache6 ${toString cfg.resolution.nscache6}
|
|
|
|
|
|
|
|
${concatMapStringsSep "\n" (x: "nsrecord " + x)
|
|
|
|
(mapAttrsToList (name: value: "${name} ${value}")
|
|
|
|
cfg.resolution.nsrecord)}
|
|
|
|
|
|
|
|
${optionalString (cfg.usersFile != null)
|
|
|
|
''users $"${cfg.usersFile}"''
|
|
|
|
}
|
|
|
|
|
|
|
|
${concatMapStringsSep "\n" (service: ''
|
|
|
|
auth ${concatStringsSep " " service.auth}
|
|
|
|
|
|
|
|
${optionalString (cfg.denyPrivate)
|
|
|
|
"deny * * ${optionalList cfg.privateRanges}"}
|
|
|
|
|
|
|
|
${concatMapStringsSep "\n" (acl:
|
|
|
|
"${acl.rule} ${
|
|
|
|
concatMapStringsSep " " optionalList [
|
|
|
|
acl.users
|
|
|
|
acl.sources
|
|
|
|
acl.targets
|
|
|
|
acl.targetPorts
|
|
|
|
]
|
|
|
|
}") service.acl}
|
|
|
|
|
|
|
|
maxconn ${toString service.maxConnections}
|
|
|
|
|
|
|
|
${optionalString (service.extraConfig != null) service.extraConfig}
|
|
|
|
|
|
|
|
${service.type} -i${toString service.bindAddress} ${
|
|
|
|
optionalString (service.bindPort != null)
|
|
|
|
"-p${toString service.bindPort}"
|
|
|
|
} ${
|
|
|
|
optionalString (service.extraArguments != null) service.extraArguments
|
|
|
|
}
|
|
|
|
|
|
|
|
flush
|
|
|
|
'') cfg.services}
|
|
|
|
${optionalString (cfg.extraConfig != null) cfg.extraConfig}
|
|
|
|
'');
|
|
|
|
systemd.services."3proxy" = {
|
|
|
|
description = "Tiny free proxy server";
|
|
|
|
documentation = [ "https://github.com/z3APA3A/3proxy/wiki" ];
|
|
|
|
after = [ "network.target" ];
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
serviceConfig = {
|
|
|
|
DynamicUser = true;
|
|
|
|
StateDirectory = "3proxy";
|
|
|
|
ExecStart = "${pkg}/bin/3proxy ${cfg.confFile}";
|
|
|
|
Restart = "on-failure";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
meta.maintainers = with maintainers; [ misuzu ];
|
|
|
|
}
|