Skip to content

Commit

Permalink
Source files
Browse files Browse the repository at this point in the history
  • Loading branch information
thanatos-tshock committed Oct 7, 2017
1 parent c5b36e4 commit 4d2c314
Show file tree
Hide file tree
Showing 9 changed files with 605 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/Connection.Limit/bin
/Connection.Limit/obj
*.suo
/*.user
packages/
References/
.vs/
22 changes: 22 additions & 0 deletions Connection.Limit.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.16
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Connection.Limit", "Connection.Limit\Connection.Limit.csproj", "{2C05B111-C1E5-4BF3-988F-AA3AA42F0FC1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2C05B111-C1E5-4BF3-988F-AA3AA42F0FC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C05B111-C1E5-4BF3-988F-AA3AA42F0FC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C05B111-C1E5-4BF3-988F-AA3AA42F0FC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C05B111-C1E5-4BF3-988F-AA3AA42F0FC1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
32 changes: 32 additions & 0 deletions Connection.Limit/Config.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Newtonsoft.Json;
using System;

namespace Connection.Limit
{
public class Config
{
[JsonProperty("enabled")]
public bool Enabled { get; set; } = true;

[JsonProperty("max-connections-per-ip")]
public int MaxConnectionsPerIp { get; set; } = 1;

[JsonProperty("recalibration-time-milliseconds")]
public int RecalibrationTimeMilliseconds { get; set; } = 1000;

public void Verify()
{
if (MaxConnectionsPerIp < 1)
{
Console.WriteLine($"{MaxConnectionsPerIp} is an invalid value for config property: max-connections-per-ip. Minimum value is 1.");
MaxConnectionsPerIp = 1;
}

if (RecalibrationTimeMilliseconds < 1000)
{
Console.WriteLine($"{RecalibrationTimeMilliseconds} is an invalid value for config property: recalibration-time-milliseconds. Minimum value is 1000.");
RecalibrationTimeMilliseconds = 1000;
}
}
}
}
67 changes: 67 additions & 0 deletions Connection.Limit/Connection.Limit.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2C05B111-C1E5-4BF3-988F-AA3AA42F0FC1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Connection.Limit</RootNamespace>
<AssemblyName>xxConnection.Limit</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\TShock_Testing\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="OTAPI">
<HintPath>..\..\..\..\..\..\..\TShock_Testing\OTAPI.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="TerrariaServer">
<HintPath>..\..\..\..\..\..\..\TShock_Testing\TerrariaServer.exe</HintPath>
</Reference>
<Reference Include="TShockAPI">
<HintPath>..\..\..\..\..\..\..\TShock_Testing\ServerPlugins\TShockAPI.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Config.cs" />
<Compile Include="ConnectionLimitPlugin.cs" />
<Compile Include="Limiter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TcpSocket.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
12 changes: 12 additions & 0 deletions Connection.Limit/Connection.Limit.csproj.user
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartArguments>
</StartArguments>
<StartAction>Program</StartAction>
<StartProgram>
</StartProgram>
<StartWorkingDirectory>
</StartWorkingDirectory>
</PropertyGroup>
</Project>
95 changes: 95 additions & 0 deletions Connection.Limit/ConnectionLimitPlugin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using Newtonsoft.Json;
using OTAPI;
using System;
using System.IO;
using Terraria;
using TerrariaApi.Server;
using TShockAPI;

namespace Connection.Limit
{
[ApiVersion(2, 1)]
public class ConnectionLimitPlugin : TerrariaPlugin
{
internal const String PluginName = "Connection.Limit";
internal const String ConsoleTag = "[" + PluginName + "]: ";

public override string Author => "thanatos";
public override string Description => "Limits the amount of connections per ip";
public override string Name => PluginName;
public override Version Version => typeof(ConnectionLimitPlugin).Assembly.GetName().Version;

private Config _config;
private TcpSocket _socket;

public ConnectionLimitPlugin(Main game) : base(game)
{
this.Order = 1000;
}

void LoadConfig()
{
string
directory = Path.Combine("tshock", "connection_limit"),
filepath = Path.Combine(directory, "config.json")
;
Directory.CreateDirectory(directory);

if (File.Exists(filepath))
{
_config = JsonConvert.DeserializeObject<Config>(File.ReadAllText(filepath));
}
else
{
var config = new Config();
File.WriteAllText(filepath, JsonConvert.SerializeObject(config, Formatting.Indented));
_config = config;
}

_config.Verify();
}

public override void Initialize()
{
LoadConfig();

if (!_config.Enabled)
{
Console.WriteLine($"{ConsoleTag} disabled by configuration file.");
return;
}

Commands.ChatCommands.Add(new Command("connection.limit.toggle", (CommandArgs args) =>
{
this._config.Enabled = !this._config.Enabled;
args.Player.SendInfoMessage($"{PluginName} is {(this._config.Enabled ? "enabled" : "disabled")}");
}, new[]
{
"cl-toggle"
}));
Commands.ChatCommands.Add(new Command("connection.limit.stats", (CommandArgs args) =>
{
long accepted = _socket?.Limiter?.AcceptedConnections ?? 0L;
long blocked = _socket?.Limiter?.BlockedConnections ?? 0L;
Console.WriteLine($"{ConsoleTag} Accepted connections for current session: {accepted}");
Console.WriteLine($"{ConsoleTag} Blocked connections for current session: {blocked}");
}, new[]
{
"cl-stats"
}));

Hooks.World.IO.PreLoadWorld = (ref bool loadFromCloud) =>
{
Hooks.Net.Socket.Create = CreateSocket;
return HookResult.Continue;
};

Console.WriteLine($"{ConsoleTag} initialised");
}

TcpSocket CreateSocket()
{
return _socket ?? (_socket = new TcpSocket(_config));
}
}
}
129 changes: 129 additions & 0 deletions Connection.Limit/Limiter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;

namespace Connection.Limit
{
public class Limiter
{
private Dictionary<string, int> _registry = new Dictionary<string, int>();
private Config _config;
private DateTime? _lastCalibration;

private long _blockedConnections = 0;
public long BlockedConnections
{
get
{
return System.Threading.Interlocked.Read(ref _blockedConnections);
}
}

private long _acceptedConnections = 0;
public long AcceptedConnections
{
get
{
return System.Threading.Interlocked.Read(ref _acceptedConnections);
}
}

public Limiter(Config config)
{
_config = config;
}

public bool Register(string ip)
{
bool allow = true;

if (CanRecalibrate())
Recalibrate();

lock (_registry)
{
int number;
if (_registry.TryGetValue(ip, out number))
{
allow = number < _config.MaxConnectionsPerIp;

if (allow)
{
_registry[ip]++;
}
}
else
{
_registry.Add(ip, 1);
}
}

if (allow)
{
System.Threading.Interlocked.Increment(ref _acceptedConnections);
}
else
{
System.Threading.Interlocked.Increment(ref _blockedConnections);
}

return allow;
}

public void Unregister(string ip)
{
lock (_registry)
{
int number;
if (_registry.TryGetValue(ip, out number))
{
if (number <= 0)
{
System.Diagnostics.Debug.WriteLine("Tried decreasing an ip limit when the number is already 0");
}
else
{
_registry[ip]--;
}
}
else
{
System.Diagnostics.Debug.WriteLine("Tried decreasing an ip limit when there was no registration");
}
}
}

public bool CanRecalibrate() => _lastCalibration == null || (DateTime.Now - _lastCalibration.Value).TotalMilliseconds >= _config.RecalibrationTimeMilliseconds;

public void Recalibrate()
{
System.Diagnostics.Debug.WriteLine("Recalibrating");
lock (_registry)
{
_registry.Clear();

foreach (var client in Terraria.Netplay.Clients)
{
if (client != null && client.IsActive)
{
var socket = client.Socket as TcpSocket;
if (socket != null)
{
var ip = socket.IpAddress;
int number;
if (_registry.TryGetValue(ip, out number))
{
_registry[ip]++;
}
else
{
_registry.Add(ip, 1);
}
}
}
}

_lastCalibration = DateTime.Now;
}
}
}
}
Loading

0 comments on commit 4d2c314

Please sign in to comment.