1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8
9 cfg = config.programs.proxychains;
10
11 configFile = ''
12 ${cfg.chain.type}_chain
13 ${lib.optionalString (
14 cfg.chain.type == "random"
15 ) "chain_len = ${builtins.toString cfg.chain.length}"}
16 ${lib.optionalString cfg.proxyDNS "proxy_dns"}
17 ${lib.optionalString cfg.quietMode "quiet_mode"}
18 remote_dns_subnet ${builtins.toString cfg.remoteDNSSubnet}
19 tcp_read_time_out ${builtins.toString cfg.tcpReadTimeOut}
20 tcp_connect_time_out ${builtins.toString cfg.tcpConnectTimeOut}
21 localnet ${cfg.localnet}
22 [ProxyList]
23 ${builtins.concatStringsSep "\n" (
24 lib.mapAttrsToList (k: v: "${v.type} ${v.host} ${builtins.toString v.port}") (
25 lib.filterAttrs (k: v: v.enable) cfg.proxies
26 )
27 )}
28 '';
29
30 proxyOptions = {
31 options = {
32 enable = lib.mkEnableOption "this proxy";
33
34 type = lib.mkOption {
35 type = lib.types.enum [
36 "http"
37 "socks4"
38 "socks5"
39 ];
40 description = "Proxy type.";
41 };
42
43 host = lib.mkOption {
44 type = lib.types.str;
45 description = "Proxy host or IP address.";
46 };
47
48 port = lib.mkOption {
49 type = lib.types.port;
50 description = "Proxy port";
51 };
52 };
53 };
54
55in
56{
57
58 ###### interface
59
60 options = {
61
62 programs.proxychains = {
63
64 enable = lib.mkEnableOption "proxychains configuration";
65
66 package = lib.mkPackageOption pkgs "proxychains" {
67 example = "proxychains-ng";
68 };
69
70 chain = {
71 type = lib.mkOption {
72 type = lib.types.enum [
73 "dynamic"
74 "strict"
75 "random"
76 ];
77 default = "strict";
78 description = ''
79 `dynamic` - Each connection will be done via chained proxies
80 all proxies chained in the order as they appear in the list
81 at least one proxy must be online to play in chain
82 (dead proxies are skipped)
83 otherwise `EINTR` is returned to the app.
84
85 `strict` - Each connection will be done via chained proxies
86 all proxies chained in the order as they appear in the list
87 all proxies must be online to play in chain
88 otherwise `EINTR` is returned to the app.
89
90 `random` - Each connection will be done via random proxy
91 (or proxy chain, see {option}`programs.proxychains.chain.length`) from the list.
92 '';
93 };
94 length = lib.mkOption {
95 type = lib.types.nullOr lib.types.int;
96 default = null;
97 description = ''
98 Chain length for random chain.
99 '';
100 };
101 };
102
103 proxyDNS = lib.mkOption {
104 type = lib.types.bool;
105 default = true;
106 description = "Proxy DNS requests - no leak for DNS data.";
107 };
108
109 quietMode = lib.mkEnableOption "Quiet mode (no output from the library)";
110
111 remoteDNSSubnet = lib.mkOption {
112 type = lib.types.enum [
113 10
114 127
115 224
116 ];
117 default = 224;
118 description = ''
119 Set the class A subnet number to use for the internal remote DNS mapping, uses the reserved 224.x.x.x range by default.
120 '';
121 };
122
123 tcpReadTimeOut = lib.mkOption {
124 type = lib.types.int;
125 default = 15000;
126 description = "Connection read time-out in milliseconds.";
127 };
128
129 tcpConnectTimeOut = lib.mkOption {
130 type = lib.types.int;
131 default = 8000;
132 description = "Connection time-out in milliseconds.";
133 };
134
135 localnet = lib.mkOption {
136 type = lib.types.str;
137 default = "127.0.0.0/255.0.0.0";
138 description = "By default enable localnet for loopback address ranges.";
139 };
140
141 proxies = lib.mkOption {
142 type = lib.types.attrsOf (lib.types.submodule proxyOptions);
143 description = ''
144 Proxies to be used by proxychains.
145 '';
146
147 example = lib.literalExpression ''
148 { myproxy =
149 { type = "socks4";
150 host = "127.0.0.1";
151 port = 1337;
152 };
153 }
154 '';
155 };
156
157 };
158
159 };
160
161 ###### implementation
162
163 meta.maintainers = with lib.maintainers; [ sorki ];
164
165 config = lib.mkIf cfg.enable {
166
167 assertions = lib.singleton {
168 assertion = cfg.chain.type != "random" && cfg.chain.length == null;
169 message = ''
170 Option `programs.proxychains.chain.length`
171 only makes sense with `programs.proxychains.chain.type` = "random".
172 '';
173 };
174
175 programs.proxychains.proxies = lib.mkIf config.services.tor.client.enable {
176 torproxy = lib.mkDefault {
177 enable = true;
178 type = "socks4";
179 host = "127.0.0.1";
180 port = 9050;
181 };
182 };
183
184 environment.etc."proxychains.conf".text = configFile;
185 environment.systemPackages = [ cfg.package ];
186 };
187
188}