@chenpu17/tcpmapping 2.0.0

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/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # TCP转发服务器
2
+
3
+ 一个功能强大、安全可靠的TCP端口转发服务器,支持多端口映射、WebUI管理界面和实时连接监控。
4
+
5
+ ## 功能特性
6
+
7
+ ### 核心功能
8
+ - **TCP协议端口转发** - 将TCP请求转发到后端服务器
9
+ - **多端口映射配置** - 同时支持多个端口转发规则
10
+ - **动态配置管理** - 通过WebUI实时添加/删除/启动/停止端口映射
11
+ - **连接监控** - 实时显示每个映射的连接数和流量统计
12
+
13
+ ### WebUI管理界面
14
+ - 现代化响应式Web界面
15
+ - 实时系统状态监控(映射数、连接数、运行时间)
16
+ - 每个端口映射的连接数和流量统计
17
+ - 映射的启动/停止控制
18
+
19
+ ### 安全特性
20
+ - 强密码策略(8字符+大小写+数字)
21
+ - 登录失败保护(5次失败锁定30分钟)
22
+ - 会话管理(24小时自动超时)
23
+ - bcrypt 12轮密码哈希加密
24
+ - 自动生成的Session Secret
25
+
26
+ ## 快速开始
27
+
28
+ ### 安装
29
+ ```bash
30
+ # 安装依赖
31
+ npm install
32
+
33
+ # 设置管理员密码
34
+ npm run setup-password
35
+
36
+ # 启动服务器
37
+ npm start
38
+ ```
39
+
40
+ ### 访问
41
+ 启动后访问 **http://localhost:9999** 进入管理界面。
42
+
43
+ ## 配置说明
44
+
45
+ 编辑 `config.json` 配置端口映射:
46
+
47
+ ```json
48
+ {
49
+ "mappings": [
50
+ {
51
+ "name": "服务名称",
52
+ "listen": { "host": "0.0.0.0", "port": 8080 },
53
+ "target": { "host": "192.168.1.100", "port": 3000 }
54
+ }
55
+ ],
56
+ "webui": { "enabled": true, "port": 9999, "host": "0.0.0.0" },
57
+ "logging": { "enabled": true, "level": "info" }
58
+ }
59
+ ```
60
+
61
+ ## 项目结构
62
+
63
+ ```
64
+ ├── server.js # 主服务器
65
+ ├── config.json # 端口映射配置
66
+ ├── auth-config.json # 认证配置(敏感)
67
+ ├── setup-password.js # 密码设置工具
68
+ ├── package.json # 项目配置
69
+ ├── .gitignore # Git忽略规则
70
+ ├── public/ # Web界面
71
+ │ ├── login.html # 登录页面
72
+ │ └── dashboard.html # 管理面板
73
+ └── docs/ # 文档目录
74
+ ├── API.md # API接口文档
75
+ ├── 功能总结.md # 功能清单
76
+ └── 安全配置说明.md # 安全指南
77
+ ```
78
+
79
+ ## API接口
80
+
81
+ 详细API文档请参阅 [docs/API.md](docs/API.md)
82
+
83
+ 主要接口:
84
+ - `GET /api/health` - 健康检查(无需认证)
85
+ - `POST /api/login` - 登录
86
+ - `GET /api/mappings` - 获取映射列表(含连接数统计)
87
+ - `POST /api/mappings` - 添加映射
88
+ - `PUT /api/mappings/:id` - 更新映射
89
+ - `DELETE /api/mappings/:id` - 删除映射
90
+ - `POST /api/mappings/:id/start` - 启动映射
91
+ - `POST /api/mappings/:id/stop` - 停止映射
92
+ - `GET /api/connections` - 获取连接状态
93
+ - `GET /api/status` - 获取系统状态
94
+
95
+ ## 技术栈
96
+
97
+ - **后端**: Node.js, Express.js, bcryptjs
98
+ - **前端**: 原生HTML/CSS/JavaScript
99
+ - **安全**: bcrypt密码哈希, Session管理
100
+
101
+ ## 许可证
102
+
103
+ MIT License
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn, execSync } = require('child_process');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+
8
+ const APP_NAME = 'tcpmapping';
9
+ const PID_FILE = path.join(os.tmpdir(), 'tcpmapping.pid');
10
+ const LOG_FILE = path.join(os.tmpdir(), 'tcpmapping.log');
11
+ const SERVER_FILE = path.join(__dirname, '..', 'server.js');
12
+ const SETUP_PASSWORD_FILE = path.join(__dirname, '..', 'setup-password.js');
13
+
14
+ // 获取命令行参数
15
+ const args = process.argv.slice(2);
16
+ const command = args[0] || 'help';
17
+
18
+ // 颜色输出
19
+ const colors = {
20
+ green: (text) => `\x1b[32m${text}\x1b[0m`,
21
+ red: (text) => `\x1b[31m${text}\x1b[0m`,
22
+ yellow: (text) => `\x1b[33m${text}\x1b[0m`,
23
+ blue: (text) => `\x1b[34m${text}\x1b[0m`,
24
+ cyan: (text) => `\x1b[36m${text}\x1b[0m`
25
+ };
26
+
27
+ // 检查进程是否运行
28
+ function isRunning() {
29
+ if (!fs.existsSync(PID_FILE)) {
30
+ return false;
31
+ }
32
+
33
+ const pid = fs.readFileSync(PID_FILE, 'utf8').trim();
34
+
35
+ try {
36
+ process.kill(parseInt(pid), 0);
37
+ return parseInt(pid);
38
+ } catch (e) {
39
+ // 进程不存在,清理PID文件
40
+ fs.unlinkSync(PID_FILE);
41
+ return false;
42
+ }
43
+ }
44
+
45
+ // 启动服务
46
+ function start() {
47
+ const pid = isRunning();
48
+ if (pid) {
49
+ console.log(colors.yellow(`${APP_NAME} is already running (PID: ${pid})`));
50
+ return;
51
+ }
52
+
53
+ console.log(colors.blue(`Starting ${APP_NAME}...`));
54
+
55
+ const out = fs.openSync(LOG_FILE, 'a');
56
+ const err = fs.openSync(LOG_FILE, 'a');
57
+
58
+ const child = spawn('node', [SERVER_FILE], {
59
+ detached: true,
60
+ stdio: ['ignore', out, err],
61
+ cwd: path.dirname(SERVER_FILE)
62
+ });
63
+
64
+ fs.writeFileSync(PID_FILE, child.pid.toString());
65
+ child.unref();
66
+
67
+ console.log(colors.green(`${APP_NAME} started successfully (PID: ${child.pid})`));
68
+ console.log(colors.cyan(`WebUI: http://localhost:9999`));
69
+ console.log(colors.cyan(`Log file: ${LOG_FILE}`));
70
+ }
71
+
72
+ // 停止服务
73
+ function stop() {
74
+ const pid = isRunning();
75
+ if (!pid) {
76
+ console.log(colors.yellow(`${APP_NAME} is not running`));
77
+ return;
78
+ }
79
+
80
+ console.log(colors.blue(`Stopping ${APP_NAME} (PID: ${pid})...`));
81
+
82
+ try {
83
+ process.kill(pid, 'SIGTERM');
84
+
85
+ // 等待进程退出
86
+ let attempts = 0;
87
+ while (attempts < 10) {
88
+ try {
89
+ process.kill(pid, 0);
90
+ // 进程仍在运行
91
+ require('child_process').execSync('sleep 0.5');
92
+ attempts++;
93
+ } catch (e) {
94
+ // 进程已退出
95
+ break;
96
+ }
97
+ }
98
+
99
+ // 如果进程仍在运行,强制终止
100
+ try {
101
+ process.kill(pid, 0);
102
+ process.kill(pid, 'SIGKILL');
103
+ } catch (e) {
104
+ // 进程已退出
105
+ }
106
+
107
+ if (fs.existsSync(PID_FILE)) {
108
+ fs.unlinkSync(PID_FILE);
109
+ }
110
+
111
+ console.log(colors.green(`${APP_NAME} stopped successfully`));
112
+ } catch (e) {
113
+ console.log(colors.red(`Failed to stop ${APP_NAME}: ${e.message}`));
114
+ }
115
+ }
116
+
117
+ // 重启服务
118
+ function restart() {
119
+ console.log(colors.blue(`Restarting ${APP_NAME}...`));
120
+ stop();
121
+ setTimeout(() => {
122
+ start();
123
+ }, 1000);
124
+ }
125
+
126
+ // 查看状态
127
+ function status() {
128
+ const pid = isRunning();
129
+ if (pid) {
130
+ console.log(colors.green(`${APP_NAME} is running (PID: ${pid})`));
131
+
132
+ // 尝试获取健康状态
133
+ try {
134
+ const http = require('http');
135
+ const req = http.get('http://localhost:9999/api/health', { timeout: 2000 }, (res) => {
136
+ let data = '';
137
+ res.on('data', chunk => data += chunk);
138
+ res.on('end', () => {
139
+ try {
140
+ const health = JSON.parse(data);
141
+ console.log(colors.cyan(` Status: ${health.status}`));
142
+ console.log(colors.cyan(` Uptime: ${Math.floor(health.uptime / 60)} minutes`));
143
+ console.log(colors.cyan(` Active Mappings: ${health.activeMappings}`));
144
+ console.log(colors.cyan(` Active Connections: ${health.activeConnections}`));
145
+ } catch (e) {}
146
+ });
147
+ });
148
+ req.on('error', () => {});
149
+ req.on('timeout', () => req.destroy());
150
+ } catch (e) {}
151
+ } else {
152
+ console.log(colors.red(`${APP_NAME} is not running`));
153
+ }
154
+ }
155
+
156
+ // 查看日志
157
+ function logs(follow = false) {
158
+ if (!fs.existsSync(LOG_FILE)) {
159
+ console.log(colors.yellow('No log file found'));
160
+ return;
161
+ }
162
+
163
+ if (follow) {
164
+ console.log(colors.blue(`Tailing ${LOG_FILE}... (Ctrl+C to exit)`));
165
+ const tail = spawn('tail', ['-f', LOG_FILE], { stdio: 'inherit' });
166
+ process.on('SIGINT', () => {
167
+ tail.kill();
168
+ process.exit(0);
169
+ });
170
+ } else {
171
+ const content = fs.readFileSync(LOG_FILE, 'utf8');
172
+ const lines = content.split('\n').slice(-50);
173
+ console.log(lines.join('\n'));
174
+ }
175
+ }
176
+
177
+ // 设置密码
178
+ function setupPassword() {
179
+ console.log(colors.blue('Setting up password...'));
180
+ const child = spawn('node', [SETUP_PASSWORD_FILE], {
181
+ stdio: 'inherit',
182
+ cwd: path.dirname(SETUP_PASSWORD_FILE)
183
+ });
184
+
185
+ child.on('exit', (code) => {
186
+ process.exit(code);
187
+ });
188
+ }
189
+
190
+ // 初始化配置
191
+ function init() {
192
+ const configDir = process.cwd();
193
+ const configFile = path.join(configDir, 'config.json');
194
+
195
+ if (fs.existsSync(configFile)) {
196
+ console.log(colors.yellow('config.json already exists'));
197
+ return;
198
+ }
199
+
200
+ const defaultConfig = {
201
+ mappings: [
202
+ {
203
+ name: "Example",
204
+ listen: { host: "0.0.0.0", port: 8080 },
205
+ target: { host: "127.0.0.1", port: 3000 }
206
+ }
207
+ ],
208
+ webui: { enabled: true, port: 9999, host: "0.0.0.0" },
209
+ logging: { enabled: true, level: "info" }
210
+ };
211
+
212
+ fs.writeFileSync(configFile, JSON.stringify(defaultConfig, null, 2));
213
+ console.log(colors.green('Created config.json'));
214
+ console.log(colors.cyan('Edit config.json to configure your port mappings'));
215
+ }
216
+
217
+ // 显示版本
218
+ function version() {
219
+ const pkg = require(path.join(__dirname, '..', 'package.json'));
220
+ console.log(`${APP_NAME} v${pkg.version}`);
221
+ }
222
+
223
+ // 显示帮助
224
+ function help() {
225
+ console.log(`
226
+ ${colors.cyan('TCP Mapping Server')} - TCP端口转发服务器
227
+
228
+ ${colors.yellow('Usage:')}
229
+ tcpmapping <command>
230
+
231
+ ${colors.yellow('Commands:')}
232
+ ${colors.green('start')} Start the server in background
233
+ ${colors.green('stop')} Stop the server
234
+ ${colors.green('restart')} Restart the server
235
+ ${colors.green('status')} Show server status
236
+ ${colors.green('logs')} Show recent logs
237
+ ${colors.green('logs -f')} Follow logs in real-time
238
+ ${colors.green('setup-password')} Set up admin password
239
+ ${colors.green('init')} Create default config.json
240
+ ${colors.green('version')} Show version
241
+ ${colors.green('help')} Show this help message
242
+
243
+ ${colors.yellow('Examples:')}
244
+ tcpmapping start # Start server
245
+ tcpmapping status # Check if server is running
246
+ tcpmapping logs -f # Follow logs
247
+
248
+ ${colors.yellow('WebUI:')}
249
+ After starting, visit http://localhost:9999
250
+ `);
251
+ }
252
+
253
+ // 执行命令
254
+ switch (command) {
255
+ case 'start':
256
+ start();
257
+ break;
258
+ case 'stop':
259
+ stop();
260
+ break;
261
+ case 'restart':
262
+ restart();
263
+ break;
264
+ case 'status':
265
+ status();
266
+ break;
267
+ case 'logs':
268
+ logs(args[1] === '-f');
269
+ break;
270
+ case 'setup-password':
271
+ case 'passwd':
272
+ setupPassword();
273
+ break;
274
+ case 'init':
275
+ init();
276
+ break;
277
+ case 'version':
278
+ case '-v':
279
+ case '--version':
280
+ version();
281
+ break;
282
+ case 'help':
283
+ case '-h':
284
+ case '--help':
285
+ default:
286
+ help();
287
+ break;
288
+ }
package/config.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "mappings": [
3
+ {
4
+ "name": "Dify",
5
+ "listen": {
6
+ "host": "0.0.0.0",
7
+ "port": 5588
8
+ },
9
+ "target": {
10
+ "host": "113.45.34.202",
11
+ "port": 5588
12
+ }
13
+ },
14
+ {
15
+ "name": "语音助手",
16
+ "listen": {
17
+ "host": "0.0.0.0",
18
+ "port": 3443
19
+ },
20
+ "target": {
21
+ "host": "115.120.49.208",
22
+ "port": 443
23
+ }
24
+ },
25
+ {
26
+ "name": "语音助手",
27
+ "listen": {
28
+ "host": "0.0.0.0",
29
+ "port": 443
30
+ },
31
+ "target": {
32
+ "host": "115.120.49.208",
33
+ "port": 443
34
+ }
35
+ }
36
+ ],
37
+ "webui": {
38
+ "enabled": true,
39
+ "port": 9999,
40
+ "host": "0.0.0.0"
41
+ },
42
+ "logging": {
43
+ "enabled": true,
44
+ "level": "info"
45
+ }
46
+ }
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@chenpu17/tcpmapping",
3
+ "version": "2.0.0",
4
+ "description": "TCP端口转发服务器,支持多端口映射、WebUI管理界面和实时连接监控",
5
+ "main": "server.js",
6
+ "bin": {
7
+ "tcpmapping": "./bin/tcpmapping.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node server.js",
11
+ "dev": "node server.js",
12
+ "setup-password": "node setup-password.js",
13
+ "reset-password": "node setup-password.js"
14
+ },
15
+ "files": [
16
+ "bin/",
17
+ "public/",
18
+ "server.js",
19
+ "setup-password.js",
20
+ "config.json"
21
+ ],
22
+ "keywords": [
23
+ "tcp",
24
+ "proxy",
25
+ "forward",
26
+ "port-forward",
27
+ "port-mapping",
28
+ "server",
29
+ "webui",
30
+ "cli",
31
+ "nodejs"
32
+ ],
33
+ "author": "chenpu17",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/chenpu17/TcpMapping.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/chenpu17/TcpMapping/issues"
41
+ },
42
+ "homepage": "https://github.com/chenpu17/TcpMapping#readme",
43
+ "engines": {
44
+ "node": ">=14.0.0"
45
+ },
46
+ "dependencies": {
47
+ "express": "^4.18.2",
48
+ "express-session": "^1.17.3",
49
+ "bcryptjs": "^2.4.3",
50
+ "body-parser": "^1.20.2"
51
+ }
52
+ }