-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
136 lines (111 loc) · 4.44 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
const express = require('express');
const { exec } = require('child_process');
const bodyParser = require('body-parser');
require('dotenv').config();
const app = express();
const PORT = process.env.PORT||3000;
// Load API secret from environment variables
const API_SECRET = process.env.API_SECRET;
// Middleware for parsing JSON
app.use(bodyParser.json());
app.use(express.static('public'));
// Middleware for API secret verification
function authenticate(req, res, next) {
const apiSecret = req.headers['api-secret'];
if (!apiSecret || apiSecret !== API_SECRET) {
return res.status(403).json({ error: 'Forbidden: Invalid API secret' });
}
next();
}
// Helper function to execute shell commands
function executeCommand(command) {
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if (error) {
return reject({ error: error.message, stderr });
}
resolve(stdout || stderr);
});
});
}
// Route to add a port forwarding rule
app.post('/api/port-forward', authenticate, async (req, res) => {
const { externalPort, targetIp, targetPort } = req.body;
if (!externalPort || !targetIp || !targetPort) {
return res.status(400).json({ error: 'Invalid parameters' });
}
try {
const preroutingCommand = `iptables -t nat -A PREROUTING -p tcp --dport ${externalPort} -j DNAT --to-destination ${targetIp}:${targetPort}`;
const postroutingCommand = `iptables -t nat -A POSTROUTING -j MASQUERADE`;
await executeCommand(preroutingCommand);
await executeCommand(postroutingCommand);
res.json({ message: `Port forwarding added: ${externalPort} -> ${targetIp}:${targetPort}` });
} catch (err) {
res.status(500).json({ error: 'Failed to add port forwarding', details: err });
}
});
// Route to list all NAT port forwarding rules
app.get('/api/port-forward', authenticate, async (req, res) => {
try {
const listCommand = `iptables -t nat -L PREROUTING -n -v`;
const output = await executeCommand(listCommand);
// Parse the output to JSON format
const rules = parseIptablesOutput(output);
res.json({ message: 'NAT port forwarding rules:', rules });
} catch (err) {
res.status(500).json({ error: 'Failed to retrieve port forwarding rules', details: err });
}
});
// Helper function to parse iptables output
function parseIptablesOutput(output) {
const lines = output.trim().split('\n');
const rules = [];
// Skip the first two lines which are headers
for (let i = 2; i < lines.length; i++) {
const line = lines[i].trim();
if (line === '') continue; // Skip empty lines
const columns = line.split(/\s+/); // Split by whitespace
// Assuming the structure is consistent and the columns are:
// 0: target, 1: protocol, 2: in-interface, 3: out-interface,
// 4: source, 5: destination, 6: options
if (columns.length >= 6) { // Ensure there are enough columns
const rule = {
target: columns[0],
protocol: columns[1],
in: columns[2],
out: columns[3],
source: columns[4],
destination: columns[5],
options: columns.slice(6).join(' '), // Join any remaining columns as options
};
rules.push(rule);
}
}
return rules;
}
// Route to delete a specific port forwarding rule
app.delete('/api/port-forward', authenticate, async (req, res) => {
const { externalPort, targetIp, targetPort } = req.body;
if (!externalPort || !targetIp || !targetPort) {
return res.status(400).json({ error: 'Invalid parameters' });
}
try {
// Delete the specific PREROUTING rule
const preroutingDelete = `iptables -t nat -D PREROUTING -p tcp --dport ${externalPort} -j DNAT --to-destination ${targetIp}:${targetPort}`;
await executeCommand(preroutingDelete);
// Check if other rules exist in PREROUTING; if not, remove MASQUERADE
const checkRulesCommand = `iptables -t nat -L PREROUTING -n -v | grep 'DNAT --to-destination'`;
const activeRules = await executeCommand(checkRulesCommand);
if (!activeRules.trim()) {
const postroutingDelete = `iptables -t nat -D POSTROUTING -j MASQUERADE`;
await executeCommand(postroutingDelete);
}
res.json({ message: `Port forwarding removed: ${externalPort} -> ${targetIp}:${targetPort}` });
} catch (err) {
res.status(500).json({ error: 'Failed to remove port forwarding', details: err });
}
});
// Start server
app.listen(PORT,"0.0.0.0", () => {
console.log(`Server running on http://localhost:${PORT}`);
});