@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.
@@ -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
- * It only supports basic port forwarding and uses iptables comments to tag rules.
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.rulesInstalled = false;
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
- // If deleteOnExit is true, register cleanup handlers.
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
- IPTablesProxy.cleanSlateSync();
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
- * Sets up iptables rules for port forwarding.
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
- async start() {
43
- const dnatCmd = `iptables -t nat -A PREROUTING -p tcp --dport ${this.settings.fromPort} ` +
44
- `-j DNAT --to-destination ${this.settings.toHost}:${this.settings.toPort} ` +
45
- `-m comment --comment "${this.ruleTag}:DNAT"`;
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
- await execAsync(dnatCmd);
48
- console.log(`Added iptables rule: ${dnatCmd}`);
49
- this.rulesInstalled = true;
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
- console.error(`Failed to add iptables DNAT rule: ${err}`);
53
- throw err;
54
- }
55
- // If preserveSourceIP is false, add a MASQUERADE rule.
56
- if (!this.settings.preserveSourceIP) {
57
- const masqueradeCmd = `iptables -t nat -A POSTROUTING -p tcp -d ${this.settings.toHost} ` +
58
- `--dport ${this.settings.toPort} -j MASQUERADE ` +
59
- `-m comment --comment "${this.ruleTag}:MASQ"`;
60
- try {
61
- await execAsync(masqueradeCmd);
62
- console.log(`Added iptables rule: ${masqueradeCmd}`);
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
- catch (err) {
65
- console.error(`Failed to add iptables MASQUERADE rule: ${err}`);
66
- // Roll back the DNAT rule if MASQUERADE fails.
67
- try {
68
- const rollbackCmd = `iptables -t nat -D PREROUTING -p tcp --dport ${this.settings.fromPort} ` +
69
- `-j DNAT --to-destination ${this.settings.toHost}:${this.settings.toPort} ` +
70
- `-m comment --comment "${this.ruleTag}:DNAT"`;
71
- await execAsync(rollbackCmd);
72
- this.rulesInstalled = false;
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
- catch (rollbackErr) {
75
- console.error(`Rollback failed: ${rollbackErr}`);
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
- * Removes the iptables rules that were added in start(), by matching the unique comment.
248
+ * Adds a port forwarding rule
83
249
  */
84
- async stop() {
85
- if (!this.rulesInstalled)
86
- return;
87
- const dnatDelCmd = `iptables -t nat -D PREROUTING -p tcp --dport ${this.settings.fromPort} ` +
88
- `-j DNAT --to-destination ${this.settings.toHost}:${this.settings.toPort} ` +
89
- `-m comment --comment "${this.ruleTag}:DNAT"`;
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
- await execAsync(dnatDelCmd);
92
- console.log(`Removed iptables rule: ${dnatDelCmd}`);
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
- console.error(`Failed to remove iptables DNAT rule: ${err}`);
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
- if (!this.settings.preserveSourceIP) {
98
- const masqueradeDelCmd = `iptables -t nat -D POSTROUTING -p tcp -d ${this.settings.toHost} ` +
99
- `--dport ${this.settings.toPort} -j MASQUERADE ` +
100
- `-m comment --comment "${this.ruleTag}:MASQ"`;
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
- await execAsync(masqueradeDelCmd);
103
- console.log(`Removed iptables rule: ${masqueradeDelCmd}`);
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
- console.error(`Failed to remove iptables MASQUERADE rule: ${err}`);
525
+ this.log('error', `Failed to delete custom chain: ${err}`);
107
526
  }
108
527
  }
109
- this.rulesInstalled = false;
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('iptables-save -t nat');
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 = `iptables -t nat ${deleteRule}`;
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 iptables-save: ${err}`);
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('iptables-save -t nat').toString();
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 = `iptables -t nat ${deleteRule}`;
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 iptables-save: ${err}`);
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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