Browse Source

Added spam control module.

Added reconnection on disconnect.
Added disconnection checking.
Fixed kicked logging.
Fixed version exploit.
tags/3.0.0
Teknikode 4 years ago
parent
commit
84f9232686

+ 8
- 0
Combot.sln View File

@@ -9,6 +9,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interface", "Interface\Inte
{D469C717-7625-40F1-966D-3C9DD00F5B9C} = {D469C717-7625-40F1-966D-3C9DD00F5B9C}
{EBAC601C-652C-466A-B4F0-94495F4C8E49} = {EBAC601C-652C-466A-B4F0-94495F4C8E49}
{289A0E25-F669-4E00-9DB9-0C5AE51E2BCC} = {289A0E25-F669-4E00-9DB9-0C5AE51E2BCC}
{921B252D-D2D0-412F-BD6D-9559DCD20BB0} = {921B252D-D2D0-412F-BD6D-9559DCD20BB0}
{9ADA4844-4566-4C2E-8649-3D87E2F76563} = {9ADA4844-4566-4C2E-8649-3D87E2F76563}
{72CCA645-3E1D-4355-9BDE-5C1884BCB6FC} = {72CCA645-3E1D-4355-9BDE-5C1884BCB6FC}
{1A544D51-1041-4A9A-B1ED-E738735DF52E} = {1A544D51-1041-4A9A-B1ED-E738735DF52E}
@@ -70,6 +71,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seen", "Modules\Seen\Seen.c
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Messaging", "Modules\Messaging\Messaging.csproj", "{2434E995-592F-4EE2-B321-033B7493F93E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spam Control", "Modules\Spam Control\Spam Control.csproj", "{921B252D-D2D0-412F-BD6D-9559DCD20BB0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -156,6 +159,10 @@ Global
{2434E995-592F-4EE2-B321-033B7493F93E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2434E995-592F-4EE2-B321-033B7493F93E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2434E995-592F-4EE2-B321-033B7493F93E}.Release|Any CPU.Build.0 = Release|Any CPU
{921B252D-D2D0-412F-BD6D-9559DCD20BB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{921B252D-D2D0-412F-BD6D-9559DCD20BB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{921B252D-D2D0-412F-BD6D-9559DCD20BB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{921B252D-D2D0-412F-BD6D-9559DCD20BB0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -178,5 +185,6 @@ Global
{9ADA4844-4566-4C2E-8649-3D87E2F76563} = {D157677E-4D33-4156-B55E-E21C4B5A3024}
{909F6291-F0F5-4452-A4CA-BEF96916C01D} = {D157677E-4D33-4156-B55E-E21C4B5A3024}
{2434E995-592F-4EE2-B321-033B7493F93E} = {D157677E-4D33-4156-B55E-E21C4B5A3024}
{921B252D-D2D0-412F-BD6D-9559DCD20BB0} = {D157677E-4D33-4156-B55E-E21C4B5A3024}
EndGlobalSection
EndGlobal

+ 21
- 7
Combot/Bot.cs View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -66,16 +67,24 @@ namespace Combot
{
if (ServerConfig.Hosts.Count > i)
{
IPAddress[] ipList = Dns.GetHostAddresses(ServerConfig.Hosts[i].Host);
foreach (IPAddress ip in ipList)
try
{
serverConnected = IRC.Connect(ip, ServerConfig.Hosts[i].Port);
if (serverConnected)

IPAddress[] ipList = Dns.GetHostAddresses(ServerConfig.Hosts[i].Host);
foreach (IPAddress ip in ipList)
{
break;
serverConnected = IRC.Connect(ip, ServerConfig.Hosts[i].Port);
if (serverConnected)
{
break;
}
}
i++;
}
catch (SocketException ex)
{
break;
}
i++;
}
else
{
@@ -123,9 +132,14 @@ namespace Combot
{
if (RetryAllowed)
{
if (ErrorEvent != null)
{
ErrorEvent(new BotError() { Message = string.Format("Retrying connection in {0} seconds.", (int)Math.Pow(2, RetryCount)), Type = ErrorType.IRC });
}
Task.Run(() =>
{
Thread.Sleep((int)Math.Pow(1000, RetryCount));
Thread.Sleep(1000 * (int)Math.Pow(2, RetryCount));
RetryCount++;
Connect();
});
}

+ 55
- 10
IRCServices/IRC.cs View File

@@ -6,6 +6,8 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using Combot.IRCServices.Messaging;
using Combot.IRCServices.TCP;

@@ -27,6 +29,7 @@ namespace Combot.IRCServices
private int ReadTimeout;
private int AllowedFailedReads;
private Thread TCPReader;
private Thread KeepAlive;
private event Action<string> TCPMessageEvent;
private readonly TCPInterface _TCP;
private readonly ReaderWriterLockSlim ChannelRWLock;
@@ -78,6 +81,10 @@ namespace Combot.IRCServices
TCPReader.IsBackground = true;
TCPReader.Start();

KeepAlive = new Thread(() => CheckConnection(IP, port));
KeepAlive.IsBackground = true;
KeepAlive.Start();

if (ConnectEvent != null)
{
ConnectEvent();
@@ -261,6 +268,54 @@ namespace Combot.IRCServices
}
}

private void CheckConnection(IPAddress IP, int port)
{
int diconnectCount = 0;
bool stillConnected = true;
while (_TCP.Connected)
{
Thread.Sleep(1000);
stillConnected = NetworkInterface.GetIsNetworkAvailable();

if (stillConnected)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
s.Connect(IP, port);
}
catch
{
stillConnected = false;
}
}

if (!stillConnected)
{
diconnectCount++;
}
else
{
diconnectCount = 0;
}

if (diconnectCount >= 5)
{
Disconnect();
}
}
}

/// <summary>
/// Responds with PONG on a PING with the specified arguments.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HandlePing(object sender, PingInfo e)
{
SendPong(e.Message);
}

private void HandleTCPConnection(int e)
{
if (DisconnectEvent != null)
@@ -282,16 +337,6 @@ namespace Combot.IRCServices
Disconnect();
}

/// <summary>
/// Responds with PONG on a PING with the specified arguments.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HandlePing(object sender, PingInfo e)
{
SendPong(e.Message);
}

private void HandleReply(object sender, IReply e)
{
if (e.GetType() == typeof(ServerReplyMessage))

+ 29
- 3
IRCServices/TCP/TCPInterface.cs View File

@@ -71,10 +71,36 @@ namespace Combot.IRCServices.TCP

internal void Write(string data)
{
if (_tcpStream.CanWrite && Connected)
try
{
if (_tcpStream.CanWrite && Connected)
{
byte[] message = System.Text.Encoding.UTF8.GetBytes(data + Environment.NewLine);
_tcpStream.Write(message, 0, message.Length);
}
}
catch (IOException)
{
/*
_currentFailedCount++;
Action<TCPError> localEvent = TCPErrorEvent;
if (localEvent != null && _tcpStream.CanRead)
{
TCPError error = new TCPError();
error.Message = string.Format("Read Timeout, No Response from Server in {0}ms", _readTimeout);
localEvent(error);
}
*/
}
catch (Exception ex)
{
byte[] message = System.Text.Encoding.UTF8.GetBytes(data + Environment.NewLine);
_tcpStream.Write(message, 0, message.Length);
Action<TCPError> localEvent = TCPErrorEvent;
if (localEvent != null)
{
TCPError error = new TCPError();
error.Message = ex.Message;
localEvent(error);
}
}
}


+ 1
- 1
Modules/Logging/Logging.cs View File

@@ -82,7 +82,7 @@ namespace Combot.Modules.Plugins
AddNick(info.Nick.Nickname);
AddNick(info.KickedNick.Nickname);
Database database = new Database(Bot.ServerConfig.Database);
string query = "INSERT INTO `channelkickss` SET " +
string query = "INSERT INTO `channelkicks` SET " +
"`server_id` = (SELECT `id` FROM `servers` WHERE `name` = {0}), " +
"`channel_id` = (SELECT `channels`.`id` FROM `channels` INNER JOIN `servers` ON `servers`.`id` = `channels`.`server_id` WHERE `servers`.`name` = {1} && `channels`.`name` = {2}), " +
"`nick_id` = (SELECT `nicks`.`id` FROM `nicks` INNER JOIN `servers` ON `servers`.`id` = `nicks`.`server_id` WHERE `servers`.`name` = {3} && `nickname` = {4}), " +

+ 25
- 0
Modules/Spam Control/Module.config View File

@@ -0,0 +1,25 @@
{
"Name": "Spam Control",
"ClassName": "Spam_Control",
"Enabled": true,
"ChannelBlacklist": [],
"NickBlacklist": [],
"Commands": [],
"Options": [
{
"Name": "Max Messages",
"Description": "The maximum number of messages allowed per time alotted.",
"Value": 5
},
{
"Name": "Maximum Highlights",
"Description": "The maximum number of highlights allowed in a set period of time.",
"Value": 5
},
{
"Name": "Time Threshold",
"Description": "The minimum time allowed for a set of messages in milliseconds.",
"Value": 5000
}
]
}

+ 36
- 0
Modules/Spam Control/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Spam_Control Module")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Teknik")]
[assembly: AssemblyProduct("Combot")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("5c350b8e-5820-4034-9d67-49d2ddbfcc6f")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

+ 76
- 0
Modules/Spam Control/Spam Control.csproj View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" 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>{921B252D-D2D0-412F-BD6D-9559DCD20BB0}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Spam_Control</RootNamespace>
<AssemblyName>Spam Control</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\Bin\Modules\Spam Control\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\Modules\Spam Control\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<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.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="SpamHighlightInfo.cs" />
<Compile Include="SpamMessageInfo.cs" />
<Compile Include="Spam_Control.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Combot\Combot.csproj">
<Project>{23e4c371-16e4-4fac-8b11-44288399bb55}</Project>
<Name>Combot</Name>
</ProjectReference>
<ProjectReference Include="..\..\IRCServices\IRCServices.csproj">
<Project>{65fcbf1c-8c9e-4688-becc-185d9030899f}</Project>
<Name>IRCServices</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Module.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>mkdir "$(SolutionDir)Bin\Interface\$(ConfigurationName)\Modules\$(TargetName)"
copy /Y "$(TargetPath)" "$(SolutionDir)Bin\Interface\$(ConfigurationName)\Modules\$(TargetName)"
copy /Y "$(TargetDir)Module.config" "$(SolutionDir)Bin\Interface\$(ConfigurationName)\Modules\$(TargetName)"</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 25
- 0
Modules/Spam Control/SpamHighlightInfo.cs View File

@@ -0,0 +1,25 @@
using System;

namespace Combot.Modules.Plugins
{
public class SpamHighlightInfo
{
public string Channel { get; set; }
public string Nick { get; set; }
public int Highlights { get; set; }
public DateTime FirstHighlightTime { get; set; }

public SpamHighlightInfo()
{
SetDefaults();
}

private void SetDefaults()
{
Channel = string.Empty;
Nick = string.Empty;
Highlights = 0;
FirstHighlightTime = DateTime.Now;
}
}
}

+ 25
- 0
Modules/Spam Control/SpamMessageInfo.cs View File

@@ -0,0 +1,25 @@
using System;

namespace Combot.Modules.Plugins
{
public class SpamMessageInfo
{
public string Channel { get; set; }
public string Nick { get; set; }
public int Lines { get; set; }
public DateTime FirstMessageTime { get; set; }

public SpamMessageInfo()
{
SetDefaults();
}

private void SetDefaults()
{
Channel = string.Empty;
Nick = string.Empty;
Lines = 0;
FirstMessageTime = DateTime.Now;
}
}
}

+ 115
- 0
Modules/Spam Control/Spam_Control.cs View File

@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Combot.IRCServices;
using Combot.IRCServices.Messaging;

namespace Combot.Modules.Plugins
{
public class Spam_Control : Module
{
private List<SpamMessageInfo> SpamMessageList;
private List<SpamHighlightInfo> SpamHighlightList;
private ReaderWriterLockSlim SpamMessageLock;
private ReaderWriterLockSlim SpamHighlightLock;

public override void Initialize()
{
SpamMessageList = new List<SpamMessageInfo>();
SpamHighlightList = new List<SpamHighlightInfo>();
SpamMessageLock = new ReaderWriterLockSlim();
SpamHighlightLock = new ReaderWriterLockSlim();
Bot.IRC.Message.ChannelMessageReceivedEvent += HandleChannelMessage;
}

private void HandleChannelMessage(object sender, ChannelMessage message)
{
if (!ChannelBlacklist.Contains(message.Channel) && !NickBlacklist.Contains(message.Sender.Nickname))
{
// Check for line spam
if (SpamMessageList.Exists(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname))
{
SpamMessageLock.EnterReadLock();
SpamMessageInfo info = SpamMessageList.Find(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname);
SpamMessageLock.ExitReadLock();
TimeSpan difference = message.TimeStamp.Subtract(info.FirstMessageTime);
if (difference.TotalMilliseconds < (int) GetOptionValue("Time Threshold"))
{
info.Lines++;
if (info.Lines > (int) GetOptionValue("Max Messages"))
{
Bot.IRC.SendKick(info.Channel, info.Nick, string.Format("Please do not spam. You have messaged {0} times within {1}ms.", info.Lines, GetOptionValue("Time Threshold")));
SpamMessageLock.EnterWriteLock();
SpamMessageList.Remove(info);
SpamMessageLock.ExitWriteLock();
}
}
else
{
SpamMessageLock.EnterWriteLock();
info.Lines = 1;
info.FirstMessageTime = message.TimeStamp;
SpamMessageLock.ExitWriteLock();
}
}
else
{
SpamMessageInfo info = new SpamMessageInfo();
info.Channel = message.Channel;
info.Nick = message.Sender.Nickname;
info.Lines = 1;
info.FirstMessageTime = message.TimeStamp;
SpamMessageLock.EnterWriteLock();
SpamMessageList.Add(info);
SpamMessageLock.ExitWriteLock();
}

// Check for highlight spam
List<string> splitMessage = message.Message.Split(new [] {' '}, StringSplitOptions.RemoveEmptyEntries).ToList();
Channel channel = Bot.IRC.Channels.Find(chan => chan.Name == message.Channel);
if (channel != null)
{
List<string> foundNicks = splitMessage.FindAll(msg => channel.Nicks.Exists(nick => msg.Contains(nick.Nickname)));
if (foundNicks.Any())
{
if (!SpamHighlightList.Exists(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname))
{
SpamHighlightInfo newInfo = new SpamHighlightInfo();
newInfo.Channel = message.Channel;
newInfo.Nick = message.Sender.Nickname;
newInfo.Highlights = 0;
newInfo.FirstHighlightTime = message.TimeStamp;

SpamHighlightLock.EnterWriteLock();
SpamHighlightList.Add(newInfo);
SpamHighlightLock.ExitWriteLock();
}
SpamHighlightLock.EnterReadLock();
SpamHighlightInfo info = SpamHighlightList.Find(highlight => highlight.Channel == message.Channel && highlight.Nick == message.Sender.Nickname);
SpamHighlightLock.ExitReadLock();
TimeSpan difference = message.TimeStamp.Subtract(info.FirstHighlightTime);
if (difference.TotalMilliseconds < (int) GetOptionValue("Time Threshold"))
{
info.Highlights += foundNicks.Count;
if (info.Highlights > (int) GetOptionValue("Maximum Highlights"))
{
Bot.IRC.SendKick(info.Channel, info.Nick, string.Format("Please do not highlight spam. You have highlighted {0} nicks within {1}ms.", info.Highlights, GetOptionValue("Time Threshold")));
SpamHighlightLock.EnterWriteLock();
SpamHighlightList.Remove(info);
SpamHighlightLock.ExitWriteLock();
}
}
else
{
SpamHighlightLock.EnterWriteLock();
info.Highlights = foundNicks.Count;
info.FirstHighlightTime = message.TimeStamp;
SpamHighlightLock.ExitWriteLock();
}
}
}
}
}
}
}

+ 7
- 1
Modules/Version/Module.config View File

@@ -46,5 +46,11 @@
"SpamCheck": true
}
],
"Options": []
"Options": [
{
"Name": "Machine Reply",
"Description": "The machine you want a version reply to say the bot is running on.",
"Value": "Windows 11"
}
]
}

+ 18
- 11
Modules/Version/Version.cs View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using Combot.IRCServices.Messaging;
@@ -25,18 +27,23 @@ namespace Combot.Modules.Plugins

if (foundCommand.Name == "Version Check")
{
VersionItem tmpItem = new VersionItem();
tmpItem.Location = command.Location;
tmpItem.MessageType = command.MessageType;
tmpItem.Nick = command.Arguments["Nickname"];
listLock.EnterWriteLock();
if (versionList.Exists(item => item.Nick == command.Arguments["Nickname"]))
string nick = command.Arguments["Nickname"].ToString();
List<string> nickList = nick.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
for (int i = 0; i < nickList.Count; i++)
{
versionList.RemoveAll(item => item.Nick == command.Arguments["Nickname"]);
VersionItem tmpItem = new VersionItem();
tmpItem.Location = command.Location;
tmpItem.MessageType = command.MessageType;
tmpItem.Nick = nickList[i];
listLock.EnterWriteLock();
if (versionList.Exists(item => item.Nick == nickList[i]))
{
versionList.RemoveAll(item => item.Nick == nickList[i]);
}
versionList.Add(tmpItem);
listLock.ExitWriteLock();
Bot.IRC.SendCTCPMessage(nickList[i], "VERSION");
}
versionList.Add(tmpItem);
listLock.ExitWriteLock();
Bot.IRC.SendCTCPMessage(command.Arguments["Nickname"], "VERSION");
}
}


Loading…
Cancel
Save