Skip to content

Commit

Permalink
better detection of dead connection
Browse files Browse the repository at this point in the history
added ability for proxy to limit destination hosts + host resolve to ip at client level
  • Loading branch information
force-net committed Sep 4, 2017
1 parent 1781248 commit b834d4a
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 36 deletions.
56 changes: 39 additions & 17 deletions AutoTunnel.Proxy.Node/proxy.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
const dgram = require('dgram');
const dns = require('dns');

var logFunc = console.log;
var checkFunc = function () {
return true;
};

var start = function (portNumber) {
var server = dgram.createSocket('udp4');
Expand Down Expand Up @@ -28,25 +32,40 @@ var start = function (portNumber) {
var spl = dstHostAndPort.split(':');
var dstHost = spl[0];
var dstPort = (spl[1] || 12017) * 1;
var socket = dgram.createSocket('udp4');
socket.on('message', function (bmsg, bep) {
var pair = proxyPairs[ep.address + ':' + ep.port];
if (pair) {
pair.lastActivity = new Date().getTime();
server.send(bmsg, 0, bep.size, ep.port, ep.address);

dns.lookup(dstHost, 4, function (err, addr) {
if (err !== null) {
logFunc('Cannot resolve host ' + dstHost, err);
return;
}

if (!checkFunc(addr, dstHost)) {
logFunc('Host ' + dstHost + " was considered as invalid for proxyfying");
return
}

dstHost = addr;

var socket = dgram.createSocket('udp4');
socket.on('message', function (bmsg, bep) {
var pair = proxyPairs[ep.address + ':' + ep.port];
if (pair) {
pair.lastActivity = new Date().getTime();
server.send(bmsg, 0, bep.size, ep.port, ep.address);
}
});
proxyPairs[ep.address + ':' + ep.port] = {
sourceHost: ep.address,
sourcePort: ep.port,
host: dstHost,
port: dstPort,
targetSocket: socket,
lastActivity: new Date().getTime()
};
logFunc('Estabilished tunnel ', ep.address + ':' + ep.port + '->' + dstHost + ':' + dstPort);

// TODO: think about answer
});
proxyPairs[ep.address + ':' + ep.port] = {
sourceHost: ep.address,
sourcePort: ep.port,
host: dstHost,
port: dstPort,
targetSocket: socket,
lastActivity: new Date().getTime()
};
logFunc('Estabilished tunnel ', ep.address + ':' + ep.port + '->' + dstHost + ':' + dstPort);

// TODO: think about answer
} else {
var pair = proxyPairs[ep.address + ':' + ep.port];

Expand Down Expand Up @@ -97,5 +116,8 @@ module.exports = {
},
setLogger: function (loggerFunc) {
logFunc = loggerFunc;
},
setAllowedTargetIpCheckFunc: function(checkingFunc) {
checkFunc = checkingFunc;
}
};
6 changes: 6 additions & 0 deletions AutoTunnel.Proxy.Node/proxyStarter.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
var p = require('./proxy.js');

p.setAllowedTargetIpCheckFunc(function (dstAddr, dstHost) {
// just for example
console.log(dstAddr)
return /192\.168\.\d+\.\d+/.test(dstAddr);
});

p.start(12018);
55 changes: 40 additions & 15 deletions AutoTunnel/ClientSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ public ClientSender(RemoteServerConfig config, TunnelStorage storage)
LogHelper.Log.WriteLine("Tunnel watcher was created for " + config.TunnelHost);

Task.Factory.StartNew(ReceiveCycle);
if (config.KeepAlive)
Task.Factory.StartNew(PingCycle);
Task.Factory.StartNew(PingCycle);
if (config.ConnectOnStart)
Init();
IPAddress dummy;
Expand Down Expand Up @@ -77,7 +76,6 @@ private void CheckHostChange()

private DateTime _lastInitRequest;


private void Init()
{
_lastInitRequest = DateTime.UtcNow;
Expand Down Expand Up @@ -111,8 +109,8 @@ private void InitInternal()

_connectEP = destEP;

Storage.AddSession(new byte[16], destEP).IsClientSession = true;
Storage.IncrementEstabilishing();
Storage.AddSession(new byte[16], destEP).IsClientSession = true;

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

var decLen = decryptHelper.Decrypt(_receiveBuffer, 4);
if (decLen < 9)
{
Console.Error.WriteLine("Invalid server response");
Storage.RemoveSession(destEP);
return;
}

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

private void PingCycle()
{
DateTime lastReceiveLast = DateTime.MinValue;
while (!_disposed)
{
if (_isInited) _socket.Send(new byte[] { (byte)StateFlags.Ping, 0, 0, 0 }, 4, SocketFlags.None);
if (_isInited)
{
// problem with server? no answers, dropping connection
if (Session.LastActivity == lastReceiveLast)
{
_isInited = false;
lastReceiveLast = DateTime.MinValue;
if (_config.KeepAlive)
Init();
}

if (_config.KeepAlive || _lastSend.Subtract(Session.LastActivity).TotalSeconds > _config.PingInterval)
{
lastReceiveLast = Session.LastActivity;
_socket.Send(new byte[] { (byte)StateFlags.Ping, 0, 0, 0 }, 4, SocketFlags.None);
_lastSend = DateTime.UtcNow;
}
}
else
{
// force renew connection attepmt
Expand All @@ -233,12 +251,15 @@ protected override void Send(byte[] packet, int packetLen)
{
var lenToSend = _encryptHelper.Encrypt(packet, packetLen);
var packetToSend = _encryptHelper.InnerBuf;
_lastSend = DateTime.UtcNow;
_socket.Send(packetToSend, lenToSend, SocketFlags.None);
}
}

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

private DateTime _lastSend;

private void ReceiveCycle()
{
byte[] buf = _receiveBuffer;
Expand All @@ -257,18 +278,20 @@ private void ReceiveCycle()
}
catch (Exception ex)
{
LogHelper.Log.WriteLine("Receive data error");
_isInited = false;
// LogHelper.Log.WriteLine(ex);
if (_socket != null)
if (_isIniting == 1 && _isInited)
{
_socket.Dispose();
_socket = null;
LogHelper.Log.WriteLine("Receive data error");
_isInited = false;
// LogHelper.Log.WriteLine(ex);
if (_socket != null)
{
_socket.Dispose();
_socket = null;
}

if (_config.KeepAlive) Init();
}

if (_config.KeepAlive)
Init();

Thread.Sleep(1000);
continue;
}
Expand All @@ -277,7 +300,7 @@ private void ReceiveCycle()
if (len % 16 != 0)
{
// in any case, this is error
// if (buf[0] == 0x3)
if (buf[0] != (byte)StateFlags.Pong)
{
LogHelper.Log.WriteLine("Received an error flag from " + _socket.RemoteEndPoint);
_isInited = false;
Expand All @@ -287,6 +310,8 @@ private void ReceiveCycle()
}
}

Session.UpdateLastActivity();

var decryptHelper = Session.Decryptor;
var decLen = decryptHelper.Decrypt(buf, 0);
_packetWriter.Write(decryptHelper.InnerBuf, decLen);
Expand Down
4 changes: 4 additions & 0 deletions AutoTunnel/Config/MainConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,9 @@ public class MainConfig
public int IdleSessionTime { get; set; }

public string LogFileName { get; set; }

[DefaultValue(15)]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public int PingBackTime { get; set; }
}
}
3 changes: 2 additions & 1 deletion AutoTunnel/Encryption/DecryptHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ public int Decrypt(byte[] data, int offset)
decryptor.TransformBlock(data, offset, 16, _headerBuf, 0);
var len = _headerBuf[0] | (_headerBuf[1] << 8) | (_headerBuf[2] << 16) | (_headerBuf[3] << 24);
if (len > data.Length) return -1;
if (_headerBuf[4] != 1 && _headerBuf[5] != 0 && _headerBuf[6] != 'A' && _headerBuf[7] != 'T') return -1;
if (_headerBuf[4] != 1 || _headerBuf[5] != 0 || _headerBuf[6] != 'A' || _headerBuf[7] != 'T') return -1;
var len16 = (len + 15) & ~15;
if (len < 0 || len > _innerBuf.Length) return -1;
decryptor.TransformBlock(data, offset + 16, len16, _innerBuf, 0);
return len;
}
Expand Down
2 changes: 1 addition & 1 deletion AutoTunnel/Encryption/ServerHandshake.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public ServerHandshake()

public byte[] GetOutPacket(byte[] inPacket, int len)
{
if (inPacket[0] != 1 && inPacket[1] != 0 && inPacket[2] != 'A' && inPacket[3] != 'T') return null;
if (inPacket[0] != 1 || inPacket[1] != 0 || inPacket[2] != 'A' || inPacket[3] != 'T') return null;
var publicRsa = Encoding.UTF8.GetString(inPacket, 4, inPacket.Length - 4);
SessionKey = new byte[16];
using (var random = RandomNumberGenerator.Create())
Expand Down
3 changes: 2 additions & 1 deletion AutoTunnel/Listener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private void CleanupThread()
_storage.RemoveSession(os);
}

_stopEvent.WaitOne(10 * 60 * 1000);
_stopEvent.WaitOne(_config.IdleSessionTime * 1000);
}
}

Expand Down Expand Up @@ -124,6 +124,7 @@ private void StartInternal()
{
session = _storage.GetSession(ep);
if (session != null) session.UpdateLastActivity();
s.SendTo(new byte[] { (byte)StateFlags.Pong, 0, 0, 0 }, 4, SocketFlags.None, ep);
continue;
}
else
Expand Down
9 changes: 8 additions & 1 deletion AutoTunnel/StateFlags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
public enum StateFlags : byte
{
Connecting = 1,

ConnectAnswer = 2,

ErrorFromServer = 3,

Ping = 5,

ProxyConnecting = 7,
ErrorFromProxy = 8

ErrorFromProxy = 8,

Pong = 9
}
}

0 comments on commit b834d4a

Please sign in to comment.