-
Notifications
You must be signed in to change notification settings - Fork 14
/
potatoServer.js
202 lines (179 loc) · 7.33 KB
/
potatoServer.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
'use strict'
const net = require('net');
const tls = require('tls');
const crypto = require('crypto');
const fs = require('fs');
const domain = require('domain');
const PotatoLib = require('./lib/potato');
const Obfs = require('./lib/obfs');
//log4js module
var log4js = require('log4js');
var logConfig = require('./logConfig.json');
log4js.configure(logConfig);
var logger = log4js.getLogger('server');
//读取配置文件
var config = require('./config.json');
var
algorithm = 'aes-256-cfb',
password = '';
//设定加密算法和密码
if (config.algorithm != null)
algorithm = config.algorithm;
if (config.password != null)
password = config.password;
var Potato = new PotatoLib(algorithm, password);
var EncryptStream = Potato.EncryptStream;
var DecryptStream = Potato.DecryptStream;
var server_port = 1999;
if (config.server_port != null)
server_port = config.server_port;
//命令行参数优先级大于配置文件
if (process.argv.length == 3) {
server_port = +process.argv[2];
}
//定义tls方式链接的参数
var ciphers = [
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-AES256-GCM-SHA384']
.join(':');
var options = {};
if (config.method === 'https') {
options = {
key: fs.readFileSync('./cert/server.key'),
cert: fs.readFileSync('./cert/server.crt'),
ciphers: ciphers,
passphrase: password,
secureProtocol: 'TLSv1_2_method',
honorCipherOrder: true,
rejectUnauthorized: true
}
}
//创建服务器
var potatoServer;
if (config.method === 'https') {
var tlsSessionStore = {};
potatoServer = tls.createServer(options);//建立tls服务器开始监听
//新建会话时保存会话,不过测试下来没什么卵用
potatoServer.on('newSession', (id, data, cb) => {
tlsSessionStore[id] = data;
logger.trace('新会话连接,id: %s\r\n', id);
cb();
});
//回复会话
potatoServer.on('resumeSession', (id, cb) => {
cb(null, tlsSessionStore[id] || null);
logger.trace('回复会话,id: %s\r\n', id);
});
potatoServer.on('secureConnection', (potatoClient) => {
onConnect(potatoClient, false)
});
}
else {
potatoServer = net.createServer(options);
potatoServer.on('connection', (potatoClient) => {
onConnect(potatoClient, true)
});
}
potatoServer.listen(server_port, () => {
logger.info('listening on ' + server_port);
});
process.on('uncaughtException', function (err) {
logger.error("捕获未处理的错误: " + err.message);
logger.error(err);
});
function onConnect(potatoClient, needCipher) {
var potatoAddr = potatoClient.remoteAddress;
var potatoPort = potatoClient.remotePort;
logger.trace('客户端连进来了: %s:%d\r\n', potatoAddr, potatoPort);
potatoClient.once('data', (data) => {
var sig;//返回信号
var errSig = false;//错误标志
var reqSymbol = Potato.SymbolRequest.Resolve(data); //解析请求头
if (reqSymbol === null) {//连接信令错误,有可能是GFW的探测链接
logger.error('请求信令错误!来自:%s:%d', potatoAddr, potatoPort);
//sig = Potato.SymbolPeply.Create(Potato.ReplyCode.COMMAND_NOT_SUPPORTED);//创建一个错误信号
//potatoClient.write(sig);//返回错误信号
//potatoClient.end();
//potatoClient.destroy();
//return;
reqSymbol = {};
reqSymbol.dst.addr = 'www.aliyun.com';
reqSymbol.dst.port = 443;
errSig = true;
}
else {
logger.trace('want to connect %s:%d\r\n', reqSymbol.dst.addr, reqSymbol.dst.port);
}
var d = domain.create();//用来捕捉错误信号的域
d.run(() => {
//尝试连接目标地址
var proxySocket = net.connect(reqSymbol.dst.port, reqSymbol.dst.addr);
//如果连上了
proxySocket.on('connect', function () {
logger.trace('connected %s:%d\r\n', this.remoteAddress, this.remotePort);
sig = Potato.SymbolPeply.Create(Potato.ReplyCode.SUCCEEDED);//创建一个成功信号
potatoClient.write(sig);//如果连上了就发送成功信号
if (errSig) {
this.pipe(potatoClient);
return;
}
if (needCipher) {
var cipher = new Potato.EncryptStream(),
decipher = new Potato.DecryptStream();
var obfs = new Obfs.ObfsResponse(),
deobfs = new Obfs.ObfsResolve();
potatoClient
.pipe(deobfs)//将potato客户端的数据反混淆
.pipe(decipher)//将potato客户端的数据解密
.pipe(this)//传给目标服务器
.pipe(cipher)//将目标服务器返回的数据加密
.pipe(obfs)//将加密后的数据混淆
.pipe(potatoClient);//传给potato客户端
}
else {
potatoClient
.pipe(this)//将potato客户端的数据传给目标服务器
.pipe(potatoClient);//将目标服务器返回的数据传给potato客户端
}
});
proxySocket.on('error', (err) => {
switch (err.code) {
case 'ENOTFOUND':
logger.info('找不到域名: %s', reqSymbol.addr);
sig = Potato.SymbolPeply.Create(Potato.ReplyCode.HOST_UNREACHABLE);
potatoClient.write(sig);
break;
case 'ECONNREFUSED':
logger.info('连接被拒绝: %s:%d', reqSymbol.addr, reqSymbol.port);
sig = Potato.SymbolPeply.Create(Potato.ReplyCode.CONNECTION_REFUSED);
potatoClient.write(sig);
break;
case 'ETIMEDOUT':
logger.info('连接超时: %s:%d', reqSymbol.addr, reqSymbol.port);
sig = Potato.SymbolPeply.Create(Potato.ReplyCode.NETWORK_UNREACHABLE);
if (potatoClient.writable)
potatoClient.write(sig);
break;
case 'ECONNRESET':
default:
logger.error("远程服务器连接错误: %s:%d", reqSymbol.dst.addr, reqSymbol.dst.port);
logger.error(err.code + '\t' + err.message);
proxySocket.end();//断开远程服务器的连接
potatoClient.end();//断开和potato客户端的连接
break;
}
});
});
//捕捉域里的错误
d.on('error', (err) => {
logger.error('域里未处理的错误:' + err.message + err.stack);
sig = Potato.SymbolPeply.Create(Potato.ReplyCode.GENERAL_FAILURE);
if (potatoClient.writable)
potatoClient.write(sig);
});
});
potatoClient.on('error', (err) => {
logger.error("potato客户端错误: %s:%d ", potatoAddr, potatoPort, err);
logger.error('potato客户端可能已经退出或崩溃。\r\n');
})
}