Skip to content

Commit

Permalink
Version 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mtonosaki committed Jan 23, 2020
1 parent cd33aa6 commit 84f8043
Show file tree
Hide file tree
Showing 25 changed files with 1,047 additions and 2 deletions.
Binary file added @Res/16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added @Res/32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added @Res/48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added @Res/64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added @Res/96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added @Res/SyslogAzureMonitorBridge.psd
Binary file not shown.
Binary file added @Res/SyslogAzureMonitorBridgeIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
# SyslogAzureMonitorBridge
Windows Service of Syslog listener and send the messages to Azure Monitor
# SyslogAzureMonitorBridge
Windows Service of Syslog listener and send the messages to Azure Monitor

![](https://aqtono.com/tomarika/syslogazure/SyslogAzureMonitorBridgeIcon.png)

## Development environment
Visual Studio, .NET Framework 4.7.2, Windows Service

## How to install

### Register as a Windwos Service
in windows command prompt (cmd.exe administrator mode)
sc create SyslogAzureMonitorBridge binpath=<full path name of the SyslogAzureMonitorBridge.exe>

### Setup your Azure environment
todo:

### Start the Service
sc start SyslogAzureMonitorBridge
6 changes: 6 additions & 0 deletions SyslogAzureMonitorBridge/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>
164 changes: 164 additions & 0 deletions SyslogAzureMonitorBridge/AzureUploader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tono;

namespace SyslogAzureMonitorBridge
{
public class AzureUploader
{
public string WorkspaceID { get; set; }
public string Key1 { get; set; }
public string LogName { get; set; } = "Syslog";
public Action<string, bool> Logger { get; set; }

public Func<Queue<SyslogMessageEventArgs>> Messages { get; set; }

public async Task PorlingMessagesAsync(CancellationToken cancellationToken)
{
while (cancellationToken.IsCancellationRequested == false)
{
await Task.Delay(5000, cancellationToken);

var queue = Messages?.Invoke();
List<SyslogMessageEventArgs> chunk;

lock (queue)
{
chunk = queue.ToList();
queue.Clear();
}
if (chunk.Count < 1)
{
continue;
}
var recs = new List<LogRecord>();
foreach (var ev in chunk)
{
// <189>[INSPECT] LAN2[out][101100] TCP 192.168.20.3:54874 > 172.217.25.193:443 (2020/01/23 14:12:42)
// <190>[NAT(1000):LAN2] Released UDP 172.16.20.3.44249 <-> 192.168.20.254.10708 ==> 172.16.20.1.53
var rec = new LogRecord();
var pristr = StrUtil.LeftOn(ev.Message, "^<[0-9]+>");
if (pristr.Length > 2)
{
// Priority = facility * 8 + severity level ex. 190 = 23*8+6
var pri = int.Parse(StrUtil.Mid(pristr, 1, pristr.Length - 2));
rec.Facility = Facilities.GetValueOrDefault(pri / 8, "n/a");
rec.SeverityLevel = SeverityLevels.GetValueOrDefault(pri % 8, "n/a");
}
rec.EventTime = ev.EventUtcTime;
rec.HostIP = ev.Remote.Address.ToString();
rec.HostName = /* Dns.GetHostEntry(ev.Remote.Address)?.HostName ?? */ ev.Remote.Address.ToString(); // Do not use Dns.GetHostEntry because of block 5 seconds each for local IPs.
rec.Computer = rec.HostName;
rec.SyslogMessage = StrUtil.MidSkip(ev.Message, "^<[0-9]+>").TrimStart(' ', '\t', '\r', '\n', '\b');
recs.Add(rec);
}
var jsonStr = JsonConvert.SerializeObject(recs, new IsoDateTimeConverter());
var datestring = DateTime.UtcNow.ToString("r");
var jsonBytes = Encoding.UTF8.GetBytes(jsonStr);
var stringToHash = "POST\n" + jsonBytes.Length + "\napplication/json\n" + "x-ms-date:" + datestring + "\n/api/logs";
var hashedString = BuildSignature(stringToHash, Key1);
var signature = "SharedKey " + WorkspaceID + ":" + hashedString;
PostData(signature, datestring, jsonStr);
}
}

public string BuildSignature(string message, string secret)
{
var encoding = new ASCIIEncoding();
var keyByte = Convert.FromBase64String(secret);
var messageBytes = encoding.GetBytes(message);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
var hash = hmacsha256.ComputeHash(messageBytes);
return Convert.ToBase64String(hash);
}
}

public void PostData(string signature, string date, string json)
{
try
{
var url = "https://" + WorkspaceID + ".ods.opinsights.azure.com/api/logs?api-version=2016-04-01";

var client = new HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("Log-Type", LogName);
client.DefaultRequestHeaders.Add("Authorization", signature);
client.DefaultRequestHeaders.Add("x-ms-date", date);
client.DefaultRequestHeaders.Add("time-generated-field", "");

var httpContent = new StringContent(json, Encoding.UTF8);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = client.PostAsync(new Uri(url), httpContent);

var responseContent = response.Result.Content;
string result = responseContent.ReadAsStringAsync().Result;
}
catch (Exception excep)
{
Logger?.Invoke("API Post Exception: " + excep.Message, true);
}
}

public static readonly Dictionary<int, string> Facilities = new Dictionary<int, string>
{
[0] = "kern",
[1] = "user",
[2] = "mail",
[3] = "daemon",
[4] = "auth",
[5] = "syslog",
[6] = "lpr",
[7] = "news",
[8] = "uucp",
[9] = "cron",
[10] = "authpriv",
[11] = "ftp",
[12] = "ntp",
[13] = "audit", // log audit
[14] = "alert", // log alert
[15] = "clock", // clock daemon
[16] = "local0",
[17] = "local1",
[18] = "local2",
[19] = "local3",
[20] = "local4",
[21] = "local5",
[22] = "local6",
[23] = "local7",
};

public static readonly Dictionary<int, string> SeverityLevels = new Dictionary<int, string>
{
[0] = "emerg",
[1] = "alert",
[2] = "crit",
[3] = "err",
[4] = "warning",
[5] = "notice",
[6] = "info",
[7] = "debug",
};

public class LogRecord
{
public string Facility { get; set; }
public string SeverityLevel { get; set; }
public DateTime EventTime { get; set; } // 2020-01-21T22:33:33Z
public string Computer { get; set; }
public string HostIP { get; set; }
public string HostName { get; set; }
public string SyslogMessage { get; set; }

};
}
}
67 changes: 67 additions & 0 deletions SyslogAzureMonitorBridge/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Configuration.Install;
using System.Linq;
using System.Reflection;
using System.ServiceProcess;

namespace SyslogAzureMonitorBridge
{
internal static class Program
{
/// <summary>
/// Program entry point
/// </summary>
/// <param name="args">
/// -----
/// /i : Register this service to Windows Service
/// /u : Uninstall this service to Windows Service
/// -----
/// /n=MySyslog : $table name. ex.MySyslog --> MySyslog_CL
/// /p=514 : Listening port number of syslog
/// /w=12345678-abcd-ef01-2345-123456789012 : Work Space ID of Azure LogAnalytics
/// /k=99aXaEa1C4OXL/EJVBqDH87qF9fHYE4XfGpKnJO/UCPv3xg/n6pAb7k6wSKFE+i40BSRuE0Apo3oP2W8G9nWXr== : Main key (ARM -> LogAnalytics -> Detail -> Connected Sources -> Windows Servers -> Key1
/// </param>
private static void Main(string[] args)
{
var service = new SyslogAzureMonitorBridge();

if (Environment.UserInteractive) // Console Version
{
if (args.Length > 0)
{
var isServiceExists = ServiceController.GetServices().Any(s => s.ServiceName == service.ServiceName);
var path = Assembly.GetExecutingAssembly().Location;
switch (args[0].ToLower())
{
case "/i":
if (isServiceExists)
{
Console.WriteLine($"The service '{service.ServiceName}' has already registered.");
}
else
{
ManagedInstallerClass.InstallHelper(new[] { path });
}
return;
case "/u":
if (isServiceExists)
{
ManagedInstallerClass.InstallHelper(new[] { "/u", path });
}
else
{
Console.WriteLine($"The service '{service.ServiceName}' is not installed yet.");
}
return;
}
}
service.OnStartConsole(args);
service.OnStopConsole();
}
else
{
ServiceBase.Run(new ServiceBase[] { service });
}
}
}
}
13 changes: 13 additions & 0 deletions SyslogAzureMonitorBridge/ProjectInstaller.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.ComponentModel;

namespace SyslogAzureMonitorBridge
{
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
InitializeComponent();
}
}
}
59 changes: 59 additions & 0 deletions SyslogAzureMonitorBridge/ProjectInstaller.designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 84f8043

Please sign in to comment.