Skip to content

Commit 8b7f3ee

Browse files
committed
config auto reload, bug fixes and improvements
1 parent b834d4a commit 8b7f3ee

File tree

16 files changed

+432
-156
lines changed

16 files changed

+432
-156
lines changed

AutoTunnel/AutoTunnel.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
7070
</None>
7171
<Compile Include="ClientSender.cs" />
72+
<Compile Include="Config\ConfigHelper.cs" />
7273
<Compile Include="Config\RemoteClientConfig.cs" />
7374
<Compile Include="Config\RemoteServerConfig.cs" />
7475
<Compile Include="Config\MainConfig.cs" />
@@ -102,6 +103,7 @@
102103
<Compile Include="Service\MainServiceInstallHelper.cs" />
103104
<Compile Include="Starter.cs" />
104105
<Compile Include="StateFlags.cs" />
106+
<Compile Include="TunnelSession.cs" />
105107
<Compile Include="TunnelStorage.cs" />
106108
<Compile Include="WinDivert.cs" />
107109
</ItemGroup>

AutoTunnel/BaseSender.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ public abstract class BaseSender : IDisposable
2020

2121
protected readonly TunnelStorage Storage;
2222

23-
public TunnelStorage.Session Session { get; set; }
23+
public TunnelSession Session { get; set; }
2424

25-
protected BaseSender(TunnelStorage.Session session, IPAddress watchAddr, TunnelStorage storage)
25+
protected BaseSender(TunnelSession session, IPAddress watchAddr, TunnelStorage storage)
2626
{
2727
Storage = storage;
2828
Session = session;

AutoTunnel/ClientSender.cs

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@ private void Init()
8484
Task.Factory.StartNew(InitInternal);
8585
}
8686

87+
private void CloseSocket()
88+
{
89+
if (_socket != null)
90+
{
91+
_socket.Dispose();
92+
}
93+
94+
_socket = null;
95+
}
96+
8797
private void InitInternal()
8898
{
8999
if (Interlocked.CompareExchange(ref _isIniting, 1, 0) == 1)
@@ -126,8 +136,7 @@ private void InitInternal()
126136
var recLength = 0;
127137

128138
// killing old socket
129-
if (_socket != null)
130-
_socket.Dispose();
139+
CloseSocket();
131140
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
132141
_socket.Connect(destEP);
133142

@@ -170,7 +179,7 @@ private void InitInternal()
170179
LogHelper.Log.WriteLine("No response from server " + destEP);
171180
if (DateTime.UtcNow.Subtract(_lastInitRequest).TotalSeconds > 60)
172181
{
173-
LogHelper.Log.WriteLine("Stopping connect atteptions to " + destEP + " until another request will occure");
182+
LogHelper.Log.WriteLine("Stopping connect atteptions to " + destEP + " until another request will occur");
174183
}
175184
}
176185

@@ -205,36 +214,42 @@ private void InitInternal()
205214
}
206215
}
207216

217+
private void DropInit()
218+
{
219+
_isInited = false;
220+
if (_config.KeepAlive)
221+
Init();
222+
}
223+
208224
private void PingCycle()
209225
{
210-
DateTime lastReceiveLast = DateTime.MinValue;
226+
DateTime lastPingDate = DateTime.MinValue;
227+
var pingSpan = TimeSpan.FromSeconds(_config.PingInterval);
228+
211229
while (!_disposed)
212230
{
213231
if (_isInited)
214232
{
215233
// problem with server? no answers, dropping connection
216-
if (Session.LastActivity == lastReceiveLast)
234+
if (Session.SendReceiveDifference > TimeSpan.FromSeconds(_config.PingInterval * 2))
217235
{
218-
_isInited = false;
219-
lastReceiveLast = DateTime.MinValue;
220-
if (_config.KeepAlive)
221-
Init();
236+
DropInit();
222237
}
223238

224-
if (_config.KeepAlive || _lastSend.Subtract(Session.LastActivity).TotalSeconds > _config.PingInterval)
239+
if ((_config.KeepAlive && DateTime.UtcNow.Subtract(lastPingDate) > pingSpan) || Session.SendReceiveDifference > pingSpan)
225240
{
226-
lastReceiveLast = Session.LastActivity;
227241
_socket.Send(new byte[] { (byte)StateFlags.Ping, 0, 0, 0 }, 4, SocketFlags.None);
228-
_lastSend = DateTime.UtcNow;
242+
lastPingDate = DateTime.UtcNow;
229243
}
230244
}
231245
else
232246
{
233-
// force renew connection attepmt
234-
_lastInitRequest = DateTime.UtcNow;
247+
// force renew connection attempt
248+
if (_config.KeepAlive)
249+
_lastInitRequest = DateTime.UtcNow;
235250
}
236251

237-
Thread.Sleep(_config.PingInterval * 1000);
252+
Thread.Sleep(1000);
238253
}
239254
}
240255

@@ -251,15 +266,13 @@ protected override void Send(byte[] packet, int packetLen)
251266
{
252267
var lenToSend = _encryptHelper.Encrypt(packet, packetLen);
253268
var packetToSend = _encryptHelper.InnerBuf;
254-
_lastSend = DateTime.UtcNow;
269+
Session.UpdateReceiveActivity();
255270
_socket.Send(packetToSend, lenToSend, SocketFlags.None);
256271
}
257272
}
258273

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

261-
private DateTime _lastSend;
262-
263276
private void ReceiveCycle()
264277
{
265278
byte[] buf = _receiveBuffer;
@@ -276,18 +289,14 @@ private void ReceiveCycle()
276289
{
277290
len = _socket.Receive(buf);
278291
}
279-
catch (Exception ex)
292+
catch (Exception/* ex*/)
280293
{
281294
if (_isIniting == 1 && _isInited)
282295
{
283296
LogHelper.Log.WriteLine("Receive data error");
284297
_isInited = false;
285298
// LogHelper.Log.WriteLine(ex);
286-
if (_socket != null)
287-
{
288-
_socket.Dispose();
289-
_socket = null;
290-
}
299+
CloseSocket();
291300

292301
if (_config.KeepAlive) Init();
293302
}
@@ -303,14 +312,12 @@ private void ReceiveCycle()
303312
if (buf[0] != (byte)StateFlags.Pong)
304313
{
305314
LogHelper.Log.WriteLine("Received an error flag from " + _socket.RemoteEndPoint);
306-
_isInited = false;
307-
// failed data
308-
Init();
315+
DropInit();
309316
continue;
310317
}
311318
}
312319

313-
Session.UpdateLastActivity();
320+
Session.UpdateReceiveActivity();
314321

315322
var decryptHelper = Session.Decryptor;
316323
var decLen = decryptHelper.Decrypt(buf, 0);
@@ -323,7 +330,7 @@ public override void Dispose()
323330
base.Dispose();
324331
_disposed = true;
325332
_initingEvent.Set();
326-
_socket.Dispose();
333+
CloseSocket();
327334
}
328335
}
329336
}

AutoTunnel/Config/ConfigHelper.cs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
6+
using Force.AutoTunnel.Logging;
7+
8+
using Newtonsoft.Json;
9+
10+
namespace Force.AutoTunnel.Config
11+
{
12+
public static class ConfigHelper
13+
{
14+
public static MainConfig Config { get; private set; }
15+
16+
private static FileSystemWatcher _fsw;
17+
18+
public static bool LoadConfig(bool isFirstTime)
19+
{
20+
try
21+
{
22+
if (_fsw != null)
23+
{
24+
_fsw.Dispose();
25+
_fsw = null;
26+
}
27+
28+
if (!isFirstTime)
29+
LogHelper.Log.WriteLine("Reloading config");
30+
31+
var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.json");
32+
if (!File.Exists(configPath))
33+
{
34+
if (isFirstTime)
35+
Console.Error.WriteLine("Missing config file");
36+
else
37+
LogHelper.Log.WriteLine("Missing config file");
38+
39+
return false;
40+
}
41+
42+
MainConfig config;
43+
using (var f = File.OpenRead(configPath))
44+
config = new JsonSerializer().Deserialize<MainConfig>(new JsonTextReader(new StreamReader(f)));
45+
46+
if (config.RemoteClients == null)
47+
config.RemoteClients = new RemoteClientConfig[0];
48+
if (config.RemoteClients.Length == 0)
49+
config.EnableListening = false;
50+
if (config.RemoteServers == null)
51+
config.RemoteServers = new RemoteServerConfig[0];
52+
foreach (var remoteServerConfig in config.RemoteServers)
53+
{
54+
if (string.IsNullOrEmpty(remoteServerConfig.ConnectHost) && string.IsNullOrEmpty(remoteServerConfig.TunnelHost))
55+
throw new InvalidOperationException("Missing host info in config");
56+
57+
if (string.IsNullOrEmpty(remoteServerConfig.TunnelHost))
58+
remoteServerConfig.TunnelHost = remoteServerConfig.ConnectHost;
59+
if (string.IsNullOrEmpty(remoteServerConfig.ConnectHost))
60+
remoteServerConfig.ConnectHost = remoteServerConfig.TunnelHost;
61+
}
62+
63+
if (!isFirstTime)
64+
Starter.Stop();
65+
66+
var log = new AggregateLog();
67+
if (Environment.UserInteractive) log.AddLog(new ConsoleLog());
68+
if (!string.IsNullOrEmpty(config.LogFileName)) log.AddLog(new FileLog(config.LogFileName));
69+
LogHelper.SetLog(log);
70+
71+
Config = config;
72+
73+
if (!isFirstTime)
74+
Starter.Start();
75+
76+
if (config.AutoReloadOnChange)
77+
{
78+
_fsw = new FileSystemWatcher(Path.GetDirectoryName(configPath) ?? string.Empty, Path.GetFileName(configPath) ?? string.Empty);
79+
_fsw.Changed += FswOnChanged;
80+
_fsw.Created += FswOnChanged;
81+
_fsw.Deleted += FswOnChanged;
82+
_fsw.EnableRaisingEvents = true;
83+
}
84+
}
85+
catch (Exception ex)
86+
{
87+
if (isFirstTime) Console.Error.WriteLine("Error in parsing config: " + ex.Message);
88+
else
89+
{
90+
LogHelper.Log.WriteLine("Error in parsing config. Leaving old config " + ex.Message);
91+
}
92+
93+
return false;
94+
}
95+
96+
return true;
97+
}
98+
99+
private static DateTime _reloadTime;
100+
101+
private static Task _activatedTask;
102+
103+
private static void FswOnChanged(object sender, FileSystemEventArgs fileSystemEventArgs)
104+
{
105+
_reloadTime = DateTime.UtcNow.AddSeconds(4);
106+
if (_activatedTask != null)
107+
return;
108+
_activatedTask = Task.Factory.StartNew(
109+
() =>
110+
{
111+
while (true)
112+
{
113+
Thread.Sleep(TimeSpan.FromSeconds(1));
114+
if (DateTime.UtcNow > _reloadTime)
115+
{
116+
_activatedTask = null;
117+
LoadConfig(false);
118+
break;
119+
}
120+
}
121+
});
122+
}
123+
}
124+
}

AutoTunnel/Config/MainConfig.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,9 @@ public class MainConfig
3131
[DefaultValue(15)]
3232
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
3333
public int PingBackTime { get; set; }
34+
35+
[DefaultValue(true)]
36+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
37+
public bool AutoReloadOnChange { get; set; }
3438
}
3539
}

AutoTunnel/Encryption/DecryptHelper.cs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public class DecryptHelper
66
{
77
private readonly byte[] _innerBuf = new byte[65536];
88

9-
private readonly byte[] _key;
9+
private readonly Aes _aes;
1010

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

@@ -19,25 +19,30 @@ public byte[] InnerBuf
1919
}
2020

2121
public DecryptHelper(byte[] key)
22-
{
23-
_key = key;
24-
}
25-
26-
public int Decrypt(byte[] data, int offset)
2722
{
2823
var aes = Aes.Create();
29-
aes.Key = _key;
24+
aes.Key = key;
3025
aes.IV = new byte[16];
3126
aes.Mode = CipherMode.CBC;
3227
aes.Padding = PaddingMode.None;
33-
var decryptor = aes.CreateDecryptor();
34-
decryptor.TransformBlock(data, offset, 16, _headerBuf, 0);
35-
var len = _headerBuf[0] | (_headerBuf[1] << 8) | (_headerBuf[2] << 16) | (_headerBuf[3] << 24);
28+
_aes = aes;
29+
// _decryptor = aes.CreateDecryptor();
30+
}
31+
32+
public int Decrypt(byte[] data, int offset)
33+
{
34+
var hb = _headerBuf;
35+
// strange situation, decryptor cannot be used multiple times, problem with resetting cbc data, or my fault...
36+
// but encrypting is work with extracted encryptor
37+
var decryptor = _aes.CreateDecryptor();
38+
decryptor.TransformBlock(data, offset, 16, hb, 0);
39+
var len = hb[0] | (hb[1] << 8) | (hb[2] << 16) | (hb[3] << 24);
3640
if (len > data.Length) return -1;
37-
if (_headerBuf[4] != 1 || _headerBuf[5] != 0 || _headerBuf[6] != 'A' || _headerBuf[7] != 'T') return -1;
41+
if (hb[4] != 1 || hb[5] != 0 || hb[6] != 'A' || hb[7] != 'T') return -1;
3842
var len16 = (len + 15) & ~15;
3943
if (len < 0 || len > _innerBuf.Length) return -1;
4044
decryptor.TransformBlock(data, offset + 16, len16, _innerBuf, 0);
45+
// decryptor.TransformFinalBlock(new byte[0], 0, 0);
4146
return len;
4247
}
4348
}

0 commit comments

Comments
 (0)