@push.rocks/smartproxy 3.28.6 → 3.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.iptablesproxy.d.ts +79 -7
- package/dist_ts/classes.iptablesproxy.js +662 -67
- package/dist_ts/classes.networkproxy.d.ts +46 -1
- package/dist_ts/classes.networkproxy.js +347 -8
- package/dist_ts/classes.portproxy.d.ts +36 -0
- package/dist_ts/classes.portproxy.js +464 -365
- package/package.json +2 -2
- package/readme.md +80 -10
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.iptablesproxy.ts +786 -68
- package/ts/classes.networkproxy.ts +417 -7
- package/ts/classes.portproxy.ts +652 -485
|
@@ -3,22 +3,34 @@ import { promisify } from 'util';
|
|
|
3
3
|
const execAsync = promisify(exec);
|
|
4
4
|
/**
|
|
5
5
|
* IPTablesProxy sets up iptables NAT rules to forward TCP traffic.
|
|
6
|
-
*
|
|
6
|
+
* Enhanced with multi-port support, IPv6, and integration with PortProxy/NetworkProxy.
|
|
7
7
|
*/
|
|
8
8
|
export class IPTablesProxy {
|
|
9
9
|
constructor(settings) {
|
|
10
|
-
this.
|
|
10
|
+
this.rules = [];
|
|
11
|
+
this.customChain = null;
|
|
12
|
+
// Validate inputs to prevent command injection
|
|
13
|
+
this.validateSettings(settings);
|
|
14
|
+
// Set default settings
|
|
11
15
|
this.settings = {
|
|
12
16
|
...settings,
|
|
13
17
|
toHost: settings.toHost || 'localhost',
|
|
18
|
+
protocol: settings.protocol || 'tcp',
|
|
19
|
+
enableLogging: settings.enableLogging !== undefined ? settings.enableLogging : false,
|
|
20
|
+
ipv6Support: settings.ipv6Support !== undefined ? settings.ipv6Support : false,
|
|
21
|
+
checkExistingRules: settings.checkExistingRules !== undefined ? settings.checkExistingRules : true,
|
|
22
|
+
netProxyIntegration: settings.netProxyIntegration || { enabled: false }
|
|
14
23
|
};
|
|
15
|
-
// Generate a unique identifier for the rules added by this instance
|
|
24
|
+
// Generate a unique identifier for the rules added by this instance
|
|
16
25
|
this.ruleTag = `IPTablesProxy:${Date.now()}:${Math.random().toString(36).substr(2, 5)}`;
|
|
17
|
-
|
|
26
|
+
if (this.settings.addJumpRule) {
|
|
27
|
+
this.customChain = `IPTablesProxy_${Math.random().toString(36).substr(2, 5)}`;
|
|
28
|
+
}
|
|
29
|
+
// Register cleanup handlers if deleteOnExit is true
|
|
18
30
|
if (this.settings.deleteOnExit) {
|
|
19
31
|
const cleanup = () => {
|
|
20
32
|
try {
|
|
21
|
-
|
|
33
|
+
this.stopSync();
|
|
22
34
|
}
|
|
23
35
|
catch (err) {
|
|
24
36
|
console.error('Error cleaning iptables rules on exit:', err);
|
|
@@ -36,105 +48,614 @@ export class IPTablesProxy {
|
|
|
36
48
|
}
|
|
37
49
|
}
|
|
38
50
|
/**
|
|
39
|
-
*
|
|
40
|
-
* The rules are tagged with a unique comment so that they can be identified later.
|
|
51
|
+
* Validates settings to prevent command injection and ensure valid values
|
|
41
52
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
53
|
+
validateSettings(settings) {
|
|
54
|
+
// Validate port numbers
|
|
55
|
+
const validatePorts = (port) => {
|
|
56
|
+
if (Array.isArray(port)) {
|
|
57
|
+
port.forEach(p => validatePorts(p));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (typeof port === 'number') {
|
|
61
|
+
if (port < 1 || port > 65535) {
|
|
62
|
+
throw new Error(`Invalid port number: ${port}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (typeof port === 'object') {
|
|
66
|
+
if (port.from < 1 || port.from > 65535 || port.to < 1 || port.to > 65535 || port.from > port.to) {
|
|
67
|
+
throw new Error(`Invalid port range: ${port.from}-${port.to}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
validatePorts(settings.fromPort);
|
|
72
|
+
validatePorts(settings.toPort);
|
|
73
|
+
// Define regex patterns at the method level so they're available throughout
|
|
74
|
+
const ipRegex = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))?$/;
|
|
75
|
+
const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$/;
|
|
76
|
+
// Validate IP addresses
|
|
77
|
+
const validateIPs = (ips) => {
|
|
78
|
+
if (!ips)
|
|
79
|
+
return;
|
|
80
|
+
for (const ip of ips) {
|
|
81
|
+
if (!ipRegex.test(ip) && !ipv6Regex.test(ip)) {
|
|
82
|
+
throw new Error(`Invalid IP address format: ${ip}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
validateIPs(settings.allowedSourceIPs);
|
|
87
|
+
validateIPs(settings.bannedSourceIPs);
|
|
88
|
+
// Validate toHost - only allow hostnames or IPs
|
|
89
|
+
if (settings.toHost) {
|
|
90
|
+
const hostRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
|
|
91
|
+
if (!hostRegex.test(settings.toHost) && !ipRegex.test(settings.toHost) && !ipv6Regex.test(settings.toHost)) {
|
|
92
|
+
throw new Error(`Invalid host format: ${settings.toHost}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Normalizes port specifications into an array of port ranges
|
|
98
|
+
*/
|
|
99
|
+
normalizePortSpec(portSpec) {
|
|
100
|
+
const result = [];
|
|
101
|
+
if (Array.isArray(portSpec)) {
|
|
102
|
+
// If it's an array, process each element
|
|
103
|
+
for (const spec of portSpec) {
|
|
104
|
+
result.push(...this.normalizePortSpec(spec));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (typeof portSpec === 'number') {
|
|
108
|
+
// Single port becomes a range with the same start and end
|
|
109
|
+
result.push({ from: portSpec, to: portSpec });
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Already a range
|
|
113
|
+
result.push(portSpec);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Gets the appropriate iptables command based on settings
|
|
119
|
+
*/
|
|
120
|
+
getIptablesCommand(isIpv6 = false) {
|
|
121
|
+
return isIpv6 ? 'ip6tables' : 'iptables';
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Checks if a rule already exists in iptables
|
|
125
|
+
*/
|
|
126
|
+
async ruleExists(table, command, isIpv6 = false) {
|
|
46
127
|
try {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
128
|
+
const iptablesCmd = this.getIptablesCommand(isIpv6);
|
|
129
|
+
const { stdout } = await execAsync(`${iptablesCmd}-save -t ${table}`);
|
|
130
|
+
// Convert the command to the format found in iptables-save output
|
|
131
|
+
// (This is a simplification - in reality, you'd need more parsing)
|
|
132
|
+
const rulePattern = command.replace(`${iptablesCmd} -t ${table} -A `, '-A ');
|
|
133
|
+
return stdout.split('\n').some(line => line.trim() === rulePattern);
|
|
50
134
|
}
|
|
51
135
|
catch (err) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
136
|
+
this.log('error', `Failed to check if rule exists: ${err}`);
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Sets up a custom chain for better rule management
|
|
142
|
+
*/
|
|
143
|
+
async setupCustomChain(isIpv6 = false) {
|
|
144
|
+
if (!this.customChain)
|
|
145
|
+
return true;
|
|
146
|
+
const iptablesCmd = this.getIptablesCommand(isIpv6);
|
|
147
|
+
const table = 'nat';
|
|
148
|
+
try {
|
|
149
|
+
// Create the chain
|
|
150
|
+
await execAsync(`${iptablesCmd} -t ${table} -N ${this.customChain}`);
|
|
151
|
+
this.log('info', `Created custom chain: ${this.customChain}`);
|
|
152
|
+
// Add jump rule to PREROUTING chain
|
|
153
|
+
const jumpCommand = `${iptablesCmd} -t ${table} -A PREROUTING -j ${this.customChain} -m comment --comment "${this.ruleTag}:JUMP"`;
|
|
154
|
+
await execAsync(jumpCommand);
|
|
155
|
+
this.log('info', `Added jump rule to ${this.customChain}`);
|
|
156
|
+
// Store the jump rule
|
|
157
|
+
this.rules.push({
|
|
158
|
+
table,
|
|
159
|
+
chain: 'PREROUTING',
|
|
160
|
+
command: jumpCommand,
|
|
161
|
+
tag: `${this.ruleTag}:JUMP`,
|
|
162
|
+
added: true
|
|
163
|
+
});
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
this.log('error', `Failed to set up custom chain: ${err}`);
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Add a source IP filter rule
|
|
173
|
+
*/
|
|
174
|
+
async addSourceIPFilter(isIpv6 = false) {
|
|
175
|
+
if (!this.settings.allowedSourceIPs && !this.settings.bannedSourceIPs) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
const iptablesCmd = this.getIptablesCommand(isIpv6);
|
|
179
|
+
const table = 'nat';
|
|
180
|
+
const chain = this.customChain || 'PREROUTING';
|
|
181
|
+
try {
|
|
182
|
+
// Add banned IPs first (explicit deny)
|
|
183
|
+
if (this.settings.bannedSourceIPs && this.settings.bannedSourceIPs.length > 0) {
|
|
184
|
+
for (const ip of this.settings.bannedSourceIPs) {
|
|
185
|
+
const command = `${iptablesCmd} -t ${table} -A ${chain} -s ${ip} -j DROP -m comment --comment "${this.ruleTag}:BANNED"`;
|
|
186
|
+
// Check if rule already exists
|
|
187
|
+
if (this.settings.checkExistingRules && await this.ruleExists(table, command, isIpv6)) {
|
|
188
|
+
this.log('info', `Rule already exists, skipping: ${command}`);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
await execAsync(command);
|
|
192
|
+
this.log('info', `Added banned IP rule: ${command}`);
|
|
193
|
+
this.rules.push({
|
|
194
|
+
table,
|
|
195
|
+
chain,
|
|
196
|
+
command,
|
|
197
|
+
tag: `${this.ruleTag}:BANNED`,
|
|
198
|
+
added: true
|
|
199
|
+
});
|
|
200
|
+
}
|
|
63
201
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
this.
|
|
202
|
+
// Add allowed IPs (explicit allow)
|
|
203
|
+
if (this.settings.allowedSourceIPs && this.settings.allowedSourceIPs.length > 0) {
|
|
204
|
+
// First add a default deny for all
|
|
205
|
+
const denyAllCommand = `${iptablesCmd} -t ${table} -A ${chain} -p ${this.settings.protocol} -j DROP -m comment --comment "${this.ruleTag}:DENY_ALL"`;
|
|
206
|
+
// Add allow rules for specific IPs
|
|
207
|
+
for (const ip of this.settings.allowedSourceIPs) {
|
|
208
|
+
const command = `${iptablesCmd} -t ${table} -A ${chain} -s ${ip} -p ${this.settings.protocol} -j ACCEPT -m comment --comment "${this.ruleTag}:ALLOWED"`;
|
|
209
|
+
// Check if rule already exists
|
|
210
|
+
if (this.settings.checkExistingRules && await this.ruleExists(table, command, isIpv6)) {
|
|
211
|
+
this.log('info', `Rule already exists, skipping: ${command}`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
await execAsync(command);
|
|
215
|
+
this.log('info', `Added allowed IP rule: ${command}`);
|
|
216
|
+
this.rules.push({
|
|
217
|
+
table,
|
|
218
|
+
chain,
|
|
219
|
+
command,
|
|
220
|
+
tag: `${this.ruleTag}:ALLOWED`,
|
|
221
|
+
added: true
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
// Now add the default deny after all allows
|
|
225
|
+
if (this.settings.checkExistingRules && await this.ruleExists(table, denyAllCommand, isIpv6)) {
|
|
226
|
+
this.log('info', `Rule already exists, skipping: ${denyAllCommand}`);
|
|
73
227
|
}
|
|
74
|
-
|
|
75
|
-
|
|
228
|
+
else {
|
|
229
|
+
await execAsync(denyAllCommand);
|
|
230
|
+
this.log('info', `Added default deny rule: ${denyAllCommand}`);
|
|
231
|
+
this.rules.push({
|
|
232
|
+
table,
|
|
233
|
+
chain,
|
|
234
|
+
command: denyAllCommand,
|
|
235
|
+
tag: `${this.ruleTag}:DENY_ALL`,
|
|
236
|
+
added: true
|
|
237
|
+
});
|
|
76
238
|
}
|
|
77
|
-
throw err;
|
|
78
239
|
}
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
this.log('error', `Failed to add source IP filter rules: ${err}`);
|
|
244
|
+
return false;
|
|
79
245
|
}
|
|
80
246
|
}
|
|
81
247
|
/**
|
|
82
|
-
*
|
|
248
|
+
* Adds a port forwarding rule
|
|
83
249
|
*/
|
|
84
|
-
async
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
250
|
+
async addPortForwardingRule(fromPortRange, toPortRange, isIpv6 = false) {
|
|
251
|
+
const iptablesCmd = this.getIptablesCommand(isIpv6);
|
|
252
|
+
const table = 'nat';
|
|
253
|
+
const chain = this.customChain || 'PREROUTING';
|
|
254
|
+
try {
|
|
255
|
+
// Handle single port case
|
|
256
|
+
if (fromPortRange.from === fromPortRange.to && toPortRange.from === toPortRange.to) {
|
|
257
|
+
// Single port forward
|
|
258
|
+
const command = `${iptablesCmd} -t ${table} -A ${chain} -p ${this.settings.protocol} --dport ${fromPortRange.from} ` +
|
|
259
|
+
`-j DNAT --to-destination ${this.settings.toHost}:${toPortRange.from} ` +
|
|
260
|
+
`-m comment --comment "${this.ruleTag}:DNAT"`;
|
|
261
|
+
// Check if rule already exists
|
|
262
|
+
if (this.settings.checkExistingRules && await this.ruleExists(table, command, isIpv6)) {
|
|
263
|
+
this.log('info', `Rule already exists, skipping: ${command}`);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
await execAsync(command);
|
|
267
|
+
this.log('info', `Added port forwarding rule: ${command}`);
|
|
268
|
+
this.rules.push({
|
|
269
|
+
table,
|
|
270
|
+
chain,
|
|
271
|
+
command,
|
|
272
|
+
tag: `${this.ruleTag}:DNAT`,
|
|
273
|
+
added: true
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
else if (fromPortRange.to - fromPortRange.from === toPortRange.to - toPortRange.from) {
|
|
278
|
+
// Port range forward with equal ranges
|
|
279
|
+
const command = `${iptablesCmd} -t ${table} -A ${chain} -p ${this.settings.protocol} --dport ${fromPortRange.from}:${fromPortRange.to} ` +
|
|
280
|
+
`-j DNAT --to-destination ${this.settings.toHost}:${toPortRange.from}-${toPortRange.to} ` +
|
|
281
|
+
`-m comment --comment "${this.ruleTag}:DNAT_RANGE"`;
|
|
282
|
+
// Check if rule already exists
|
|
283
|
+
if (this.settings.checkExistingRules && await this.ruleExists(table, command, isIpv6)) {
|
|
284
|
+
this.log('info', `Rule already exists, skipping: ${command}`);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
await execAsync(command);
|
|
288
|
+
this.log('info', `Added port range forwarding rule: ${command}`);
|
|
289
|
+
this.rules.push({
|
|
290
|
+
table,
|
|
291
|
+
chain,
|
|
292
|
+
command,
|
|
293
|
+
tag: `${this.ruleTag}:DNAT_RANGE`,
|
|
294
|
+
added: true
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
// Unequal port ranges need individual rules
|
|
300
|
+
for (let i = 0; i <= fromPortRange.to - fromPortRange.from; i++) {
|
|
301
|
+
const fromPort = fromPortRange.from + i;
|
|
302
|
+
const toPort = toPortRange.from + i % (toPortRange.to - toPortRange.from + 1);
|
|
303
|
+
const command = `${iptablesCmd} -t ${table} -A ${chain} -p ${this.settings.protocol} --dport ${fromPort} ` +
|
|
304
|
+
`-j DNAT --to-destination ${this.settings.toHost}:${toPort} ` +
|
|
305
|
+
`-m comment --comment "${this.ruleTag}:DNAT_INDIVIDUAL"`;
|
|
306
|
+
// Check if rule already exists
|
|
307
|
+
if (this.settings.checkExistingRules && await this.ruleExists(table, command, isIpv6)) {
|
|
308
|
+
this.log('info', `Rule already exists, skipping: ${command}`);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
await execAsync(command);
|
|
312
|
+
this.log('info', `Added individual port forwarding rule: ${command}`);
|
|
313
|
+
this.rules.push({
|
|
314
|
+
table,
|
|
315
|
+
chain,
|
|
316
|
+
command,
|
|
317
|
+
tag: `${this.ruleTag}:DNAT_INDIVIDUAL`,
|
|
318
|
+
added: true
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// If preserveSourceIP is false, add a MASQUERADE rule
|
|
323
|
+
if (!this.settings.preserveSourceIP) {
|
|
324
|
+
// For port range
|
|
325
|
+
const masqCommand = `${iptablesCmd} -t nat -A POSTROUTING -p ${this.settings.protocol} -d ${this.settings.toHost} ` +
|
|
326
|
+
`--dport ${toPortRange.from}:${toPortRange.to} -j MASQUERADE ` +
|
|
327
|
+
`-m comment --comment "${this.ruleTag}:MASQ"`;
|
|
328
|
+
// Check if rule already exists
|
|
329
|
+
if (this.settings.checkExistingRules && await this.ruleExists('nat', masqCommand, isIpv6)) {
|
|
330
|
+
this.log('info', `Rule already exists, skipping: ${masqCommand}`);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
await execAsync(masqCommand);
|
|
334
|
+
this.log('info', `Added MASQUERADE rule: ${masqCommand}`);
|
|
335
|
+
this.rules.push({
|
|
336
|
+
table: 'nat',
|
|
337
|
+
chain: 'POSTROUTING',
|
|
338
|
+
command: masqCommand,
|
|
339
|
+
tag: `${this.ruleTag}:MASQ`,
|
|
340
|
+
added: true
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
catch (err) {
|
|
347
|
+
this.log('error', `Failed to add port forwarding rule: ${err}`);
|
|
348
|
+
// Try to roll back any rules that were already added
|
|
349
|
+
await this.rollbackRules();
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Special handling for NetworkProxy integration
|
|
355
|
+
*/
|
|
356
|
+
async setupNetworkProxyIntegration(isIpv6 = false) {
|
|
357
|
+
if (!this.settings.netProxyIntegration?.enabled) {
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
const netProxyConfig = this.settings.netProxyIntegration;
|
|
361
|
+
const iptablesCmd = this.getIptablesCommand(isIpv6);
|
|
362
|
+
const table = 'nat';
|
|
363
|
+
const chain = this.customChain || 'PREROUTING';
|
|
90
364
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
365
|
+
// If redirectLocalhost is true, set up special rule to redirect localhost traffic to NetworkProxy
|
|
366
|
+
if (netProxyConfig.redirectLocalhost && netProxyConfig.sslTerminationPort) {
|
|
367
|
+
const redirectCommand = `${iptablesCmd} -t ${table} -A OUTPUT -p tcp -d 127.0.0.1 -j REDIRECT ` +
|
|
368
|
+
`--to-port ${netProxyConfig.sslTerminationPort} ` +
|
|
369
|
+
`-m comment --comment "${this.ruleTag}:NETPROXY_REDIRECT"`;
|
|
370
|
+
// Check if rule already exists
|
|
371
|
+
if (this.settings.checkExistingRules && await this.ruleExists(table, redirectCommand, isIpv6)) {
|
|
372
|
+
this.log('info', `Rule already exists, skipping: ${redirectCommand}`);
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
await execAsync(redirectCommand);
|
|
376
|
+
this.log('info', `Added NetworkProxy redirection rule: ${redirectCommand}`);
|
|
377
|
+
this.rules.push({
|
|
378
|
+
table,
|
|
379
|
+
chain: 'OUTPUT',
|
|
380
|
+
command: redirectCommand,
|
|
381
|
+
tag: `${this.ruleTag}:NETPROXY_REDIRECT`,
|
|
382
|
+
added: true
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return true;
|
|
93
387
|
}
|
|
94
388
|
catch (err) {
|
|
95
|
-
|
|
389
|
+
this.log('error', `Failed to set up NetworkProxy integration: ${err}`);
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Rolls back rules that were added in case of error
|
|
395
|
+
*/
|
|
396
|
+
async rollbackRules() {
|
|
397
|
+
// Process rules in reverse order (LIFO)
|
|
398
|
+
for (let i = this.rules.length - 1; i >= 0; i--) {
|
|
399
|
+
const rule = this.rules[i];
|
|
400
|
+
if (rule.added) {
|
|
401
|
+
try {
|
|
402
|
+
// Convert -A (add) to -D (delete)
|
|
403
|
+
const deleteCommand = rule.command.replace('-A', '-D');
|
|
404
|
+
await execAsync(deleteCommand);
|
|
405
|
+
this.log('info', `Rolled back rule: ${deleteCommand}`);
|
|
406
|
+
rule.added = false;
|
|
407
|
+
}
|
|
408
|
+
catch (err) {
|
|
409
|
+
this.log('error', `Failed to roll back rule: ${err}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Sets up iptables rules for port forwarding with enhanced features
|
|
416
|
+
*/
|
|
417
|
+
async start() {
|
|
418
|
+
// Optionally clean the slate first
|
|
419
|
+
if (this.settings.forceCleanSlate) {
|
|
420
|
+
await IPTablesProxy.cleanSlate();
|
|
96
421
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
422
|
+
// First set up any custom chains
|
|
423
|
+
if (this.settings.addJumpRule) {
|
|
424
|
+
const chainSetupSuccess = await this.setupCustomChain();
|
|
425
|
+
if (!chainSetupSuccess) {
|
|
426
|
+
throw new Error('Failed to set up custom chain');
|
|
427
|
+
}
|
|
428
|
+
// For IPv6 if enabled
|
|
429
|
+
if (this.settings.ipv6Support) {
|
|
430
|
+
const chainSetupSuccessIpv6 = await this.setupCustomChain(true);
|
|
431
|
+
if (!chainSetupSuccessIpv6) {
|
|
432
|
+
this.log('warn', 'Failed to set up IPv6 custom chain, continuing with IPv4 only');
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// Add source IP filters
|
|
437
|
+
await this.addSourceIPFilter();
|
|
438
|
+
if (this.settings.ipv6Support) {
|
|
439
|
+
await this.addSourceIPFilter(true);
|
|
440
|
+
}
|
|
441
|
+
// Set up NetworkProxy integration if enabled
|
|
442
|
+
if (this.settings.netProxyIntegration?.enabled) {
|
|
443
|
+
const netProxySetupSuccess = await this.setupNetworkProxyIntegration();
|
|
444
|
+
if (!netProxySetupSuccess) {
|
|
445
|
+
this.log('warn', 'Failed to set up NetworkProxy integration');
|
|
446
|
+
}
|
|
447
|
+
if (this.settings.ipv6Support) {
|
|
448
|
+
await this.setupNetworkProxyIntegration(true);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
// Normalize port specifications
|
|
452
|
+
const fromPortRanges = this.normalizePortSpec(this.settings.fromPort);
|
|
453
|
+
const toPortRanges = this.normalizePortSpec(this.settings.toPort);
|
|
454
|
+
// Handle the case where fromPort and toPort counts don't match
|
|
455
|
+
if (fromPortRanges.length !== toPortRanges.length) {
|
|
456
|
+
if (toPortRanges.length === 1) {
|
|
457
|
+
// If there's only one toPort, use it for all fromPorts
|
|
458
|
+
for (const fromRange of fromPortRanges) {
|
|
459
|
+
await this.addPortForwardingRule(fromRange, toPortRanges[0]);
|
|
460
|
+
if (this.settings.ipv6Support) {
|
|
461
|
+
await this.addPortForwardingRule(fromRange, toPortRanges[0], true);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
throw new Error('Mismatched port counts: fromPort and toPort arrays must have equal length or toPort must be a single value');
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
// Add port forwarding rules for each port specification
|
|
471
|
+
for (let i = 0; i < fromPortRanges.length; i++) {
|
|
472
|
+
await this.addPortForwardingRule(fromPortRanges[i], toPortRanges[i]);
|
|
473
|
+
if (this.settings.ipv6Support) {
|
|
474
|
+
await this.addPortForwardingRule(fromPortRanges[i], toPortRanges[i], true);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// Final check - ensure we have at least one rule added
|
|
479
|
+
if (this.rules.filter(r => r.added).length === 0) {
|
|
480
|
+
throw new Error('No rules were added');
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Removes all added iptables rules
|
|
485
|
+
*/
|
|
486
|
+
async stop() {
|
|
487
|
+
// Process rules in reverse order (LIFO)
|
|
488
|
+
for (let i = this.rules.length - 1; i >= 0; i--) {
|
|
489
|
+
const rule = this.rules[i];
|
|
490
|
+
if (rule.added) {
|
|
491
|
+
try {
|
|
492
|
+
// Convert -A (add) to -D (delete)
|
|
493
|
+
const deleteCommand = rule.command.replace('-A', '-D');
|
|
494
|
+
await execAsync(deleteCommand);
|
|
495
|
+
this.log('info', `Removed rule: ${deleteCommand}`);
|
|
496
|
+
rule.added = false;
|
|
497
|
+
}
|
|
498
|
+
catch (err) {
|
|
499
|
+
this.log('error', `Failed to remove rule: ${err}`);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
// If we created a custom chain, we need to clean it up
|
|
504
|
+
if (this.customChain) {
|
|
101
505
|
try {
|
|
102
|
-
|
|
103
|
-
|
|
506
|
+
// First flush the chain
|
|
507
|
+
await execAsync(`iptables -t nat -F ${this.customChain}`);
|
|
508
|
+
this.log('info', `Flushed custom chain: ${this.customChain}`);
|
|
509
|
+
// Then delete it
|
|
510
|
+
await execAsync(`iptables -t nat -X ${this.customChain}`);
|
|
511
|
+
this.log('info', `Deleted custom chain: ${this.customChain}`);
|
|
512
|
+
// Same for IPv6 if enabled
|
|
513
|
+
if (this.settings.ipv6Support) {
|
|
514
|
+
try {
|
|
515
|
+
await execAsync(`ip6tables -t nat -F ${this.customChain}`);
|
|
516
|
+
await execAsync(`ip6tables -t nat -X ${this.customChain}`);
|
|
517
|
+
this.log('info', `Deleted IPv6 custom chain: ${this.customChain}`);
|
|
518
|
+
}
|
|
519
|
+
catch (err) {
|
|
520
|
+
this.log('error', `Failed to delete IPv6 custom chain: ${err}`);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
104
523
|
}
|
|
105
524
|
catch (err) {
|
|
106
|
-
|
|
525
|
+
this.log('error', `Failed to delete custom chain: ${err}`);
|
|
107
526
|
}
|
|
108
527
|
}
|
|
109
|
-
|
|
528
|
+
// Clear rules array
|
|
529
|
+
this.rules = [];
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Synchronous version of stop, for use in exit handlers
|
|
533
|
+
*/
|
|
534
|
+
stopSync() {
|
|
535
|
+
// Process rules in reverse order (LIFO)
|
|
536
|
+
for (let i = this.rules.length - 1; i >= 0; i--) {
|
|
537
|
+
const rule = this.rules[i];
|
|
538
|
+
if (rule.added) {
|
|
539
|
+
try {
|
|
540
|
+
// Convert -A (add) to -D (delete)
|
|
541
|
+
const deleteCommand = rule.command.replace('-A', '-D');
|
|
542
|
+
execSync(deleteCommand);
|
|
543
|
+
this.log('info', `Removed rule: ${deleteCommand}`);
|
|
544
|
+
rule.added = false;
|
|
545
|
+
}
|
|
546
|
+
catch (err) {
|
|
547
|
+
this.log('error', `Failed to remove rule: ${err}`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
// If we created a custom chain, we need to clean it up
|
|
552
|
+
if (this.customChain) {
|
|
553
|
+
try {
|
|
554
|
+
// First flush the chain
|
|
555
|
+
execSync(`iptables -t nat -F ${this.customChain}`);
|
|
556
|
+
// Then delete it
|
|
557
|
+
execSync(`iptables -t nat -X ${this.customChain}`);
|
|
558
|
+
this.log('info', `Deleted custom chain: ${this.customChain}`);
|
|
559
|
+
// Same for IPv6 if enabled
|
|
560
|
+
if (this.settings.ipv6Support) {
|
|
561
|
+
try {
|
|
562
|
+
execSync(`ip6tables -t nat -F ${this.customChain}`);
|
|
563
|
+
execSync(`ip6tables -t nat -X ${this.customChain}`);
|
|
564
|
+
}
|
|
565
|
+
catch (err) {
|
|
566
|
+
// IPv6 failures are non-critical
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
catch (err) {
|
|
571
|
+
this.log('error', `Failed to delete custom chain: ${err}`);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
// Clear rules array
|
|
575
|
+
this.rules = [];
|
|
110
576
|
}
|
|
111
577
|
/**
|
|
112
578
|
* Asynchronously cleans up any iptables rules in the nat table that were added by this module.
|
|
113
579
|
* It looks for rules with comments containing "IPTablesProxy:".
|
|
114
580
|
*/
|
|
115
581
|
static async cleanSlate() {
|
|
582
|
+
await IPTablesProxy.cleanSlateInternal();
|
|
583
|
+
// Also clean IPv6 rules
|
|
584
|
+
await IPTablesProxy.cleanSlateInternal(true);
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Internal implementation of cleanSlate with IPv6 support
|
|
588
|
+
*/
|
|
589
|
+
static async cleanSlateInternal(isIpv6 = false) {
|
|
590
|
+
const iptablesCmd = isIpv6 ? 'ip6tables' : 'iptables';
|
|
116
591
|
try {
|
|
117
|
-
const { stdout } = await execAsync(
|
|
592
|
+
const { stdout } = await execAsync(`${iptablesCmd}-save -t nat`);
|
|
118
593
|
const lines = stdout.split('\n');
|
|
119
594
|
const proxyLines = lines.filter(line => line.includes('IPTablesProxy:'));
|
|
595
|
+
// First, find and remove any custom chains
|
|
596
|
+
const customChains = new Set();
|
|
597
|
+
const jumpRules = [];
|
|
120
598
|
for (const line of proxyLines) {
|
|
599
|
+
if (line.includes('IPTablesProxy:JUMP')) {
|
|
600
|
+
// Extract chain name from jump rule
|
|
601
|
+
const match = line.match(/\s+-j\s+(\S+)\s+/);
|
|
602
|
+
if (match && match[1].startsWith('IPTablesProxy_')) {
|
|
603
|
+
customChains.add(match[1]);
|
|
604
|
+
jumpRules.push(line);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
// Remove jump rules first
|
|
609
|
+
for (const line of jumpRules) {
|
|
121
610
|
const trimmedLine = line.trim();
|
|
122
611
|
if (trimmedLine.startsWith('-A')) {
|
|
123
|
-
// Replace the "-A" with "-D" to form a deletion command
|
|
612
|
+
// Replace the "-A" with "-D" to form a deletion command
|
|
124
613
|
const deleteRule = trimmedLine.replace('-A', '-D');
|
|
125
|
-
const cmd =
|
|
614
|
+
const cmd = `${iptablesCmd} -t nat ${deleteRule}`;
|
|
126
615
|
try {
|
|
127
616
|
await execAsync(cmd);
|
|
128
|
-
console.log(`Cleaned up iptables rule: ${cmd}`);
|
|
617
|
+
console.log(`Cleaned up iptables jump rule: ${cmd}`);
|
|
129
618
|
}
|
|
130
619
|
catch (err) {
|
|
131
|
-
console.error(`Failed to remove iptables rule: ${cmd}`, err);
|
|
620
|
+
console.error(`Failed to remove iptables jump rule: ${cmd}`, err);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
// Then remove all other rules
|
|
625
|
+
for (const line of proxyLines) {
|
|
626
|
+
if (!line.includes('IPTablesProxy:JUMP')) { // Skip jump rules we already handled
|
|
627
|
+
const trimmedLine = line.trim();
|
|
628
|
+
if (trimmedLine.startsWith('-A')) {
|
|
629
|
+
// Replace the "-A" with "-D" to form a deletion command
|
|
630
|
+
const deleteRule = trimmedLine.replace('-A', '-D');
|
|
631
|
+
const cmd = `${iptablesCmd} -t nat ${deleteRule}`;
|
|
632
|
+
try {
|
|
633
|
+
await execAsync(cmd);
|
|
634
|
+
console.log(`Cleaned up iptables rule: ${cmd}`);
|
|
635
|
+
}
|
|
636
|
+
catch (err) {
|
|
637
|
+
console.error(`Failed to remove iptables rule: ${cmd}`, err);
|
|
638
|
+
}
|
|
132
639
|
}
|
|
133
640
|
}
|
|
134
641
|
}
|
|
642
|
+
// Finally clean up custom chains
|
|
643
|
+
for (const chain of customChains) {
|
|
644
|
+
try {
|
|
645
|
+
// Flush the chain
|
|
646
|
+
await execAsync(`${iptablesCmd} -t nat -F ${chain}`);
|
|
647
|
+
console.log(`Flushed custom chain: ${chain}`);
|
|
648
|
+
// Delete the chain
|
|
649
|
+
await execAsync(`${iptablesCmd} -t nat -X ${chain}`);
|
|
650
|
+
console.log(`Deleted custom chain: ${chain}`);
|
|
651
|
+
}
|
|
652
|
+
catch (err) {
|
|
653
|
+
console.error(`Failed to delete custom chain ${chain}:`, err);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
135
656
|
}
|
|
136
657
|
catch (err) {
|
|
137
|
-
console.error(`Failed to run
|
|
658
|
+
console.error(`Failed to run ${iptablesCmd}-save: ${err}`);
|
|
138
659
|
}
|
|
139
660
|
}
|
|
140
661
|
/**
|
|
@@ -143,28 +664,102 @@ export class IPTablesProxy {
|
|
|
143
664
|
* This method is intended for use in process exit handlers.
|
|
144
665
|
*/
|
|
145
666
|
static cleanSlateSync() {
|
|
667
|
+
IPTablesProxy.cleanSlateSyncInternal();
|
|
668
|
+
// Also clean IPv6 rules
|
|
669
|
+
IPTablesProxy.cleanSlateSyncInternal(true);
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Internal implementation of cleanSlateSync with IPv6 support
|
|
673
|
+
*/
|
|
674
|
+
static cleanSlateSyncInternal(isIpv6 = false) {
|
|
675
|
+
const iptablesCmd = isIpv6 ? 'ip6tables' : 'iptables';
|
|
146
676
|
try {
|
|
147
|
-
const stdout = execSync(
|
|
677
|
+
const stdout = execSync(`${iptablesCmd}-save -t nat`).toString();
|
|
148
678
|
const lines = stdout.split('\n');
|
|
149
679
|
const proxyLines = lines.filter(line => line.includes('IPTablesProxy:'));
|
|
680
|
+
// First, find and remove any custom chains
|
|
681
|
+
const customChains = new Set();
|
|
682
|
+
const jumpRules = [];
|
|
150
683
|
for (const line of proxyLines) {
|
|
684
|
+
if (line.includes('IPTablesProxy:JUMP')) {
|
|
685
|
+
// Extract chain name from jump rule
|
|
686
|
+
const match = line.match(/\s+-j\s+(\S+)\s+/);
|
|
687
|
+
if (match && match[1].startsWith('IPTablesProxy_')) {
|
|
688
|
+
customChains.add(match[1]);
|
|
689
|
+
jumpRules.push(line);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
// Remove jump rules first
|
|
694
|
+
for (const line of jumpRules) {
|
|
151
695
|
const trimmedLine = line.trim();
|
|
152
696
|
if (trimmedLine.startsWith('-A')) {
|
|
697
|
+
// Replace the "-A" with "-D" to form a deletion command
|
|
153
698
|
const deleteRule = trimmedLine.replace('-A', '-D');
|
|
154
|
-
const cmd =
|
|
699
|
+
const cmd = `${iptablesCmd} -t nat ${deleteRule}`;
|
|
155
700
|
try {
|
|
156
701
|
execSync(cmd);
|
|
157
|
-
console.log(`Cleaned up iptables rule: ${cmd}`);
|
|
702
|
+
console.log(`Cleaned up iptables jump rule: ${cmd}`);
|
|
158
703
|
}
|
|
159
704
|
catch (err) {
|
|
160
|
-
console.error(`Failed to remove iptables rule: ${cmd}`, err);
|
|
705
|
+
console.error(`Failed to remove iptables jump rule: ${cmd}`, err);
|
|
161
706
|
}
|
|
162
707
|
}
|
|
163
708
|
}
|
|
709
|
+
// Then remove all other rules
|
|
710
|
+
for (const line of proxyLines) {
|
|
711
|
+
if (!line.includes('IPTablesProxy:JUMP')) { // Skip jump rules we already handled
|
|
712
|
+
const trimmedLine = line.trim();
|
|
713
|
+
if (trimmedLine.startsWith('-A')) {
|
|
714
|
+
const deleteRule = trimmedLine.replace('-A', '-D');
|
|
715
|
+
const cmd = `${iptablesCmd} -t nat ${deleteRule}`;
|
|
716
|
+
try {
|
|
717
|
+
execSync(cmd);
|
|
718
|
+
console.log(`Cleaned up iptables rule: ${cmd}`);
|
|
719
|
+
}
|
|
720
|
+
catch (err) {
|
|
721
|
+
console.error(`Failed to remove iptables rule: ${cmd}`, err);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
// Finally clean up custom chains
|
|
727
|
+
for (const chain of customChains) {
|
|
728
|
+
try {
|
|
729
|
+
// Flush the chain
|
|
730
|
+
execSync(`${iptablesCmd} -t nat -F ${chain}`);
|
|
731
|
+
// Delete the chain
|
|
732
|
+
execSync(`${iptablesCmd} -t nat -X ${chain}`);
|
|
733
|
+
console.log(`Deleted custom chain: ${chain}`);
|
|
734
|
+
}
|
|
735
|
+
catch (err) {
|
|
736
|
+
console.error(`Failed to delete custom chain ${chain}:`, err);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
164
739
|
}
|
|
165
740
|
catch (err) {
|
|
166
|
-
console.error(`Failed to run
|
|
741
|
+
console.error(`Failed to run ${iptablesCmd}-save: ${err}`);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Logging utility that respects the enableLogging setting
|
|
746
|
+
*/
|
|
747
|
+
log(level, message) {
|
|
748
|
+
if (!this.settings.enableLogging && level === 'info') {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
const timestamp = new Date().toISOString();
|
|
752
|
+
switch (level) {
|
|
753
|
+
case 'info':
|
|
754
|
+
console.log(`[${timestamp}] [INFO] ${message}`);
|
|
755
|
+
break;
|
|
756
|
+
case 'warn':
|
|
757
|
+
console.warn(`[${timestamp}] [WARN] ${message}`);
|
|
758
|
+
break;
|
|
759
|
+
case 'error':
|
|
760
|
+
console.error(`[${timestamp}] [ERROR] ${message}`);
|
|
761
|
+
break;
|
|
167
762
|
}
|
|
168
763
|
}
|
|
169
764
|
}
|
|
170
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5pcHRhYmxlc3Byb3h5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5pcHRhYmxlc3Byb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQy9DLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFakMsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBYWxDOzs7R0FHRztBQUNILE1BQU0sT0FBTyxhQUFhO0lBS3hCLFlBQVksUUFBK0I7UUFIbkMsbUJBQWMsR0FBWSxLQUFLLENBQUM7UUFJdEMsSUFBSSxDQUFDLFFBQVEsR0FBRztZQUNkLEdBQUcsUUFBUTtZQUNYLE1BQU0sRUFBRSxRQUFRLENBQUMsTUFBTSxJQUFJLFdBQVc7U0FDdkMsQ0FBQztRQUNGLHFFQUFxRTtRQUNyRSxJQUFJLENBQUMsT0FBTyxHQUFHLGlCQUFpQixJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFFeEYsc0RBQXNEO1FBQ3RELElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUMvQixNQUFNLE9BQU8sR0FBRyxHQUFHLEVBQUU7Z0JBQ25CLElBQUksQ0FBQztvQkFDSCxhQUFhLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ2pDLENBQUM7Z0JBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztvQkFDYixPQUFPLENBQUMsS0FBSyxDQUFDLHdDQUF3QyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUMvRCxDQUFDO1lBQ0gsQ0FBQyxDQUFDO1lBQ0YsT0FBTyxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENB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
|
|
765
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5pcHRhYmxlc3Byb3h5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5pcHRhYmxlc3Byb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQy9DLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFakMsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBc0RsQzs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQU14QixZQUFZLFFBQStCO1FBSm5DLFVBQUssR0FBbUIsRUFBRSxDQUFDO1FBRTNCLGdCQUFXLEdBQWtCLElBQUksQ0FBQztRQUd4QywrQ0FBK0M7UUFDL0MsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRWhDLHVCQUF1QjtRQUN2QixJQUFJLENBQUMsUUFBUSxHQUFHO1lBQ2QsR0FBRyxRQUFRO1lBQ1gsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLElBQUksV0FBVztZQUN0QyxRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVEsSUFBSSxLQUFLO1lBQ3BDLGFBQWEsRUFBRSxRQUFRLENBQUMsYUFBYSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsS0FBSztZQUNwRixXQUFXLEVBQUUsUUFBUSxDQUFDLFdBQVcsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLEtBQUs7WUFDOUUsa0JBQWtCLEVBQUUsUUFBUSxDQUFDLGtCQUFrQixLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxJQUFJO1lBQ2xHLG1CQUFtQixFQUFFLFFBQVEsQ0FBQyxtQkFBbUIsSUFBSSxFQUFFLE9BQU8sRUFBRSxL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
|