Skip to content

Commit b834d4a

Browse files
committed
better detection of dead connection
added ability for proxy to limit destination hosts + host resolve to ip at client level
1 parent 1781248 commit b834d4a

File tree

8 files changed

+102
-36
lines changed

8 files changed

+102
-36
lines changed

AutoTunnel.Proxy.Node/proxy.js

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
const dgram = require('dgram');
2+
const dns = require('dns');
23

34
var logFunc = console.log;
5+
var checkFunc = function () {
6+
return true;
7+
};
48

59
var start = function (portNumber) {
610
var server = dgram.createSocket('udp4');
@@ -28,25 +32,40 @@ var start = function (portNumber) {
2832
var spl = dstHostAndPort.split(':');
2933
var dstHost = spl[0];
3034
var dstPort = (spl[1] || 12017) * 1;
31-
var socket = dgram.createSocket('udp4');
32-
socket.on('message', function (bmsg, bep) {
33-
var pair = proxyPairs[ep.address + ':' + ep.port];
34-
if (pair) {
35-
pair.lastActivity = new Date().getTime();
36-
server.send(bmsg, 0, bep.size, ep.port, ep.address);
35+
36+
dns.lookup(dstHost, 4, function (err, addr) {
37+
if (err !== null) {
38+
logFunc('Cannot resolve host ' + dstHost, err);
39+
return;
40+
}
41+
42+
if (!checkFunc(addr, dstHost)) {
43+
logFunc('Host ' + dstHost + " was considered as invalid for proxyfying");
44+
return
3745
}
46+
47+
dstHost = addr;
48+
49+
var socket = dgram.createSocket('udp4');
50+
socket.on('message', function (bmsg, bep) {
51+
var pair = proxyPairs[ep.address + ':' + ep.port];
52+
if (pair) {
53+
pair.lastActivity = new Date().getTime();
54+
server.send(bmsg, 0, bep.size, ep.port, ep.address);
55+
}
56+
});
57+
proxyPairs[ep.address + ':' + ep.port] = {
58+
sourceHost: ep.address,
59+
sourcePort: ep.port,
60+
host: dstHost,
61+
port: dstPort,
62+
targetSocket: socket,
63+
lastActivity: new Date().getTime()
64+
};
65+
logFunc('Estabilished tunnel ', ep.address + ':' + ep.port + '->' + dstHost + ':' + dstPort);
66+
67+
// TODO: think about answer
3868
});
39-
proxyPairs[ep.address + ':' + ep.port] = {
40-
sourceHost: ep.address,
41-
sourcePort: ep.port,
42-
host: dstHost,
43-
port: dstPort,
44-
targetSocket: socket,
45-
lastActivity: new Date().getTime()
46-
};
47-
logFunc('Estabilished tunnel ', ep.address + ':' + ep.port + '->' + dstHost + ':' + dstPort);
48-
49-
// TODO: think about answer
5069
} else {
5170
var pair = proxyPairs[ep.address + ':' + ep.port];
5271

@@ -97,5 +116,8 @@ module.exports = {
97116
},
98117
setLogger: function (loggerFunc) {
99118
logFunc = loggerFunc;
119+
},
120+
setAllowedTargetIpCheckFunc: function(checkingFunc) {
121+
checkFunc = checkingFunc;
100122
}
101123
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
var p = require('./proxy.js');
22

3+
p.setAllowedTargetIpCheckFunc(function (dstAddr, dstHost) {
4+
// just for example
5+
console.log(dstAddr)
6+
return /192\.168\.\d+\.\d+/.test(dstAddr);
7+
});
8+
39
p.start(12018);

AutoTunnel/ClientSender.cs

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ public ClientSender(RemoteServerConfig config, TunnelStorage storage)
4343
LogHelper.Log.WriteLine("Tunnel watcher was created for " + config.TunnelHost);
4444

4545
Task.Factory.StartNew(ReceiveCycle);
46-
if (config.KeepAlive)
47-
Task.Factory.StartNew(PingCycle);
46+
Task.Factory.StartNew(PingCycle);
4847
if (config.ConnectOnStart)
4948
Init();
5049
IPAddress dummy;
@@ -77,7 +76,6 @@ private void CheckHostChange()
7776

7877
private DateTime _lastInitRequest;
7978

80-
8179
private void Init()
8280
{
8381
_lastInitRequest = DateTime.UtcNow;
@@ -111,8 +109,8 @@ private void InitInternal()
111109

112110
_connectEP = destEP;
113111

114-
Storage.AddSession(new byte[16], destEP).IsClientSession = true;
115112
Storage.IncrementEstabilishing();
113+
Storage.AddSession(new byte[16], destEP).IsClientSession = true;
116114

117115
if (proxyEP != null)
118116
LogHelper.Log.WriteLine("Initializing connection to " + _config.ConnectHost + " via proxy " + proxyEP);
@@ -179,13 +177,15 @@ private void InitInternal()
179177
if (recLength < 4 || _receiveBuffer[0] != (byte)StateFlags.ConnectAnswer)
180178
{
181179
Console.Error.WriteLine("Invalid server response");
180+
Storage.RemoveSession(destEP);
182181
return;
183182
}
184183

185184
var decLen = decryptHelper.Decrypt(_receiveBuffer, 4);
186185
if (decLen < 9)
187186
{
188187
Console.Error.WriteLine("Invalid server response");
188+
Storage.RemoveSession(destEP);
189189
return;
190190
}
191191

@@ -207,9 +207,27 @@ private void InitInternal()
207207

208208
private void PingCycle()
209209
{
210+
DateTime lastReceiveLast = DateTime.MinValue;
210211
while (!_disposed)
211212
{
212-
if (_isInited) _socket.Send(new byte[] { (byte)StateFlags.Ping, 0, 0, 0 }, 4, SocketFlags.None);
213+
if (_isInited)
214+
{
215+
// problem with server? no answers, dropping connection
216+
if (Session.LastActivity == lastReceiveLast)
217+
{
218+
_isInited = false;
219+
lastReceiveLast = DateTime.MinValue;
220+
if (_config.KeepAlive)
221+
Init();
222+
}
223+
224+
if (_config.KeepAlive || _lastSend.Subtract(Session.LastActivity).TotalSeconds > _config.PingInterval)
225+
{
226+
lastReceiveLast = Session.LastActivity;
227+
_socket.Send(new byte[] { (byte)StateFlags.Ping, 0, 0, 0 }, 4, SocketFlags.None);
228+
_lastSend = DateTime.UtcNow;
229+
}
230+
}
213231
else
214232
{
215233
// force renew connection attepmt
@@ -233,12 +251,15 @@ protected override void Send(byte[] packet, int packetLen)
233251
{
234252
var lenToSend = _encryptHelper.Encrypt(packet, packetLen);
235253
var packetToSend = _encryptHelper.InnerBuf;
254+
_lastSend = DateTime.UtcNow;
236255
_socket.Send(packetToSend, lenToSend, SocketFlags.None);
237256
}
238257
}
239258

240259
private readonly byte[] _receiveBuffer = new byte[65536];
241260

261+
private DateTime _lastSend;
262+
242263
private void ReceiveCycle()
243264
{
244265
byte[] buf = _receiveBuffer;
@@ -257,18 +278,20 @@ private void ReceiveCycle()
257278
}
258279
catch (Exception ex)
259280
{
260-
LogHelper.Log.WriteLine("Receive data error");
261-
_isInited = false;
262-
// LogHelper.Log.WriteLine(ex);
263-
if (_socket != null)
281+
if (_isIniting == 1 && _isInited)
264282
{
265-
_socket.Dispose();
266-
_socket = null;
283+
LogHelper.Log.WriteLine("Receive data error");
284+
_isInited = false;
285+
// LogHelper.Log.WriteLine(ex);
286+
if (_socket != null)
287+
{
288+
_socket.Dispose();
289+
_socket = null;
290+
}
291+
292+
if (_config.KeepAlive) Init();
267293
}
268294

269-
if (_config.KeepAlive)
270-
Init();
271-
272295
Thread.Sleep(1000);
273296
continue;
274297
}
@@ -277,7 +300,7 @@ private void ReceiveCycle()
277300
if (len % 16 != 0)
278301
{
279302
// in any case, this is error
280-
// if (buf[0] == 0x3)
303+
if (buf[0] != (byte)StateFlags.Pong)
281304
{
282305
LogHelper.Log.WriteLine("Received an error flag from " + _socket.RemoteEndPoint);
283306
_isInited = false;
@@ -287,6 +310,8 @@ private void ReceiveCycle()
287310
}
288311
}
289312

313+
Session.UpdateLastActivity();
314+
290315
var decryptHelper = Session.Decryptor;
291316
var decLen = decryptHelper.Decrypt(buf, 0);
292317
_packetWriter.Write(decryptHelper.InnerBuf, decLen);

AutoTunnel/Config/MainConfig.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,9 @@ public class MainConfig
2727
public int IdleSessionTime { get; set; }
2828

2929
public string LogFileName { get; set; }
30+
31+
[DefaultValue(15)]
32+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
33+
public int PingBackTime { get; set; }
3034
}
3135
}

AutoTunnel/Encryption/DecryptHelper.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ public int Decrypt(byte[] data, int offset)
3434
decryptor.TransformBlock(data, offset, 16, _headerBuf, 0);
3535
var len = _headerBuf[0] | (_headerBuf[1] << 8) | (_headerBuf[2] << 16) | (_headerBuf[3] << 24);
3636
if (len > data.Length) return -1;
37-
if (_headerBuf[4] != 1 && _headerBuf[5] != 0 && _headerBuf[6] != 'A' && _headerBuf[7] != 'T') return -1;
37+
if (_headerBuf[4] != 1 || _headerBuf[5] != 0 || _headerBuf[6] != 'A' || _headerBuf[7] != 'T') return -1;
3838
var len16 = (len + 15) & ~15;
39+
if (len < 0 || len > _innerBuf.Length) return -1;
3940
decryptor.TransformBlock(data, offset + 16, len16, _innerBuf, 0);
4041
return len;
4142
}

AutoTunnel/Encryption/ServerHandshake.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public ServerHandshake()
1313

1414
public byte[] GetOutPacket(byte[] inPacket, int len)
1515
{
16-
if (inPacket[0] != 1 && inPacket[1] != 0 && inPacket[2] != 'A' && inPacket[3] != 'T') return null;
16+
if (inPacket[0] != 1 || inPacket[1] != 0 || inPacket[2] != 'A' || inPacket[3] != 'T') return null;
1717
var publicRsa = Encoding.UTF8.GetString(inPacket, 4, inPacket.Length - 4);
1818
SessionKey = new byte[16];
1919
using (var random = RandomNumberGenerator.Create())

AutoTunnel/Listener.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ private void CleanupThread()
4949
_storage.RemoveSession(os);
5050
}
5151

52-
_stopEvent.WaitOne(10 * 60 * 1000);
52+
_stopEvent.WaitOne(_config.IdleSessionTime * 1000);
5353
}
5454
}
5555

@@ -124,6 +124,7 @@ private void StartInternal()
124124
{
125125
session = _storage.GetSession(ep);
126126
if (session != null) session.UpdateLastActivity();
127+
s.SendTo(new byte[] { (byte)StateFlags.Pong, 0, 0, 0 }, 4, SocketFlags.None, ep);
127128
continue;
128129
}
129130
else

AutoTunnel/StateFlags.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@
33
public enum StateFlags : byte
44
{
55
Connecting = 1,
6+
67
ConnectAnswer = 2,
8+
79
ErrorFromServer = 3,
10+
811
Ping = 5,
12+
913
ProxyConnecting = 7,
10-
ErrorFromProxy = 8
14+
15+
ErrorFromProxy = 8,
16+
17+
Pong = 9
1118
}
1219
}

0 commit comments

Comments
 (0)