This commit is contained in:
2025-02-16 05:25:30 +01:00
parent 580ebae140
commit 56be35fc15
23 changed files with 1027 additions and 414 deletions

View File

@@ -0,0 +1,84 @@
using System;
using System.Net.Sockets;
namespace EonaCat.Logger.Servers.GrayLog;
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
/// <summary>
/// GrayLog client
/// </summary>
public class Graylog : IDisposable
{
internal readonly object SendLock = new();
private string _Hostname = "127.0.0.1";
private int _Port = 12201;
internal UdpClient Udp;
public bool SupportsTcp { get; set; }
public string Nickname { get; set; }
public string IpPort => _Hostname + ":" + _Port;
public Graylog() { }
public Graylog(string hostname = "127.0.0.1", int port = 12201, string nickName = null)
{
_Hostname = hostname ?? throw new ArgumentNullException(nameof(hostname));
_Port = port >= 0 ? port : throw new ArgumentException("Port must be zero or greater.");
Nickname = nickName ?? IpPort;
SetUdp();
}
public string Hostname
{
get => _Hostname;
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentNullException(nameof(Hostname));
_Hostname = value;
SetUdp();
}
}
public int Port
{
get => _Port;
set
{
if (value < 0)
throw new ArgumentException("Port must be zero or greater.");
_Port = value;
SetUdp();
}
}
private void SetUdp()
{
DisposeUdp();
Udp = new UdpClient(_Hostname, _Port);
}
private void DisposeUdp()
{
if (Udp != null)
{
Udp.Dispose();
Udp = null;
}
}
public void Dispose()
{
DisposeUdp();
GC.SuppressFinalize(this);
}
~Graylog()
{
Dispose();
}
}

View File

@@ -0,0 +1,19 @@
namespace EonaCat.Logger.Servers.Splunk.Models;
public class SplunkPayload
{
/// <summary>
/// Event data for splunk
/// </summary>
public string EventData { get; set; }
/// <summary>
/// SourceType for splunk
/// </summary>
public string SourceType { get; set; }
/// <summary>
/// Host for splunk
/// </summary>
public string Host { get; set; }
}

View File

@@ -0,0 +1,130 @@
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using EonaCat.Json;
namespace EonaCat.Logger.Servers.Splunk;
using EonaCat.Logger.Servers.Splunk.Models;
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
/// <summary>
/// Splunk Server.
/// </summary>
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
public class Splunk : IDisposable
{
internal readonly object SendLock = new();
private string _splunkHecUrl = "https://127.0.0.1:8088/services/collector/event";
public string SplunkHecToken { get; set; } = "splunk-hec-token";
public HttpClientHandler SplunkClientHandler { get; private set; }
public HttpClient HttpClient { get; private set; }
public string Nickname { get; set; }
public bool HasHecToken => !string.IsNullOrWhiteSpace(SplunkHecToken) && SplunkHecToken != "splunk-hec-token";
public bool HasHecUrl => !string.IsNullOrWhiteSpace(SplunkHecUrl);
public bool IsHttpsHecUrl => HasHecUrl && _splunkHecUrl.ToLower().StartsWith("https");
public bool IsLocalHost => HasHecUrl && (_splunkHecUrl.ToLower().Contains("127.0.0.1") || _splunkHecUrl.ToLower().Contains("localhost"));
public Splunk(string splunkHecUrl, string splunkHecToken, HttpClientHandler httpClientHandler = null, string nickName = null)
{
SplunkHecUrl = splunkHecUrl ?? throw new ArgumentNullException(nameof(splunkHecUrl));
SplunkHecToken = splunkHecToken ?? throw new ArgumentNullException(nameof(splunkHecToken));
Nickname = nickName ?? $"{splunkHecUrl}_{splunkHecToken}";
SplunkClientHandler = httpClientHandler ?? new HttpClientHandler();
CreateHttpClient();
}
public string SplunkHecUrl
{
get => _splunkHecUrl;
set
{
if (!string.IsNullOrWhiteSpace(value) && !value.ToLower().Contains("http"))
{
value = $"http://{value}";
}
_splunkHecUrl = value;
CreateHttpClient();
}
}
private void CreateHttpClient()
{
DisposeHttpClient();
SplunkClientHandler ??= new HttpClientHandler();
HttpClient = new HttpClient(SplunkClientHandler)
{
BaseAddress = new Uri(SplunkHecUrl)
};
HttpClient.DefaultRequestHeaders.Add("Authorization", $"Splunk {SplunkHecToken}");
}
public void DisableSSLValidation()
{
DisposeHttpClient();
SplunkClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
};
CreateHttpClient();
}
public async Task<HttpResponseMessage> SendAsync(SplunkPayload splunkPayload)
{
if (splunkPayload == null) return null;
var eventObject = new
{
@event = splunkPayload.EventData,
sourcetype = splunkPayload.SourceType,
host = splunkPayload.Host
};
var eventJson = JsonHelper.ToJson(eventObject);
if (!HasHecToken) CreateHttpClient();
using var content = new StringContent(eventJson, Encoding.UTF8, "application/json");
return await HttpClient.PostAsync("/services/collector/event", content);
}
private void DisposeHttpClient()
{
if (HttpClient != null)
{
HttpClient.Dispose();
HttpClient = null;
}
if (SplunkClientHandler != null)
{
SplunkClientHandler.Dispose();
SplunkClientHandler = null;
}
}
public void Dispose()
{
DisposeHttpClient();
GC.SuppressFinalize(this);
}
~Splunk()
{
Dispose();
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Net.Sockets;
namespace EonaCat.Logger.Servers.Syslog;
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
/// <summary>
/// Syslog server.
/// </summary>
public class Syslog : IDisposable
{
private string _Hostname = "127.0.0.1";
private int _Port = 514;
internal UdpClient Udp;
public Syslog() { }
public Syslog(string hostname = "127.0.0.1", int port = 514, string nickName = null)
{
Hostname = hostname;
Port = port;
Nickname = nickName ?? IpPort;
}
public string Hostname
{
get => _Hostname;
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentNullException(nameof(Hostname));
_Hostname = value;
SetUdp();
}
}
public int Port
{
get => _Port;
set
{
if (value < 0)
throw new ArgumentException("Port must be zero or greater.");
_Port = value;
SetUdp();
}
}
public string IpPort => _Hostname + ":" + _Port;
public bool SupportsTcp { get; set; }
public string Nickname { get; set; }
private void SetUdp()
{
DisposeUdp();
Udp = new UdpClient(_Hostname, _Port);
}
private void DisposeUdp()
{
if (Udp != null)
{
Udp.Dispose();
Udp = null;
}
}
public void Dispose()
{
DisposeUdp();
GC.SuppressFinalize(this);
}
~Syslog()
{
Dispose();
}
}

View File

@@ -0,0 +1,115 @@
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace EonaCat.Logger.Servers.Tcp
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
public class Tcp : IDisposable
{
private string _Hostname = "127.0.0.1";
private int _Port = 514;
internal TcpClient _tcp;
public string Nickname { get; set; }
public string IpPort => _Hostname + ":" + _Port;
public Tcp(string hostname, int port, string nickname = null)
{
_Hostname = hostname ?? throw new ArgumentNullException(nameof(hostname));
_Port = port >= 0 ? port : throw new ArgumentException("Port must be zero or greater.");
Nickname = nickname ?? IpPort;
SetTcp();
}
public string Hostname
{
get => _Hostname;
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentNullException(nameof(Hostname));
_Hostname = value;
SetTcp();
}
}
public int Port
{
get => _Port;
set
{
if (value < 0)
throw new ArgumentException("Port must be zero or greater.");
_Port = value;
SetTcp();
}
}
internal void SetTcp()
{
DisposeTcp();
_tcp = new TcpClient(_Hostname, _Port);
}
internal void DisposeTcp()
{
if (_tcp != null)
{
_tcp.Close();
_tcp.Dispose();
_tcp = null;
}
}
public void Dispose()
{
DisposeTcp();
GC.SuppressFinalize(this);
}
internal async Task WriteAsync(byte[] data)
{
if (_tcp == null)
{
return;
}
if (data == null)
{
return;
}
using var stream = _tcp.GetStream();
await stream.WriteAsync(data, 0, data.Length);
await stream.FlushAsync();
}
internal async Task WriteAsync(string data)
{
if (_tcp == null)
{
return;
}
if (string.IsNullOrEmpty(data))
{
return;
}
var sendData = Encoding.UTF8.GetBytes(data);
using var stream = _tcp.GetStream();
await stream.WriteAsync(sendData, 0, sendData.Length);
await stream.FlushAsync();
}
~Tcp()
{
Dispose();
}
}
}

View File

@@ -0,0 +1,127 @@
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace EonaCat.Logger.Servers.Udp
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
public class Udp : IDisposable
{
const int MaxUdpPacketSize = 4096;
private string _Hostname = "127.0.0.1";
private int _Port = 514;
internal UdpClient _udp;
public string Nickname { get; set; }
public string IpPort => _Hostname + ":" + _Port;
public Udp(string hostname, int port, string nickname = null)
{
_Hostname = hostname ?? throw new ArgumentNullException(nameof(hostname));
_Port = port >= 0 ? port : throw new ArgumentException("Port must be zero or greater.");
Nickname = nickname ?? IpPort;
SetUdp();
}
public string Hostname
{
get => _Hostname;
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentNullException(nameof(Hostname));
_Hostname = value;
SetUdp();
}
}
public int Port
{
get => _Port;
set
{
if (value < 0)
throw new ArgumentException("Port must be zero or greater.");
_Port = value;
SetUdp();
}
}
internal void SetUdp()
{
DisposeUdp();
_udp = new UdpClient(_Hostname, _Port);
}
internal void DisposeUdp()
{
if (_udp != null)
{
_udp.Dispose();
_udp = null;
}
}
public void Dispose()
{
DisposeUdp();
GC.SuppressFinalize(this);
}
internal async Task WriteAsync(byte[] data, bool dontFragment = false)
{
if (_udp == null || data == null)
{
return;
}
_udp.DontFragment = dontFragment;
int maxChunkSize = MaxUdpPacketSize;
int offset = 0;
while (offset < data.Length)
{
int chunkSize = Math.Min(maxChunkSize, data.Length - offset);
byte[] chunk = new byte[chunkSize];
Array.Copy(data, offset, chunk, 0, chunkSize);
await _udp.SendAsync(chunk, chunk.Length);
offset += chunkSize;
}
}
internal async Task WriteAsync(string data, bool dontFragment = false)
{
if (_udp == null || string.IsNullOrEmpty(data))
{
return;
}
var sendData = Encoding.UTF8.GetBytes(data);
_udp.DontFragment = dontFragment;
int maxChunkSize = MaxUdpPacketSize;
int offset = 0;
while (offset < sendData.Length)
{
int chunkSize = Math.Min(maxChunkSize, sendData.Length - offset);
byte[] chunk = new byte[chunkSize];
Array.Copy(sendData, offset, chunk, 0, chunkSize);
await _udp.SendAsync(chunk, chunk.Length);
offset += chunkSize;
}
}
~Udp()
{
Dispose();
}
}
}

View File

@@ -0,0 +1,141 @@
using EonaCat.Json;
using System;
using System.Dynamic;
using System.IO;
using System.Net;
using System.Text;
namespace EonaCat.Logger.Servers.Zabbix.API;
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
public class ZabbixApi
{
public ZabbixApi(string user, string password, string zabbixURL, bool basicAuth)
{
_user = user;
_password = password;
_zabbixURL = zabbixURL;
if (basicAuth)
{
_basicAuth = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(_user + ":" + _password));
}
_auth = null;
}
public ZabbixApi(string user, string password, string zabbixURL) : this(user, password, zabbixURL, false)
{
}
private readonly string _user;
private readonly string _password;
private readonly string _zabbixURL;
private string _auth;
private readonly string _basicAuth = null;
/// <summary>
/// Determines if the user is logged in
/// </summary>
public bool IsLoggedIn { get; set; }
/// <summary>
/// Logs in the user
/// </summary>
public void Login()
{
dynamic authentication = new ExpandoObject();
authentication.user = _user;
authentication.password = _password;
ZabbixApiResponse zabbixApiResponse = ResponseAsObject("user.login", authentication);
_auth = zabbixApiResponse.Result;
IsLoggedIn = !string.IsNullOrEmpty(_auth);
}
/// <summary>
/// Logs out the user
/// </summary>
/// <returns></returns>
public bool Logout()
{
ZabbixApiResponse zbxResponse = ResponseAsObject("user.logout", new string[] { });
var result = zbxResponse.Result;
return result;
}
/// <summary>
/// Generic method to send a request to the Zabbix API
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public string ResponseAsJson(string method, object parameters)
{
ZabbixApiRequest zbxRequest = new ZabbixApiRequest("2.0", method, 1, _auth, parameters);
string jsonParameters = JsonHelper.ToJson(zbxRequest);
return SendRequest(jsonParameters);
}
/// <summary>
/// Generic method to send a request to the Zabbix API
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public ZabbixApiResponse ResponseAsObject(string method, object parameters)
{
ZabbixApiRequest zbxRequest = new ZabbixApiRequest("2.0", method, 1, _auth, parameters);
string jsonParameters = JsonHelper.ToJson(zbxRequest);
return CreateResponse(SendRequest(jsonParameters));
}
/// <summary>
/// Creates a ZabbixApiResponse object from a JSON string
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
private ZabbixApiResponse CreateResponse(string json)
{
ZabbixApiResponse zbxResponse = JsonHelper.ToObject<ZabbixApiResponse>(json);
return zbxResponse;
}
/// <summary>
/// Sends a request to the Zabbix API
/// </summary>
/// <param name="jsonParams"></param>
/// <returns></returns>
private string SendRequest(string jsonParams)
{
WebRequest request = WebRequest.Create(_zabbixURL);
if (_basicAuth != null)
{
request.Headers.Add("Authorization", "Basic " + _basicAuth);
}
request.ContentType = "application/json-rpc";
request.Method = "POST";
string jsonResult;
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(jsonParams);
streamWriter.Flush();
streamWriter.Close();
}
WebResponse response = request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
jsonResult = streamReader.ReadToEnd();
}
return jsonResult;
}
}

View File

@@ -0,0 +1,42 @@
namespace EonaCat.Logger.Servers.Zabbix.API
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
public class ZabbixApiRequest
{
/// <summary>
/// Jsonrpc version
/// </summary>
public string Jsonrpc { get; set; }
/// <summary>
/// Method to call
/// </summary>
public string Method { get; set; }
/// <summary>
/// Id of the request
/// </summary>
public int Id { get; set; }
/// <summary>
/// Authentification token
/// </summary>
public string Auth { get; set; }
/// <summary>
/// Parameters of the request
/// </summary>
public dynamic Parameters { get; set; }
public ZabbixApiRequest(string jsonrpc, string method, int id, string auth, dynamic parameters)
{
Jsonrpc = jsonrpc;
Method = method;
Id = id;
Auth = auth;
Parameters = parameters;
}
}
}

View File

@@ -0,0 +1,25 @@
using System.Dynamic;
namespace EonaCat.Logger.Servers.Zabbix.API
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
public class ZabbixApiResponse
{
/// <summary>
/// Jsonrpc version
/// </summary>
public string Jsonrpc { get; set; }
/// <summary>
/// Result of the request
/// </summary>
public dynamic Result = new ExpandoObject();
/// <summary>
/// Id of the request
/// </summary>
public int Id { get; set; }
}
}

View File

@@ -0,0 +1,22 @@

namespace EonaCat.Logger.Servers.Zabbix
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
/// <summary>
/// Zabbix server.
/// </summary>
public class ZabbixData
{
public string Host { get; set; }
public string Key { get; set; }
public string Value { get; set; }
public ZabbixData(string host, string key, string value)
{
Host = host;
Key = key;
Value = value;
}
}
}

View File

@@ -0,0 +1,79 @@
using EonaCat.Json;
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace EonaCat.Logger.Servers.Zabbix
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
public class ZabbixRequest
{
private const int BUFFER_SIZE = 1024;
/// <summary>
/// The request to send to the Zabbix server
/// </summary>
public string Request { get; set; }
/// <summary>
/// The data to send to the Zabbix server
/// </summary>
public ZabbixData[] Data { get; set; }
public ZabbixRequest(string host, string key, string value)
{
Request = "sender data";
Data = [new ZabbixData(host, key, value)];
}
/// <summary>
/// Sends the request to the Zabbix server
/// </summary>
/// <param name="server"></param>
/// <param name="port"></param>
/// <param name="timeout"></param>
/// <returns></returns>
/// <exception cref="TimeoutException"></exception>
public async Task<ZabbixResponse> SendAsync(string server, int port = 10051, int timeout = 500)
{
string json = JsonHelper.ToJson(new ZabbixRequest(Data[0].Host, Data[0].Key, Data[0].Value));
using (TcpClient tcpClient = new TcpClient(server, port))
using (NetworkStream stream = tcpClient.GetStream())
{
byte[] header = Encoding.ASCII.GetBytes("ZBXD\x01");
byte[] dataLength = BitConverter.GetBytes((long)json.Length);
byte[] content = Encoding.ASCII.GetBytes(json);
byte[] message = new byte[header.Length + dataLength.Length + content.Length];
Buffer.BlockCopy(header, 0, message, 0, header.Length);
Buffer.BlockCopy(dataLength, 0, message, header.Length, dataLength.Length);
Buffer.BlockCopy(content, 0, message, header.Length + dataLength.Length, content.Length);
stream.Write(message, 0, message.Length);
stream.Flush();
int counter = 0;
while (!stream.DataAvailable)
{
if (counter < timeout / 50)
{
counter++;
await Task.Delay(50).ConfigureAwait(false);
}
else
{
throw new TimeoutException();
}
}
byte[] responseBytes = new byte[BUFFER_SIZE];
stream.Read(responseBytes, 0, responseBytes.Length);
string responseAsString = Encoding.UTF8.GetString(responseBytes);
string jsonResult = responseAsString.Substring(responseAsString.IndexOf('{'));
return JsonHelper.ToObject<ZabbixResponse>(jsonResult);
}
}
}
}

View File

@@ -0,0 +1,11 @@
namespace EonaCat.Logger.Servers.Zabbix
{
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
public class ZabbixResponse
{
public string Response { get; set; }
public string Info { get; set; }
}
}