Skip to content

Commit

Permalink
config auto reload, bug fixes and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
force-net committed Sep 4, 2017
1 parent b834d4a commit 8b7f3ee
Show file tree
Hide file tree
Showing 16 changed files with 432 additions and 156 deletions.
2 changes: 2 additions & 0 deletions AutoTunnel/AutoTunnel.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Compile Include="ClientSender.cs" />
<Compile Include="Config\ConfigHelper.cs" />
<Compile Include="Config\RemoteClientConfig.cs" />
<Compile Include="Config\RemoteServerConfig.cs" />
<Compile Include="Config\MainConfig.cs" />
Expand Down Expand Up @@ -102,6 +103,7 @@
<Compile Include="Service\MainServiceInstallHelper.cs" />
<Compile Include="Starter.cs" />
<Compile Include="StateFlags.cs" />
<Compile Include="TunnelSession.cs" />
<Compile Include="TunnelStorage.cs" />
<Compile Include="WinDivert.cs" />
</ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions AutoTunnel/BaseSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ public abstract class BaseSender : IDisposable

protected readonly TunnelStorage Storage;

public TunnelStorage.Session Session { get; set; }
public TunnelSession Session { get; set; }

protected BaseSender(TunnelStorage.Session session, IPAddress watchAddr, TunnelStorage storage)
protected BaseSender(TunnelSession session, IPAddress watchAddr, TunnelStorage storage)
{
Storage = storage;
Session = session;
Expand Down
65 changes: 36 additions & 29 deletions AutoTunnel/ClientSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ private void Init()
Task.Factory.StartNew(InitInternal);
}

private void CloseSocket()
{
if (_socket != null)
{
_socket.Dispose();
}

_socket = null;
}

private void InitInternal()
{
if (Interlocked.CompareExchange(ref _isIniting, 1, 0) == 1)
Expand Down Expand Up @@ -126,8 +136,7 @@ private void InitInternal()
var recLength = 0;

// killing old socket
if (_socket != null)
_socket.Dispose();
CloseSocket();
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_socket.Connect(destEP);

Expand Down Expand Up @@ -170,7 +179,7 @@ private void InitInternal()
LogHelper.Log.WriteLine("No response from server " + destEP);
if (DateTime.UtcNow.Subtract(_lastInitRequest).TotalSeconds > 60)
{
LogHelper.Log.WriteLine("Stopping connect atteptions to " + destEP + " until another request will occure");
LogHelper.Log.WriteLine("Stopping connect atteptions to " + destEP + " until another request will occur");
}
}

Expand Down Expand Up @@ -205,36 +214,42 @@ private void InitInternal()
}
}

private void DropInit()
{
_isInited = false;
if (_config.KeepAlive)
Init();
}

private void PingCycle()
{
DateTime lastReceiveLast = DateTime.MinValue;
DateTime lastPingDate = DateTime.MinValue;
var pingSpan = TimeSpan.FromSeconds(_config.PingInterval);

while (!_disposed)
{
if (_isInited)
{
// problem with server? no answers, dropping connection
if (Session.LastActivity == lastReceiveLast)
if (Session.SendReceiveDifference > TimeSpan.FromSeconds(_config.PingInterval * 2))
{
_isInited = false;
lastReceiveLast = DateTime.MinValue;
if (_config.KeepAlive)
Init();
DropInit();
}

if (_config.KeepAlive || _lastSend.Subtract(Session.LastActivity).TotalSeconds > _config.PingInterval)
if ((_config.KeepAlive && DateTime.UtcNow.Subtract(lastPingDate) > pingSpan) || Session.SendReceiveDifference > pingSpan)
{
lastReceiveLast = Session.LastActivity;
_socket.Send(new byte[] { (byte)StateFlags.Ping, 0, 0, 0 }, 4, SocketFlags.None);
_lastSend = DateTime.UtcNow;
lastPingDate = DateTime.UtcNow;
}
}
else
{
// force renew connection attepmt
_lastInitRequest = DateTime.UtcNow;
// force renew connection attempt
if (_config.KeepAlive)
_lastInitRequest = DateTime.UtcNow;
}

Thread.Sleep(_config.PingInterval * 1000);
Thread.Sleep(1000);
}
}

Expand All @@ -251,15 +266,13 @@ protected override void Send(byte[] packet, int packetLen)
{
var lenToSend = _encryptHelper.Encrypt(packet, packetLen);
var packetToSend = _encryptHelper.InnerBuf;
_lastSend = DateTime.UtcNow;
Session.UpdateReceiveActivity();
_socket.Send(packetToSend, lenToSend, SocketFlags.None);
}
}

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

private DateTime _lastSend;

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

if (_config.KeepAlive) Init();
}
Expand All @@ -303,14 +312,12 @@ private void ReceiveCycle()
if (buf[0] != (byte)StateFlags.Pong)
{
LogHelper.Log.WriteLine("Received an error flag from " + _socket.RemoteEndPoint);
_isInited = false;
// failed data
Init();
DropInit();
continue;
}
}

Session.UpdateLastActivity();
Session.UpdateReceiveActivity();

var decryptHelper = Session.Decryptor;
var decLen = decryptHelper.Decrypt(buf, 0);
Expand All @@ -323,7 +330,7 @@ public override void Dispose()
base.Dispose();
_disposed = true;
_initingEvent.Set();
_socket.Dispose();
CloseSocket();
}
}
}
124 changes: 124 additions & 0 deletions AutoTunnel/Config/ConfigHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

using Force.AutoTunnel.Logging;

using Newtonsoft.Json;

namespace Force.AutoTunnel.Config
{
public static class ConfigHelper
{
public static MainConfig Config { get; private set; }

private static FileSystemWatcher _fsw;

public static bool LoadConfig(bool isFirstTime)
{
try
{
if (_fsw != null)
{
_fsw.Dispose();
_fsw = null;
}

if (!isFirstTime)
LogHelper.Log.WriteLine("Reloading config");

var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.json");
if (!File.Exists(configPath))
{
if (isFirstTime)
Console.Error.WriteLine("Missing config file");
else
LogHelper.Log.WriteLine("Missing config file");

return false;
}

MainConfig config;
using (var f = File.OpenRead(configPath))
config = new JsonSerializer().Deserialize<MainConfig>(new JsonTextReader(new StreamReader(f)));

if (config.RemoteClients == null)
config.RemoteClients = new RemoteClientConfig[0];
if (config.RemoteClients.Length == 0)
config.EnableListening = false;
if (config.RemoteServers == null)
config.RemoteServers = new RemoteServerConfig[0];
foreach (var remoteServerConfig in config.RemoteServers)
{
if (string.IsNullOrEmpty(remoteServerConfig.ConnectHost) && string.IsNullOrEmpty(remoteServerConfig.TunnelHost))
throw new InvalidOperationException("Missing host info in config");

if (string.IsNullOrEmpty(remoteServerConfig.TunnelHost))
remoteServerConfig.TunnelHost = remoteServerConfig.ConnectHost;
if (string.IsNullOrEmpty(remoteServerConfig.ConnectHost))
remoteServerConfig.ConnectHost = remoteServerConfig.TunnelHost;
}

if (!isFirstTime)
Starter.Stop();

var log = new AggregateLog();
if (Environment.UserInteractive) log.AddLog(new ConsoleLog());
if (!string.IsNullOrEmpty(config.LogFileName)) log.AddLog(new FileLog(config.LogFileName));
LogHelper.SetLog(log);

Config = config;

if (!isFirstTime)
Starter.Start();

if (config.AutoReloadOnChange)
{
_fsw = new FileSystemWatcher(Path.GetDirectoryName(configPath) ?? string.Empty, Path.GetFileName(configPath) ?? string.Empty);
_fsw.Changed += FswOnChanged;
_fsw.Created += FswOnChanged;
_fsw.Deleted += FswOnChanged;
_fsw.EnableRaisingEvents = true;
}
}
catch (Exception ex)
{
if (isFirstTime) Console.Error.WriteLine("Error in parsing config: " + ex.Message);
else
{
LogHelper.Log.WriteLine("Error in parsing config. Leaving old config " + ex.Message);
}

return false;
}

return true;
}

private static DateTime _reloadTime;

private static Task _activatedTask;

private static void FswOnChanged(object sender, FileSystemEventArgs fileSystemEventArgs)
{
_reloadTime = DateTime.UtcNow.AddSeconds(4);
if (_activatedTask != null)
return;
_activatedTask = Task.Factory.StartNew(
() =>
{
while (true)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
if (DateTime.UtcNow > _reloadTime)
{
_activatedTask = null;
LoadConfig(false);
break;
}
}
});
}
}
}
4 changes: 4 additions & 0 deletions AutoTunnel/Config/MainConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,9 @@ public class MainConfig
[DefaultValue(15)]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public int PingBackTime { get; set; }

[DefaultValue(true)]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public bool AutoReloadOnChange { get; set; }
}
}
27 changes: 16 additions & 11 deletions AutoTunnel/Encryption/DecryptHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class DecryptHelper
{
private readonly byte[] _innerBuf = new byte[65536];

private readonly byte[] _key;
private readonly Aes _aes;

private readonly byte[] _headerBuf = new byte[16];

Expand All @@ -19,25 +19,30 @@ public byte[] InnerBuf
}

public DecryptHelper(byte[] key)
{
_key = key;
}

public int Decrypt(byte[] data, int offset)
{
var aes = Aes.Create();
aes.Key = _key;
aes.Key = key;
aes.IV = new byte[16];
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;
var decryptor = aes.CreateDecryptor();
decryptor.TransformBlock(data, offset, 16, _headerBuf, 0);
var len = _headerBuf[0] | (_headerBuf[1] << 8) | (_headerBuf[2] << 16) | (_headerBuf[3] << 24);
_aes = aes;
// _decryptor = aes.CreateDecryptor();
}

public int Decrypt(byte[] data, int offset)
{
var hb = _headerBuf;
// strange situation, decryptor cannot be used multiple times, problem with resetting cbc data, or my fault...
// but encrypting is work with extracted encryptor
var decryptor = _aes.CreateDecryptor();
decryptor.TransformBlock(data, offset, 16, hb, 0);
var len = hb[0] | (hb[1] << 8) | (hb[2] << 16) | (hb[3] << 24);
if (len > data.Length) return -1;
if (_headerBuf[4] != 1 || _headerBuf[5] != 0 || _headerBuf[6] != 'A' || _headerBuf[7] != 'T') return -1;
if (hb[4] != 1 || hb[5] != 0 || hb[6] != 'A' || hb[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);
// decryptor.TransformFinalBlock(new byte[0], 0, 0);
return len;
}
}
Expand Down
Loading

0 comments on commit 8b7f3ee

Please sign in to comment.