├── StreamExtended
├── StrongKey.snk
├── Properties
│ └── AssemblyInfo.cs
├── BufferPool
│ ├── IBufferPool.cs
│ └── DefaultBufferPool.cs
├── Network
│ ├── ICustomStreamWriter.cs
│ ├── DataEventArgs.cs
│ ├── ICustomStreamReader.cs
│ ├── CopyStream.cs
│ ├── ServerHelloAlpnAdderStream.cs
│ ├── ClientHelloAlpnAdderStream.cs
│ └── CustomBufferedPeekStream.cs
├── StreamExtended.Mono.csproj
├── StreamExtended.csproj
├── StreamExtended.NetCore.csproj
├── StreamExtended.nuspec
├── TaskExtended.cs
├── Models
│ └── SslExtension.cs
├── StreamExtended.Docs.csproj
├── ServerHelloInfo.cs
└── ClientHelloInfo.cs
├── SyslogParser
├── source.txt
├── SyslogParser.csproj
├── Code
│ ├── EverythingListener.cs
│ ├── RfcVisitor.cs
│ └── CaseChangingCharStream.cs
└── ParsingHelper.cs
├── SimpleTcpServer
├── SimpleTcpServer.csproj
├── Program.cs
├── TcpEchoClient.cs
└── TcpEchoServer.cs
├── libSyslogServer
├── libSyslogServer.csproj
├── Classes
│ ├── Settings.cs
│ └── Common.cs
├── ReceiverThread.cs
├── WriterTask.cs
└── SyslogServer.cs
├── SyslogServer
├── Common
│ ├── SeverityType.cs
│ ├── FacilityType.cs
│ ├── Rfc3164SyslogMessage.cs
│ ├── Rfc5424SyslogMessage.cs
│ └── MessageHandler.cs
├── SyslogServer.csproj
├── SyslogServer.cs
├── UpdSyslogServer.cs
├── TcpSyslogServer.cs
├── syslog_info.txt
├── TlsSyslogServer.cs
└── Program.cs
├── SelfSignedCertificate
├── SelfSignedCertificate.csproj
└── Helpers
│ ├── KeyValuePairList.cs
│ ├── StringStream.cs
│ ├── NonBackdooredPrng.cs
│ └── CertificateInfo.cs
├── SimpleTlsServer
├── SimpleTlsServer.csproj
└── Program.cs
├── NetCoreServer
├── NetCoreServer.csproj
├── HttpServer.cs
├── HttpsServer.cs
├── SslContext.cs
├── IWebSocket.cs
├── WsServer.cs
├── WssServer.cs
├── Buffer.cs
├── Utilities.cs
├── HttpSession.cs
└── HttpsSession.cs
├── LICENSE.TXT
├── README.md
├── .gitattributes
├── NetCoreSyslogServer.sln
└── .gitignore
/StreamExtended/StrongKey.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ststeiger/NetCoreSyslogServer/HEAD/StreamExtended/StrongKey.snk
--------------------------------------------------------------------------------
/StreamExtended/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ststeiger/NetCoreSyslogServer/HEAD/StreamExtended/Properties/AssemblyInfo.cs
--------------------------------------------------------------------------------
/SyslogParser/source.txt:
--------------------------------------------------------------------------------
1 |
2 | https://raw.githubusercontent.com/ottobackwards/grok-v-antlr/master/src/main/antlr4/org/ottobackwards/dsl/generated/Rfc5424.g4
3 |
--------------------------------------------------------------------------------
/SimpleTcpServer/SimpleTcpServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SyslogParser/SyslogParser.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/libSyslogServer/libSyslogServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SyslogServer/Common/SeverityType.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SyslogServer
3 | {
4 |
5 | public enum SeverityType
6 | {
7 | Emergency
8 | , Alert
9 | , Critical
10 | , Error
11 | , Warning
12 | , Notice
13 | , Informational
14 | , Debug
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/SyslogServer/Common/FacilityType.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SyslogServer
3 | {
4 |
5 | public enum FacilityType
6 | {
7 | Kern, User, Mail, Daemon, Auth, Syslog, LPR
8 | , News, UUCP, Cron, AuthPriv, FTP, NTP, Audit, Audit2, CRON2
9 | , Local0, Local1, Local2, Local3, Local4, Local5, Local6, Local7
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/SelfSignedCertificate/SelfSignedCertificate.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleTlsServer/SimpleTlsServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net5.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SimpleTlsServer/Program.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SimpleTlsServer
3 | {
4 |
5 |
6 | class Program
7 | {
8 |
9 |
10 | static void Main(string[] args)
11 | {
12 | ExampleTlsServer.Test();
13 | System.Console.WriteLine(" --- Press any key to continue --- ");
14 | System.Console.ReadKey();
15 | } // End Sub Main
16 |
17 |
18 | } // End Class Program
19 |
20 |
21 | } // End Namespace
22 |
--------------------------------------------------------------------------------
/StreamExtended/BufferPool/IBufferPool.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace StreamExtended
4 | {
5 | ///
6 | /// Use this interface to implement custom buffer pool.
7 | /// To use the default buffer pool implementation use DefaultBufferPool class.
8 | ///
9 | public interface IBufferPool : IDisposable
10 | {
11 | byte[] GetBuffer(int bufferSize);
12 | void ReturnBuffer(byte[] buffer);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/SimpleTcpServer/Program.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SimpleTcpServer
3 | {
4 |
5 |
6 | class Program
7 | {
8 |
9 |
10 | static void Main(string[] args)
11 | {
12 | _ = TcpEchoServer.Test();
13 | TcpEchoClient.Test();
14 |
15 | System.Console.WriteLine(" --- Press any key to continue --- ");
16 | System.Console.ReadKey();
17 | } // End Sub Main
18 |
19 |
20 | } // End Class Program
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/SyslogParser/Code/EverythingListener.cs:
--------------------------------------------------------------------------------
1 |
2 | using SyslogServer.grammars;
3 |
4 |
5 | namespace SyslogParser
6 | {
7 |
8 | public class EverythingListener
9 | : Rfc5424BaseListener
10 | {
11 |
12 | public override void EnterEveryRule([Antlr4.Runtime.Misc.NotNull] Antlr4.Runtime.ParserRuleContext context)
13 | {
14 | string s = context.GetText();
15 | System.Console.WriteLine(s);
16 |
17 | }
18 | }
19 |
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/SyslogServer/SyslogServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net5.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/StreamExtended/Network/ICustomStreamWriter.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace StreamExtended.Network
5 | {
6 | ///
7 | /// A concrete implementation of this interface is required when calling CopyStream.
8 | ///
9 | public interface ICustomStreamWriter
10 | {
11 | void Write(byte[] buffer, int i, int bufferLength);
12 |
13 | Task WriteAsync(byte[] buffer, int i, int bufferLength, CancellationToken cancellationToken);
14 | }
15 | }
--------------------------------------------------------------------------------
/StreamExtended/StreamExtended.Mono.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net45
5 | True
6 | StrongKey.snk
7 | 1.0.0
8 | false
9 | Package Description
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/StreamExtended/StreamExtended.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net45;netstandard1.3
5 | True
6 | StrongKey.snk
7 | 1.0.0
8 | false
9 | Package Description
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/StreamExtended/StreamExtended.NetCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard1.3
5 | True
6 | StrongKey.snk
7 | 1.0.0
8 | false
9 | Package Description
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/libSyslogServer/Classes/Settings.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace libSyslogServer
3 | {
4 |
5 |
6 | public class Settings
7 | {
8 | public string Version { get; set; }
9 | public int UdpPort { get; set; }
10 | public bool DisplayTimestamps { get; set; }
11 | public string LogFileDirectory { get; set; }
12 | public string LogFilename { get; set; }
13 | public int LogWriterIntervalSec { get; set; }
14 |
15 | public static Settings Default()
16 | {
17 | Settings ret = new Settings();
18 | ret.Version = "Watson Syslog Server v1.0.1";
19 | ret.UdpPort = 514;
20 | ret.DisplayTimestamps = false;
21 | ret.LogFileDirectory = "logs\\";
22 | ret.LogFilename = "log.txt";
23 | ret.LogWriterIntervalSec = 10;
24 | return ret;
25 | }
26 | }
27 |
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/StreamExtended/Network/DataEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace StreamExtended.Network
4 | {
5 | ///
6 | /// Wraps the data sent/received event argument.
7 | ///
8 | public class DataEventArgs : EventArgs
9 | {
10 | public DataEventArgs(byte[] buffer, int offset, int count)
11 | {
12 | Buffer = buffer;
13 | Offset = offset;
14 | Count = count;
15 | }
16 |
17 | ///
18 | /// The buffer with data.
19 | ///
20 | public byte[] Buffer { get; }
21 |
22 | ///
23 | /// Offset in buffer from which valid data begins.
24 | ///
25 | public int Offset { get; }
26 |
27 | ///
28 | /// Length from offset in buffer with valid data.
29 | ///
30 | public int Count { get; }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/StreamExtended/StreamExtended.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | StreamExtended
5 | $version$
6 | Extended SslStream
7 | honfika, justcoding121
8 |
9 | https://github.com/justcoding121/Stream-Extended/blob/master/LICENSE
10 | https://github.com/justcoding121/Stream-Extended
11 | false
12 | SNI for SslStream.
13 |
14 | Copyright © Stream-Extended All rights reserved.
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/StreamExtended/TaskExtended.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace StreamExtended
9 | {
10 | ///
11 | /// Mimic a Task but you can set AsyncState
12 | ///
13 | ///
14 | public class TaskResult : IAsyncResult
15 | {
16 | Task Task;
17 | object mAsyncState;
18 |
19 | public TaskResult(Task pTask, object state)
20 | {
21 | Task = pTask;
22 | mAsyncState = state;
23 | }
24 |
25 | public object AsyncState => mAsyncState;
26 | public WaitHandle AsyncWaitHandle => ((IAsyncResult)Task).AsyncWaitHandle;
27 | public bool CompletedSynchronously => ((IAsyncResult)Task).CompletedSynchronously;
28 | public bool IsCompleted => Task.IsCompleted;
29 | public T Result => Task.Result;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/NetCoreServer/NetCoreServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | 5.0.7.0
6 | Ivan Shynkarenka
7 | Copyright (c) 2019-2021 Ivan Shynkarenka
8 | https://github.com/chronoxor/NetCoreServer
9 | Ultra fast and low latency asynchronous socket server & client C# .NET Core library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K connections problem solution
10 | MIT
11 | https://github.com/chronoxor/NetCoreServer
12 | async;client;server;tcp;udp;ssl;tls;http;https;websocket;low latency;performance
13 |
14 |
15 |
16 | true
17 | snupkg
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2016 Marauder Software Inc
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/SyslogParser/Code/RfcVisitor.cs:
--------------------------------------------------------------------------------
1 |
2 | using Antlr4.Runtime.Misc;
3 | using SyslogServer.grammars;
4 |
5 |
6 | namespace SyslogParser
7 | {
8 |
9 | public class RfcVisitor
10 | : Rfc5424BaseVisitor
11 | {
12 |
13 |
14 | public override string VisitHeaderVersion([NotNull] Rfc5424Parser.HeaderVersionContext context)
15 | {
16 | string s = base.VisitChildren(context);
17 | return s;
18 | }
19 |
20 |
21 | public override string VisitHeaderAppName([NotNull] Rfc5424Parser.HeaderAppNameContext context)
22 | {
23 | string s = VisitChildren(context);
24 | return s;
25 | }
26 |
27 |
28 | public override string VisitHeaderNilAppName([NotNull] Rfc5424Parser.HeaderNilAppNameContext context)
29 | {
30 | string s = base.VisitChildren(context);
31 | return s;
32 | }
33 |
34 |
35 | public override string Visit([Antlr4.Runtime.Misc.NotNull]
36 | Antlr4.Runtime.Tree.IParseTree tree)
37 | {
38 | string t = tree.GetText();
39 | System.Console.WriteLine(t);
40 |
41 | return base.Visit(tree);
42 | }
43 |
44 | }
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/SimpleTcpServer/TcpEchoClient.cs:
--------------------------------------------------------------------------------
1 | // This code is adapted from a sample found at the URL
2 | // "http://blogs.msdn.com/b/jmanning/archive/2004/12/19/325699.aspx"
3 |
4 | // https://thiscouldbebetter.wordpress.com/2015/01/13/an-echo-server-and-client-in-c-using-tcplistener-and-tcpclient/
5 | namespace SimpleTcpServer
6 | {
7 |
8 |
9 | public class TcpEchoClient
10 | {
11 |
12 |
13 | public static void Test()
14 | {
15 | System.Console.WriteLine("Starting echo client...");
16 |
17 | int port = 1234;
18 | System.Net.Sockets.TcpClient client =
19 | new System.Net.Sockets.TcpClient("localhost", port);
20 |
21 | System.Net.Sockets.NetworkStream stream = client.GetStream();
22 |
23 | System.IO.StreamReader reader = new System.IO.StreamReader(stream);
24 | System.IO.StreamWriter writer = new System.IO.StreamWriter(stream)
25 | { AutoFlush = true };
26 |
27 | while (true)
28 | {
29 | System.Console.Write("Enter text to send: ");
30 | string lineToSend = System.Console.ReadLine();
31 | System.Console.WriteLine("Sending to server: " + lineToSend);
32 | writer.WriteLine(lineToSend);
33 | string lineReceived = reader.ReadLine();
34 | System.Console.WriteLine("Received from server: " + lineReceived);
35 | } // Whend
36 | } // End Sub Test
37 |
38 |
39 | } // End Class TcpEchoClient
40 |
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/SelfSignedCertificate/Helpers/KeyValuePairList.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SelfSignedCertificate
3 | {
4 |
5 |
6 | public class KeyValuePairList
7 | : System.Collections.Generic.List>
8 | {
9 | public void Add(TKey key, TValue value)
10 | {
11 | this.Add(new System.Collections.Generic.KeyValuePair(key, value));
12 | }
13 |
14 | public System.Collections.Generic.List Keys
15 | {
16 | get
17 | {
18 |
19 | System.Collections.Generic.List ls
20 | = new System.Collections.Generic.List();
21 |
22 | for (int i = 0; i < this.Count; ++i)
23 | {
24 | ls.Add(this[i].Key);
25 | }
26 |
27 | return ls;
28 | }
29 | }
30 |
31 | public System.Collections.Generic.List Values
32 | {
33 | get
34 | {
35 | System.Collections.Generic.List ls
36 | = new System.Collections.Generic.List();
37 |
38 | for (int i = 0; i < this.Count; ++i)
39 | {
40 | ls.Add(this[i].Value);
41 | }
42 |
43 | return ls;
44 | }
45 | }
46 |
47 | }
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/StreamExtended/BufferPool/DefaultBufferPool.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Concurrent;
2 |
3 | namespace StreamExtended
4 | {
5 |
6 | ///
7 | /// A concrete IBufferPool implementation using a thread-safe stack.
8 | /// Works well when all consumers ask for buffers with the same size.
9 | /// If your application would use variable size buffers consider implementing IBufferPool using System.Buffers library from Microsoft.
10 | ///
11 | public class DefaultBufferPool : IBufferPool
12 | {
13 | private readonly ConcurrentStack buffers = new ConcurrentStack();
14 |
15 | ///
16 | /// Gets a buffer.
17 | ///
18 | /// Size of the buffer.
19 | ///
20 | public byte[] GetBuffer(int bufferSize)
21 | {
22 | if (!buffers.TryPop(out var buffer) || buffer.Length != bufferSize)
23 | {
24 | buffer = new byte[bufferSize];
25 | }
26 |
27 | return buffer;
28 | }
29 |
30 | ///
31 | /// Returns the buffer.
32 | ///
33 | /// The buffer.
34 | public void ReturnBuffer(byte[] buffer)
35 | {
36 | if (buffer != null)
37 | {
38 | buffers.Push(buffer);
39 | }
40 | }
41 |
42 | public void Dispose()
43 | {
44 | buffers.Clear();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/StreamExtended/Models/SslExtension.cs:
--------------------------------------------------------------------------------
1 | namespace StreamExtended.Models
2 | {
3 | ///
4 | /// The SSL extension information.
5 | ///
6 | public class SslExtension
7 | {
8 | ///
9 | /// Gets the value.
10 | ///
11 | ///
12 | /// The value.
13 | ///
14 | public int Value { get; }
15 |
16 | ///
17 | /// Gets the name.
18 | ///
19 | ///
20 | /// The name.
21 | ///
22 | public string Name { get; }
23 |
24 | ///
25 | /// Gets the data.
26 | ///
27 | ///
28 | /// The data.
29 | ///
30 | public string Data { get; }
31 |
32 | ///
33 | /// Gets the position.
34 | ///
35 | ///
36 | /// The position.
37 | ///
38 | public int Position { get; }
39 |
40 | ///
41 | /// Initializes a new instance of the class.
42 | ///
43 | /// The value.
44 | /// The name.
45 | /// The data.
46 | /// The position.
47 | public SslExtension(int value, string name, string data, int position)
48 | {
49 | Value = value;
50 | Name = name;
51 | Data = data;
52 | Position = position;
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/SimpleTcpServer/TcpEchoServer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SimpleTcpServer
3 | {
4 |
5 |
6 | // This code is adapted from a sample found at the URL
7 | // "http://blogs.msdn.com/b/jmanning/archive/2004/12/19/325699.aspx"
8 |
9 |
10 | // https://thiscouldbebetter.wordpress.com/2015/01/13/an-echo-server-and-client-in-c-using-tcplistener-and-tcpclient/
11 | public class TcpEchoServer
12 | {
13 |
14 |
15 | public static async System.Threading.Tasks.Task Test()
16 | {
17 | System.Console.WriteLine("Starting echo server...");
18 |
19 | int port = 1234;
20 | System.Net.IPAddress listenerAddress = System.Net.IPAddress.Loopback;
21 |
22 | System.Net.Sockets.TcpListener listener =
23 | new System.Net.Sockets.TcpListener(listenerAddress, port);
24 |
25 | listener.Start();
26 |
27 | System.Net.Sockets.TcpClient client = await listener.AcceptTcpClientAsync();
28 | System.Net.Sockets.NetworkStream stream = client.GetStream();
29 | System.IO.StreamWriter writer = new System.IO.StreamWriter(stream, System.Text.Encoding.ASCII)
30 | { AutoFlush = true };
31 |
32 | System.IO.StreamReader reader = new System.IO.StreamReader(stream, System.Text.Encoding.ASCII);
33 |
34 | while (true)
35 | {
36 | string inputLine = "";
37 | while (inputLine != null)
38 | {
39 | inputLine = await reader.ReadLineAsync();
40 | await writer.WriteLineAsync("Echoing string: " + inputLine);
41 | System.Console.WriteLine("Echoing string: " + inputLine);
42 | }
43 |
44 | System.Console.WriteLine("Server saw disconnect from client.");
45 | }
46 | } // End Task Test
47 |
48 |
49 | } // End Class TcpEchoServer
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/libSyslogServer/ReceiverThread.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace libSyslogServer
3 | {
4 |
5 |
6 | public partial class SyslogServer
7 | {
8 |
9 |
10 | static void ReceiverThread()
11 | {
12 | if (_ListenerUdp == null) _ListenerUdp =
13 | new System.Net.Sockets.UdpClient(_Settings.UdpPort);
14 |
15 | try
16 | {
17 |
18 | System.Net.IPEndPoint endpoint =
19 | new System.Net.IPEndPoint(System.Net.IPAddress.Any, _Settings.UdpPort);
20 |
21 | string receivedData;
22 | byte[] receivedBytes;
23 |
24 | while (true)
25 | {
26 |
27 | receivedBytes = _ListenerUdp.Receive(ref endpoint);
28 | // Encoding.ASCII ?
29 | receivedData = System.Text.Encoding.ASCII.GetString(receivedBytes, 0, receivedBytes.Length);
30 | string msg = null;
31 | if (_Settings.DisplayTimestamps) msg = System.DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + " ";
32 | msg += receivedData;
33 | System.Console.WriteLine(msg);
34 |
35 |
36 | lock (_WriterLock)
37 | {
38 | _MessageQueue.Add(msg);
39 | }
40 |
41 | }
42 |
43 |
44 | }
45 | catch (System.Exception e)
46 | {
47 | _ListenerUdp.Close();
48 | _ListenerUdp = null;
49 | System.Console.WriteLine("***");
50 | System.Console.WriteLine("ReceiverThread exiting due to exception: " + e.Message);
51 | return;
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NetCore Syslog Server
2 |
3 |
4 | ## Simple Syslog Server in C#
5 |
6 |
7 | ## Watson Syslog Server
8 |
9 | This project is based on Watson Syslog Server.
10 | Moved Watson Syslog Server to libSyslogServer for reference.
11 | Watson Syslog Server will automatically start using a default configuration listening on UDP/514 and storing log files in the ```logs\``` directory.
12 | If you wish to change this, create a file called ```syslog.json``` with the following structure:
13 | ```
14 | {
15 | "Version": "Watson Syslog Server v1.0.0",
16 | "UdpPort": 514,
17 | "DisplayTimestamps": true,
18 | "LogFileDirectory": "logs\\",
19 | "LogFilename": "log.txt",
20 | "LogWriterIntervalSec": 10
21 | }
22 | ```
23 |
24 |
25 | ## Starting the Server
26 |
27 | Build/compile and run the binary.
28 |
29 | ## Running under Windows Linux and MacOS
30 |
31 | This application should work well in all NetCore environments.
32 | Tested on:
33 | - Windows 10
34 | - Linux (Ubuntu 20.04 LTS "Focal Fossa" x64)
35 | - OSX (10.13 "High Sierra")
36 |
37 |
38 |
39 | ## Running under Mono
40 |
41 | This app should work well in Mono environments.
42 | It is recommended that when running under Mono, you execute the containing EXE using --server and after using the Mono Ahead-of-Time Compiler (AOT).
43 | ```
44 | mono --aot=nrgctx-trampolines=8096,nimt-trampolines=8096,ntrampolines=4048 --server myapp.exe
45 | mono --server myapp.exe
46 | ```
47 |
48 |
49 | ## Help or Feedback
50 |
51 | Do you need help or have feedback?
52 | See the "issues" tab.
53 |
54 | ## New in v2.0.0
55 |
56 | - Dependency on NetCoreServer
57 | - Support for 10'000 concurrent connections
58 | - Support for TCP
59 | - Support for TLS (Note TLS 1.2 REQUIRED, TLS 1 only supported if you modify the source)
60 | - Working Client for TLS (see https://github.com/ststeiger/SyslogNet)
61 |
62 | ## New in v1.0.0
63 |
64 | - Initial release, support for UDP
65 |
--------------------------------------------------------------------------------
/SyslogServer/SyslogServer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SyslogServer
3 | {
4 |
5 | public enum NetworkProtocol
6 | {
7 | UPD,
8 | TCP,
9 | TLS
10 | } // End Enum NetworkProtocol
11 |
12 |
13 | // TODO: create a composite-class for a general syslog server
14 | class SyslogServer
15 | {
16 |
17 | protected TlsSyslogServer TlsServer;
18 | protected UpdSyslogServer UdpServer;
19 | protected TcpSyslogServer TcpServer;
20 |
21 | protected NetCoreServer.SslSession Session;
22 | protected SyslogTcpSession TcpSession;
23 |
24 | public int Port;
25 |
26 |
27 | public SyslogServer()
28 | {
29 |
30 | } // End Constructor
31 |
32 |
33 | public void Start(NetworkProtocol protocol, System.Net.IPAddress address, int port)
34 | {
35 | switch (protocol)
36 | {
37 | case NetworkProtocol.TCP:
38 | TcpSyslogServer.Test();
39 | break;
40 | case NetworkProtocol.TLS:
41 | TlsSyslogServer.Test();
42 | break;
43 | default:
44 | UpdSyslogServer.Test();
45 | break;
46 | }
47 |
48 | } // End Sub Start
49 |
50 |
51 | public void Start(NetworkProtocol protocol, System.Net.IPAddress address)
52 | {
53 | this.Port = 514; // UDP
54 |
55 | switch (protocol)
56 | {
57 | case NetworkProtocol.TCP:
58 | this.Port = 1468; // TCP
59 | break;
60 | case NetworkProtocol.TLS:
61 | this.Port = 6514; // TLS
62 | break;
63 | }
64 |
65 | Start(protocol, address, this.Port);
66 | } // End Sub Start
67 |
68 |
69 | public void Stop()
70 | {
71 |
72 | } // End Sub Stop
73 |
74 |
75 | } // End Class SyslogServer
76 |
77 |
78 | } // End Namespace SyslogServer
79 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/libSyslogServer/WriterTask.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace libSyslogServer
3 | {
4 |
5 |
6 | public partial class SyslogServer
7 | {
8 | static void WriterTask()
9 | {
10 | try
11 | {
12 | while (true)
13 | {
14 | System.Threading.Tasks.Task.Delay(1000).Wait();
15 |
16 | if (System.DateTime.Compare(_LastWritten.AddSeconds(_Settings.LogWriterIntervalSec), System.DateTime.Now) < 0)
17 | {
18 | lock (_WriterLock)
19 | {
20 | if (_MessageQueue == null || _MessageQueue.Count < 1)
21 | {
22 | _LastWritten = System.DateTime.Now;
23 | continue;
24 | }
25 |
26 | foreach (string currMessage in _MessageQueue)
27 | {
28 | string currFilename = _Settings.LogFileDirectory + System.DateTime.Now.ToString("MMddyyyy") + "-" + _Settings.LogFilename;
29 |
30 | if (!System.IO.File.Exists(currFilename))
31 | {
32 | System.Console.WriteLine("Creating file: " + currFilename + System.Environment.NewLine);
33 | {
34 | using (System.IO.FileStream fsCreate =
35 | System.IO.File.Create(currFilename))
36 | {
37 | byte[] createData = new System.Text.UTF8Encoding(true).GetBytes("--- Creating log file at " + System.DateTime.Now + " ---" + System.Environment.NewLine);
38 | fsCreate.Write(createData, 0, createData.Length);
39 | }
40 | }
41 | }
42 |
43 | using (System.IO.StreamWriter swAppend =
44 | System.IO.File.AppendText(currFilename))
45 | {
46 | swAppend.WriteLine(currMessage);
47 | }
48 | }
49 |
50 | _LastWritten = System.DateTime.Now;
51 | _MessageQueue = new System.Collections.Generic.List();
52 | }
53 | }
54 | }
55 | }
56 | catch (System.Exception e)
57 | {
58 | System.Console.WriteLine("***");
59 | System.Console.WriteLine("WriterTask exiting due to exception: " + e.Message);
60 | System.Environment.Exit(-1);
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/SyslogParser/ParsingHelper.cs:
--------------------------------------------------------------------------------
1 |
2 | // using Antlr4.Runtime.Misc;
3 | using SyslogServer.grammars;
4 |
5 |
6 | namespace SyslogParser
7 | {
8 |
9 |
10 | internal class ParsingHelper
11 | {
12 |
13 |
14 | public static System.Collections.Generic.List LexWithAntlr(string text)
15 | {
16 | System.Collections.Generic.List ls = new System.Collections.Generic.List();
17 |
18 | System.IO.StringReader reader = new System.IO.StringReader(text);
19 |
20 | // Antlr4.Runtime.AntlrInputStream input = new Antlr4.Runtime.AntlrInputStream(reader);
21 |
22 | Antlr4.Runtime.ICharStream input1 = new Antlr4.Runtime.AntlrInputStream(reader);
23 | Antlr4.Runtime.CaseChangingCharStream input = new Antlr4.Runtime.CaseChangingCharStream(input1, true);
24 |
25 |
26 |
27 | Rfc5424Lexer lexer = new Rfc5424Lexer(input);
28 |
29 | Antlr4.Runtime.CommonTokenStream tokenStream = new Antlr4.Runtime.CommonTokenStream(lexer);
30 | tokenStream.Fill();
31 |
32 |
33 |
34 |
35 | Rfc5424Parser parser = new Rfc5424Parser(tokenStream);
36 |
37 | Rfc5424Parser.Syslog_msgContext msgContext = parser.syslog_msg();
38 |
39 |
40 | RfcVisitor vis = new RfcVisitor();
41 | string s = vis.Visit(msgContext);
42 |
43 |
44 | Antlr4.Runtime.Tree.ParseTreeWalker walker = new Antlr4.Runtime.Tree.ParseTreeWalker();
45 | // AntlrTsqListener listener = new AntlrTsqListener();
46 | EverythingListener listener = new EverythingListener();
47 |
48 | // walker.Walk(listener, msgContext);
49 |
50 |
51 | // new EverythingListener().EnterBom(parser.bom());
52 | // new EverythingListener().EnterTimestamp(parser.timestamp());
53 | // new EverythingListener().EnterEveryRule(parser.version());
54 | // new EverythingListener().EnterEveryRule(parser.timestamp());
55 |
56 |
57 |
58 | // var x = parser.msg();
59 | var x = parser.timestamp();
60 |
61 |
62 |
63 | Antlr4.Runtime.Misc.Interval msgInt = x.SourceInterval; // new Antlr4.Runtime.Misc.Interval(lastIndex, token.StopIndex);
64 | string extractedMsg = tokenStream.GetText(msgInt);
65 | System.Console.WriteLine(extractedMsg);
66 |
67 |
68 |
69 |
70 | int lastIndex = 0;
71 |
72 | foreach (Antlr4.Runtime.IToken token in tokenStream.GetTokens())
73 | {
74 | // System.Console.WriteLine(token.Text);
75 | string tokenTypeName = lexer.Vocabulary.GetSymbolicName(token.Type);
76 | Antlr4.Runtime.Misc.Interval ival = new Antlr4.Runtime.Misc.Interval(lastIndex, token.StopIndex);
77 | string extracted = token.InputStream.GetText(ival);
78 |
79 | // table_name, cte_name: ID, SQUARE_BRACKET_ID
80 | // Local variables: LOCAL_ID
81 |
82 | lastIndex = token.StopIndex + 1;
83 | } // Next token
84 |
85 | return ls;
86 | }
87 |
88 |
89 | }
90 |
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/NetCoreServer/HttpServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.IO;
4 |
5 | namespace NetCoreServer
6 | {
7 | ///
8 | /// HTTP server is used to create HTTP Web server and communicate with clients using HTTP protocol. It allows to receive GET, POST, PUT, DELETE requests and send HTTP responses.
9 | ///
10 | /// Thread-safe.
11 | public class HttpServer : TcpServer
12 | {
13 | ///
14 | /// Initialize HTTP server with a given IP address and port number
15 | ///
16 | /// IP address
17 | /// Port number
18 | public HttpServer(IPAddress address, int port) : base(address, port) { Cache = new FileCache(); }
19 | ///
20 | /// Initialize HTTP server with a given IP address and port number
21 | ///
22 | /// IP address
23 | /// Port number
24 | public HttpServer(string address, int port) : base(address, port) { Cache = new FileCache(); }
25 | ///
26 | /// Initialize HTTP server with a given IP endpoint
27 | ///
28 | /// IP endpoint
29 | public HttpServer(IPEndPoint endpoint) : base(endpoint) { Cache = new FileCache(); }
30 |
31 | ///
32 | /// Get the static content cache
33 | ///
34 | public FileCache Cache { get; }
35 |
36 | ///
37 | /// Add static content cache
38 | ///
39 | /// Static content path
40 | /// Cache prefix (default is "/")
41 | /// Refresh cache timeout (default is 1 hour)
42 | public void AddStaticContent(string path, string prefix = "/", TimeSpan? timeout = null)
43 | {
44 | timeout ??= TimeSpan.FromHours(1);
45 |
46 | bool Handler(FileCache cache, string key, byte[] value, TimeSpan timespan)
47 | {
48 | HttpResponse header = new HttpResponse();
49 | header.SetBegin(200);
50 | header.SetContentType(Path.GetExtension(key));
51 | header.SetHeader("Cache-Control", $"max-age={timespan.Seconds}");
52 | header.SetBody(value);
53 | return cache.Add(key, header.Cache.Data, timespan);
54 | }
55 |
56 | Cache.InsertPath(path, prefix, timeout.Value, Handler);
57 | }
58 | ///
59 | /// Remove static content cache
60 | ///
61 | /// Static content path
62 | public void RemoveStaticContent(string path) { Cache.RemovePath(path); }
63 | ///
64 | /// Clear static content cache
65 | ///
66 | public void ClearStaticContent() { Cache.Clear(); }
67 |
68 | ///
69 | /// Watchdog the static content cache
70 | ///
71 | public void Watchdog(DateTime utc) { Cache.Watchdog(utc); }
72 |
73 | protected override TcpSession CreateSession() { return new HttpSession(this); }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/SyslogParser/Code/CaseChangingCharStream.cs:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 | * Use of this file is governed by the BSD 3-clause license that
3 | * can be found in the LICENSE.txt file in the project root.
4 | */
5 | using System;
6 | using Antlr4.Runtime.Misc;
7 |
8 | // https://github.com/antlr/antlr4/tree/master/doc/resources
9 | namespace Antlr4.Runtime
10 | {
11 |
12 |
13 | ///
14 | /// This class supports case-insensitive lexing by wrapping an existing
15 | /// and forcing the lexer to see either upper or
16 | /// lowercase characters. Grammar literals should then be either upper or
17 | /// lower case such as 'BEGIN' or 'begin'. The text of the character
18 | /// stream is unaffected. Example: input 'BeGiN' would match lexer rule
19 | /// 'BEGIN' if constructor parameter upper=true but getText() would return
20 | /// 'BeGiN'.
21 | ///
22 | public class CaseChangingCharStream
23 | : ICharStream
24 | {
25 | private ICharStream stream;
26 | private bool upper;
27 |
28 | ///
29 | /// Constructs a new CaseChangingCharStream wrapping the given forcing
30 | /// all characters to upper case or lower case.
31 | ///
32 | /// The stream to wrap.
33 | /// If true force each symbol to upper case, otherwise force to lower.
34 | public CaseChangingCharStream(ICharStream stream, bool upper)
35 | {
36 | this.stream = stream;
37 | this.upper = upper;
38 | }
39 |
40 | public int Index
41 | {
42 | get
43 | {
44 | return stream.Index;
45 | }
46 | }
47 |
48 | public int Size
49 | {
50 | get
51 | {
52 | return stream.Size;
53 | }
54 | }
55 |
56 | public string SourceName
57 | {
58 | get
59 | {
60 | return stream.SourceName;
61 | }
62 | }
63 |
64 | public void Consume()
65 | {
66 | stream.Consume();
67 | }
68 |
69 | [return: NotNull]
70 | public string GetText(Interval interval)
71 | {
72 | return stream.GetText(interval);
73 | }
74 |
75 | public int La(int i)
76 | {
77 | int c = stream.La(i);
78 |
79 | if (c <= 0)
80 | {
81 | return c;
82 | }
83 |
84 | char o = (char)c;
85 |
86 | if (upper)
87 | {
88 | return (int)char.ToUpperInvariant(o);
89 | }
90 |
91 | return (int)char.ToLowerInvariant(o);
92 | }
93 |
94 |
95 | public int Mark()
96 | {
97 | return stream.Mark();
98 | }
99 |
100 | public void Release(int marker)
101 | {
102 | stream.Release(marker);
103 | }
104 |
105 | public void Seek(int index)
106 | {
107 | stream.Seek(index);
108 | }
109 | }
110 |
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/SelfSignedCertificate/Helpers/StringStream.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SelfSignedCertificate
3 | {
4 |
5 |
6 | public class StringStream
7 | : System.IO.Stream, System.IDisposable
8 | {
9 |
10 | protected System.IO.MemoryStream m_stream;
11 | protected System.IO.StreamWriter m_writer;
12 | private bool disposedValue;
13 |
14 | public StringStream(string s)
15 | {
16 | this.m_stream = new System.IO.MemoryStream();
17 | this.m_writer = new System.IO.StreamWriter(this.m_stream);
18 | this.m_writer.Write(s);
19 | this.m_writer.Flush();
20 | this.m_stream.Position = 0;
21 | }
22 |
23 |
24 | public override bool CanRead => this.m_stream.CanRead;
25 |
26 | public override bool CanSeek => this.m_stream.CanSeek;
27 |
28 | public override bool CanWrite => this.m_stream.CanWrite;
29 |
30 | public override long Length => this.m_stream.Length;
31 |
32 | public override long Position { get => this.m_stream.Position; set => this.m_stream.Position = value; }
33 |
34 | public override void Flush()
35 | {
36 | this.m_stream.Flush();
37 | }
38 |
39 | public override int Read(byte[] buffer, int offset, int count)
40 | {
41 | return this.m_stream.Read(buffer, offset, count);
42 | }
43 |
44 | public override long Seek(long offset, System.IO.SeekOrigin origin)
45 | {
46 | return this.m_stream.Seek(offset, origin);
47 | }
48 |
49 | public override void SetLength(long value)
50 | {
51 | this.m_stream.SetLength(value);
52 | }
53 |
54 | public override void Write(byte[] buffer, int offset, int count)
55 | {
56 | this.m_stream.Write(buffer, offset, count);
57 | }
58 |
59 | protected void OnDispose(bool disposing)
60 | {
61 | if (!disposedValue)
62 | {
63 | if (disposing)
64 | {
65 | // TODO: Verwalteten Zustand (verwaltete Objekte) bereinigen
66 | if (this.m_writer != null)
67 | this.m_writer.Dispose();
68 |
69 | if (this.m_stream != null)
70 | this.m_stream.Dispose();
71 | }
72 |
73 | // TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalizer überschreiben
74 | // TODO: Große Felder auf NULL setzen
75 | disposedValue = true;
76 | }
77 | } // End Sub OnDispose
78 |
79 | // // TODO: Finalizer nur überschreiben, wenn "Dispose(bool disposing)" Code für die Freigabe nicht verwalteter Ressourcen enthält
80 | // ~StringStream()
81 | // {
82 | // // Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(bool disposing)" ein.
83 | // Dispose(disposing: false);
84 | // }
85 |
86 | void System.IDisposable.Dispose()
87 | {
88 | // Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(bool disposing)" ein.
89 | OnDispose(true);
90 | System.GC.SuppressFinalize(this);
91 | } // End Sub Dispose
92 |
93 |
94 | } // End Class StringStream
95 |
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/SyslogServer/UpdSyslogServer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SyslogServer
3 | {
4 |
5 |
6 | public class UpdSyslogServer
7 | : NetCoreServer.UdpServer
8 | {
9 |
10 | protected MessageHandler m_messageHandler;
11 |
12 |
13 | public UpdSyslogServer(System.Net.IPAddress address, int port, MessageHandler handler)
14 | : base(address, port)
15 | {
16 | this.m_messageHandler = handler;
17 | }
18 |
19 |
20 | protected override void OnStarted()
21 | {
22 | // Start receive datagrams
23 | ReceiveAsync();
24 | } // End Sub OnStarted
25 |
26 |
27 | protected override void OnReceived(
28 | System.Net.EndPoint endpoint
29 | , byte[] buffer
30 | , long offset
31 | , long size)
32 | {
33 | System.Console.WriteLine("Incoming: " + System.Text.Encoding.UTF8.GetString(buffer, (int)offset, (int)size));
34 | this.m_messageHandler.OnReceived(endpoint, buffer, offset, size);
35 |
36 |
37 | // Echo the message back to the sender
38 | // SendAsync(endpoint, buffer, 0, size);
39 | } // End Sub OnReceived
40 |
41 |
42 | protected override void OnSent(System.Net.EndPoint endpoint, long sent)
43 | {
44 | // Continue receive datagrams
45 | ReceiveAsync();
46 | } // End Sub OnSent
47 |
48 |
49 | protected override void OnError(System.Net.Sockets.SocketError error)
50 | {
51 | // System.Console.WriteLine($"Echo UDP server caught an error with code {error}");
52 | this.m_messageHandler.OnError(error);
53 | } // End Sub OnError
54 |
55 |
56 | public static void Test()
57 | {
58 | // UDP server port
59 | int port = 514;
60 |
61 | System.Console.WriteLine($"UDP server port: {port}");
62 |
63 | System.Console.WriteLine();
64 |
65 | // Create a new UDP echo server
66 | UpdSyslogServer server =
67 | new UpdSyslogServer(System.Net.IPAddress.Any, port, MessageHandler.CreateInstance(123, port));
68 |
69 | // Start the server
70 | System.Console.Write("Server starting...");
71 | server.Start();
72 | System.Console.WriteLine("Done!");
73 |
74 | System.Console.WriteLine("Press Enter to stop the server or '!' to restart the server...");
75 |
76 | // Perform text input
77 | for (; ; )
78 | {
79 | string line = System.Console.ReadLine();
80 | if (string.IsNullOrEmpty(line))
81 | break;
82 |
83 | // Restart the server
84 | if (line == "!")
85 | {
86 | System.Console.Write("Server restarting...");
87 | server.Restart();
88 | System.Console.WriteLine("Done!");
89 | }
90 |
91 | } // Next
92 |
93 | // Stop the server
94 | System.Console.Write("Server stopping...");
95 | server.Stop();
96 | System.Console.WriteLine("Done!");
97 | } // End Sub Test
98 |
99 |
100 | } // End Class UpdSyslogServer
101 |
102 |
103 | } // End Namespace SyslogServer
104 |
--------------------------------------------------------------------------------
/NetCoreServer/HttpsServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Net;
4 |
5 | namespace NetCoreServer
6 | {
7 | ///
8 | /// HTTPS server is used to create secured HTTPS Web server and communicate with clients using secure HTTPS protocol. It allows to receive GET, POST, PUT, DELETE requests and send HTTP responses.
9 | ///
10 | /// Thread-safe.
11 | public class HttpsServer : SslServer
12 | {
13 | ///
14 | /// Initialize HTTPS server with a given IP address and port number
15 | ///
16 | /// SSL context
17 | /// IP address
18 | /// Port number
19 | public HttpsServer(SslContext context, IPAddress address, int port) : base(context, address, port) { Cache = new FileCache(); }
20 | ///
21 | /// Initialize HTTPS server with a given IP address and port number
22 | ///
23 | /// SSL context
24 | /// IP address
25 | /// Port number
26 | public HttpsServer(SslContext context, string address, int port) : base(context, address, port) { Cache = new FileCache(); }
27 | ///
28 | /// Initialize HTTPS server with a given IP endpoint
29 | ///
30 | /// SSL context
31 | /// IP endpoint
32 | public HttpsServer(SslContext context, IPEndPoint endpoint) : base(context, endpoint) { Cache = new FileCache(); }
33 |
34 | ///
35 | /// Get the static content cache
36 | ///
37 | public FileCache Cache { get; }
38 |
39 | ///
40 | /// Add static content cache
41 | ///
42 | /// Static content path
43 | /// Cache prefix (default is "/")
44 | /// Refresh cache timeout (default is 1 hour)
45 | public void AddStaticContent(string path, string prefix = "/", TimeSpan? timeout = null)
46 | {
47 | timeout ??= TimeSpan.FromHours(1);
48 |
49 | bool Handler(FileCache cache, string key, byte[] value, TimeSpan timespan)
50 | {
51 | HttpResponse header = new HttpResponse();
52 | header.SetBegin(200);
53 | header.SetContentType(Path.GetExtension(key));
54 | header.SetHeader("Cache-Control", $"max-age={timespan.Seconds}");
55 | header.SetBody(value);
56 | return cache.Add(key, header.Cache.Data, timespan);
57 | }
58 |
59 | Cache.InsertPath(path, prefix, timeout.Value, Handler);
60 | }
61 | ///
62 | /// Remove static content cache
63 | ///
64 | /// Static content path
65 | public void RemoveStaticContent(string path) { Cache.RemovePath(path); }
66 | ///
67 | /// Clear static content cache
68 | ///
69 | public void ClearStaticContent() { Cache.Clear(); }
70 |
71 | ///
72 | /// Watchdog the static content cache
73 | ///
74 | public void Watchdog(DateTime utc) { Cache.Watchdog(utc); }
75 |
76 | protected override SslSession CreateSession() { return new HttpsSession(this); }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/StreamExtended/Network/ICustomStreamReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace StreamExtended.Network
6 | {
7 | ///
8 | /// This concrete implemetation of interface acts as the source stream for CopyStream class.
9 | ///
10 | public interface ICustomStreamReader
11 | {
12 | int BufferSize { get; }
13 |
14 | int Available { get; }
15 |
16 | bool DataAvailable { get; }
17 |
18 | ///
19 | /// Fills the buffer asynchronous.
20 | ///
21 | ///
22 | Task FillBufferAsync(CancellationToken cancellationToken = default(CancellationToken));
23 |
24 | ///
25 | /// Peeks a byte from buffer.
26 | ///
27 | /// The index.
28 | ///
29 | /// Index is out of buffer size
30 | byte PeekByteFromBuffer(int index);
31 |
32 | ///
33 | /// Peeks a byte asynchronous.
34 | ///
35 | /// The index.
36 | /// The cancellation token.
37 | ///
38 | Task PeekByteAsync(int index, CancellationToken cancellationToken = default(CancellationToken));
39 |
40 | ///
41 | /// Peeks bytes asynchronous.
42 | ///
43 | /// The index.
44 | /// The cancellation token.
45 | ///
46 | Task PeekBytesAsync(int index, int size, CancellationToken cancellationToken = default(CancellationToken));
47 |
48 | byte ReadByteFromBuffer();
49 |
50 | ///
51 | /// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
52 | ///
53 | /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source.
54 | /// The zero-based byte offset in at which to begin storing the data read from the current stream.
55 | /// The maximum number of bytes to be read from the current stream.
56 | ///
57 | /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
58 | ///
59 | int Read(byte[] buffer, int offset, int count);
60 |
61 | ///
62 | /// Read the specified number (or less) of raw bytes from the base stream to the given buffer to the specified offset
63 | ///
64 | ///
65 | ///
66 | ///
67 | ///
68 | /// The number of bytes read
69 | Task ReadAsync(byte[] buffer, int offset, int bytesToRead,
70 | CancellationToken cancellationToken = default(CancellationToken));
71 |
72 | ///
73 | /// Read a line from the byte stream
74 | ///
75 | ///
76 | Task ReadLineAsync(CancellationToken cancellationToken = default(CancellationToken));
77 | }
78 | }
--------------------------------------------------------------------------------
/NetCoreServer/SslContext.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Security;
2 | using System.Security.Authentication;
3 | using System.Security.Cryptography.X509Certificates;
4 |
5 | namespace NetCoreServer
6 | {
7 | ///
8 | /// SSL context
9 | ///
10 | public class SslContext
11 | {
12 | ///
13 | /// Initialize SSL context with default protocols
14 | ///
15 | public SslContext() : this(SslProtocols.Tls12) {}
16 | ///
17 | /// Initialize SSL context with given protocols
18 | ///
19 | /// SSL protocols
20 | public SslContext(SslProtocols protocols) { Protocols = protocols; }
21 | ///
22 | /// Initialize SSL context with given protocols and certificate
23 | ///
24 | /// SSL protocols
25 | /// SSL certificate
26 | public SslContext(SslProtocols protocols, X509Certificate certificate) : this(protocols, certificate, null) {}
27 | ///
28 | /// Initialize SSL context with given protocols, certificate and validation callback
29 | ///
30 | /// SSL protocols
31 | /// SSL certificate
32 | /// SSL certificate
33 | public SslContext(SslProtocols protocols, X509Certificate certificate, RemoteCertificateValidationCallback certificateValidationCallback)
34 | {
35 | Protocols = protocols;
36 | Certificate = certificate;
37 | CertificateValidationCallback = certificateValidationCallback;
38 | }
39 | ///
40 | /// Initialize SSL context with given protocols and certificates collection
41 | ///
42 | /// SSL protocols
43 | /// SSL certificates collection
44 | public SslContext(SslProtocols protocols, X509Certificate2Collection certificates) : this(protocols, certificates, null) {}
45 | ///
46 | /// Initialize SSL context with given protocols, certificates collection and validation callback
47 | ///
48 | /// SSL protocols
49 | /// SSL certificates collection
50 | /// SSL certificate
51 | public SslContext(SslProtocols protocols, X509Certificate2Collection certificates, RemoteCertificateValidationCallback certificateValidationCallback)
52 | {
53 | Protocols = protocols;
54 | Certificates = certificates;
55 | CertificateValidationCallback = certificateValidationCallback;
56 | }
57 |
58 | ///
59 | /// SSL protocols
60 | ///
61 | public SslProtocols Protocols { get; set; }
62 | ///
63 | /// SSL certificate
64 | ///
65 | public X509Certificate Certificate { get; set; }
66 | ///
67 | /// SSL certificates collection
68 | ///
69 | public X509Certificate2Collection Certificates { get; set; }
70 | ///
71 | /// SSL certificate validation callback
72 | ///
73 | public RemoteCertificateValidationCallback CertificateValidationCallback { get; set; }
74 |
75 | ///
76 | /// Is the client is asked for a certificate for authentication.
77 | /// Note that this is only a request - if no certificate is provided, the server still accepts the connection request.
78 | ///
79 | public bool ClientCertificateRequired { get; set; }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/StreamExtended/StreamExtended.Docs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {EBF2EA46-EA00-4350-BE1D-D86AFD699DB3}
8 | Library
9 | Properties
10 | StreamExtended
11 | StreamExtended
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | true
25 | bin\Debug\StreamExtended.xml
26 | latest
27 |
28 |
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
81 |
--------------------------------------------------------------------------------
/NetCoreServer/IWebSocket.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Sockets;
2 |
3 | namespace NetCoreServer
4 | {
5 | public interface IWebSocket
6 | {
7 | ///
8 | /// Handle WebSocket client connecting notification
9 | ///
10 | /// Notification is called when WebSocket client is connecting to the server.You can handle the connection and change WebSocket upgrade HTTP request by providing your own headers.
11 | /// WebSocket upgrade HTTP request
12 | void OnWsConnecting(HttpRequest request) {}
13 |
14 | ///
15 | /// Handle WebSocket client connected notification
16 | ///
17 | /// WebSocket upgrade HTTP response
18 | void OnWsConnected(HttpResponse response) {}
19 |
20 | ///
21 | /// Handle WebSocket server session validating notification
22 | ///
23 | /// Notification is called when WebSocket client is connecting to the server.You can handle the connection and validate WebSocket upgrade HTTP request.
24 | /// WebSocket upgrade HTTP request
25 | /// WebSocket upgrade HTTP response
26 | /// return 'true' if the WebSocket update request is valid, 'false' if the WebSocket update request is not valid
27 | bool OnWsConnecting(HttpRequest request, HttpResponse response) { return true; }
28 |
29 | ///
30 | /// Handle WebSocket server session connected notification
31 | ///
32 | /// WebSocket upgrade HTTP request
33 | void OnWsConnected(HttpRequest request) {}
34 |
35 | ///
36 | /// Handle WebSocket client disconnected notification
37 | ///
38 | void OnWsDisconnected() {}
39 |
40 | ///
41 | /// Handle WebSocket received notification
42 | ///
43 | /// Received buffer
44 | /// Received buffer offset
45 | /// Received buffer size
46 | void OnWsReceived(byte[] buffer, long offset, long size) {}
47 |
48 | ///
49 | /// Handle WebSocket client close notification
50 | ///
51 | /// Received buffer
52 | /// Received buffer offset
53 | /// Received buffer size
54 | void OnWsClose(byte[] buffer, long offset, long size) {}
55 |
56 | ///
57 | /// Handle WebSocket ping notification
58 | ///
59 | /// Received buffer
60 | /// Received buffer offset
61 | /// Received buffer size
62 | void OnWsPing(byte[] buffer, long offset, long size) {}
63 |
64 | ///
65 | /// Handle WebSocket pong notification
66 | ///
67 | /// Received buffer
68 | /// Received buffer offset
69 | /// Received buffer size
70 | void OnWsPong(byte[] buffer, long offset, long size) {}
71 |
72 | ///
73 | /// Handle WebSocket error notification
74 | ///
75 | /// Error message
76 | void OnWsError(string error) {}
77 |
78 | ///
79 | /// Handle socket error notification
80 | ///
81 | /// Socket error
82 | void OnWsError(SocketError error) {}
83 |
84 | ///
85 | /// Send WebSocket server upgrade response
86 | ///
87 | /// WebSocket upgrade HTTP response
88 | void SendResponse(HttpResponse response) {}
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/StreamExtended/ServerHelloInfo.cs:
--------------------------------------------------------------------------------
1 | using StreamExtended.Models;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace StreamExtended
8 | {
9 | ///
10 | /// Wraps up the server SSL hello information.
11 | ///
12 | public class ServerHelloInfo
13 | {
14 | private static readonly string[] compressions = {
15 | "null",
16 | "DEFLATE"
17 | };
18 |
19 | public int HandshakeVersion { get; set; }
20 |
21 | public int MajorVersion { get; set; }
22 |
23 | public int MinorVersion { get; set; }
24 |
25 | public byte[] Random { get; set; }
26 |
27 | public DateTime Time
28 | {
29 | get
30 | {
31 | DateTime time = DateTime.MinValue;
32 | if (Random.Length > 3)
33 | {
34 | time = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)
35 | .AddSeconds(((uint)Random[3] << 24) + ((uint)Random[2] << 16) + ((uint)Random[1] << 8) + (uint)Random[0]).ToLocalTime();
36 | }
37 |
38 | return time;
39 | }
40 | }
41 |
42 | public byte[] SessionId { get; set; }
43 |
44 | public int CipherSuite { get; set; }
45 |
46 | public byte CompressionMethod { get; set; }
47 |
48 | internal int ServerHelloLength { get; set; }
49 |
50 | internal int EntensionsStartPosition { get; set; }
51 |
52 | public Dictionary Extensions { get; set; }
53 |
54 | private static string SslVersionToString(int major, int minor)
55 | {
56 | string str = "Unknown";
57 | if (major == 3 && minor == 4)
58 | str = "TLS/1.3";
59 | else if (major == 3 && minor == 3)
60 | str = "TLS/1.2";
61 | else if (major == 3 && minor == 2)
62 | str = "TLS/1.1";
63 | else if (major == 3 && minor == 1)
64 | str = "TLS/1.0";
65 | else if (major == 3 && minor == 0)
66 | str = "SSL/3.0";
67 | else if (major == 2 && minor == 0)
68 | str = "SSL/2.0";
69 |
70 | return $"{major}.{minor} ({str})";
71 | }
72 |
73 | ///
74 | /// Returns a that represents this instance.
75 | ///
76 | ///
77 | /// A that represents this instance.
78 | ///
79 | public override string ToString()
80 | {
81 | var sb = new StringBuilder();
82 | sb.AppendLine($"A SSLv{HandshakeVersion}-compatible ServerHello handshake was found. Titanium extracted the parameters below.");
83 | sb.AppendLine();
84 | sb.AppendLine($"Version: {SslVersionToString(MajorVersion, MinorVersion)}");
85 | sb.AppendLine($"Random: {string.Join(" ", Random.Select(x => x.ToString("X2")))}");
86 | sb.AppendLine($"\"Time\": {Time}");
87 | sb.AppendLine($"SessionID: {string.Join(" ", SessionId.Select(x => x.ToString("X2")))}");
88 |
89 | if (Extensions != null)
90 | {
91 | sb.AppendLine("Extensions:");
92 | foreach (var extension in Extensions.Values.OrderBy(x => x.Position))
93 | {
94 | sb.AppendLine($"{extension.Name}: {extension.Data}");
95 | }
96 | }
97 |
98 | string compression = compressions.Length > CompressionMethod
99 | ? compressions[CompressionMethod]
100 | : $"unknown [0x{CompressionMethod:X2}]";
101 | sb.AppendLine($"Compression: {compression}");
102 |
103 | sb.Append("Cipher:");
104 | if (!SslCiphers.Ciphers.TryGetValue(CipherSuite, out string cipherStr))
105 | {
106 | cipherStr = "unknown";
107 | }
108 |
109 | sb.AppendLine($"[0x{CipherSuite:X4}] {cipherStr}");
110 |
111 | return sb.ToString();
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/StreamExtended/ClientHelloInfo.cs:
--------------------------------------------------------------------------------
1 | using StreamExtended.Models;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace StreamExtended
8 | {
9 | ///
10 | /// Wraps up the client SSL hello information.
11 | ///
12 | public class ClientHelloInfo
13 | {
14 | private static readonly string[] compressions = {
15 | "null",
16 | "DEFLATE"
17 | };
18 |
19 | public int HandshakeVersion { get; set; }
20 |
21 | public int MajorVersion { get; set; }
22 |
23 | public int MinorVersion { get; set; }
24 |
25 | public byte[] Random { get; set; }
26 |
27 | public DateTime Time
28 | {
29 | get
30 | {
31 | DateTime time = DateTime.MinValue;
32 | if (Random.Length > 3)
33 | {
34 | time = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)
35 | .AddSeconds(((uint)Random[3] << 24) + ((uint)Random[2] << 16) + ((uint)Random[1] << 8) + (uint)Random[0]).ToLocalTime();
36 | }
37 |
38 | return time;
39 | }
40 | }
41 |
42 | public byte[] SessionId { get; set; }
43 |
44 | public int[] Ciphers { get; set; }
45 |
46 | public byte[] CompressionData { get; set; }
47 |
48 | internal int ClientHelloLength { get; set; }
49 |
50 | internal int EntensionsStartPosition { get; set; }
51 |
52 | public Dictionary Extensions { get; set; }
53 |
54 | private static string SslVersionToString(int major, int minor)
55 | {
56 | string str = "Unknown";
57 |
58 | if (major == 3 && minor == 4)
59 | str = "TLS/1.3";
60 | else if (major == 3 && minor == 3)
61 | str = "TLS/1.2";
62 | else if (major == 3 && minor == 2)
63 | str = "TLS/1.1";
64 | else if (major == 3 && minor == 1)
65 | str = "TLS/1.0";
66 | else if (major == 3 && minor == 0)
67 | str = "SSL/3.0";
68 | else if (major == 2 && minor == 0)
69 | str = "SSL/2.0";
70 |
71 | return $"{major}.{minor} ({str})";
72 | }
73 |
74 | ///
75 | /// Returns a that represents this instance.
76 | ///
77 | ///
78 | /// A that represents this instance.
79 | ///
80 | public override string ToString()
81 | {
82 | var sb = new StringBuilder();
83 | sb.AppendLine($"A SSLv{HandshakeVersion}-compatible ClientHello handshake was found. Titanium extracted the parameters below.");
84 | sb.AppendLine();
85 | sb.AppendLine($"Version: {SslVersionToString(MajorVersion, MinorVersion)}");
86 | sb.AppendLine($"Random: {string.Join(" ", Random.Select(x => x.ToString("X2")))}");
87 | sb.AppendLine($"\"Time\": {Time}");
88 | sb.AppendLine($"SessionID: {string.Join(" ", SessionId.Select(x => x.ToString("X2")))}");
89 |
90 | if (Extensions != null)
91 | {
92 | sb.AppendLine("Extensions:");
93 | foreach (var extension in Extensions.Values.OrderBy(x => x.Position))
94 | {
95 | sb.AppendLine($"{extension.Name}: {extension.Data}");
96 | }
97 | }
98 |
99 | if (CompressionData != null && CompressionData.Length > 0)
100 | {
101 | int compressionMethod = CompressionData[0];
102 | string compression = compressions.Length > compressionMethod
103 | ? compressions[compressionMethod]
104 | : $"unknown [0x{compressionMethod:X2}]";
105 | sb.AppendLine($"Compression: {compression}");
106 | }
107 |
108 | if (Ciphers.Length > 0)
109 | {
110 | sb.AppendLine("Ciphers:");
111 | foreach (int cipherSuite in Ciphers)
112 | {
113 | if (!SslCiphers.Ciphers.TryGetValue(cipherSuite, out string cipherStr))
114 | {
115 | cipherStr = "unknown";
116 | }
117 |
118 | sb.AppendLine($"[0x{cipherSuite:X4}] {cipherStr}");
119 | }
120 | }
121 |
122 | return sb.ToString();
123 | }
124 | }
125 | }
--------------------------------------------------------------------------------
/libSyslogServer/SyslogServer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace libSyslogServer
3 | {
4 |
5 |
6 | public partial class SyslogServer
7 | {
8 | public static string _SettingsContents;
9 | public static Settings _Settings;
10 |
11 | public static System.Threading.Thread _ListenerThread;
12 | public static System.Net.Sockets.UdpClient _ListenerUdp;
13 | public static bool _ConsoleDisplay;
14 |
15 | public static System.DateTime _LastWritten;
16 | private static System.Collections.Generic.List _MessageQueue;
17 | private static readonly object _WriterLock;
18 |
19 |
20 | static SyslogServer()
21 | {
22 | _SettingsContents = "";
23 | _ConsoleDisplay = true;
24 | _LastWritten = System.DateTime.Now;
25 | _WriterLock = new object();
26 | _MessageQueue = new System.Collections.Generic.List();
27 | }
28 |
29 |
30 | public static void StartServer()
31 | {
32 |
33 | if (System.IO.File.Exists("syslog.json"))
34 | {
35 | _SettingsContents = System.Text.Encoding.UTF8.GetString(
36 | System.IO.File.ReadAllBytes("syslog.json")
37 | );
38 | }
39 |
40 | if (System.String.IsNullOrEmpty(_SettingsContents))
41 | {
42 | System.Console.WriteLine("Unable to read syslog.json, using default configuration:");
43 | _Settings = Settings.Default();
44 | System.Console.WriteLine(Common.SerializeJson(_Settings));
45 | }
46 | else
47 | {
48 | try
49 | {
50 | _Settings = Common.DeserializeJson(_SettingsContents);
51 | }
52 | catch (System.Exception)
53 | {
54 | System.Console.WriteLine("Unable to deserialize syslog.json, please check syslog.json for correctness, exiting");
55 | System.Environment.Exit(-1);
56 | }
57 | }
58 |
59 | if (!System.IO.Directory.Exists(_Settings.LogFileDirectory))
60 | System.IO.Directory.CreateDirectory(_Settings.LogFileDirectory);
61 |
62 |
63 | System.Console.WriteLine("---");
64 | System.Console.WriteLine(_Settings.Version);
65 | System.Console.WriteLine("(c)2017 Joel Christner");
66 | System.Console.WriteLine("---");
67 |
68 | InternalStartServer();
69 |
70 |
71 |
72 |
73 | while (true)
74 | {
75 | string userInput = Common.InputString("[syslog :: ? for help] >", null, false);
76 | switch (userInput)
77 | {
78 | case "?":
79 | System.Console.WriteLine("---");
80 | System.Console.WriteLine(" q quit the application");
81 | System.Console.WriteLine(" cls clear the screen");
82 | break;
83 |
84 | case "q":
85 | System.Console.WriteLine("Exiting.");
86 | System.Environment.Exit(0);
87 | break;
88 |
89 | case "c":
90 | case "cls":
91 | System.Console.Clear();
92 | break;
93 |
94 | default:
95 | System.Console.WriteLine("Unknown command. Type '?' for help.");
96 | continue;
97 | }
98 | }
99 |
100 |
101 | }
102 |
103 | static void InternalStartServer()
104 | {
105 | try
106 | {
107 | System.Console.WriteLine("Starting at " + System.DateTime.Now);
108 |
109 | _ListenerThread = new System.Threading.Thread(ReceiverThread);
110 | _ListenerThread.Start();
111 | System.Console.WriteLine("Listening on UDP/" + _Settings.UdpPort + ".");
112 |
113 | System.Threading.Tasks.Task.Run(() => WriterTask());
114 | System.Console.WriteLine("Writer thread started successfully");
115 | }
116 | catch (System.Exception e)
117 | {
118 | System.Console.WriteLine("***");
119 | System.Console.WriteLine("Exiting due to exception: " + e.Message);
120 | System.Environment.Exit(-1);
121 | }
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/SyslogServer/TcpSyslogServer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SyslogServer
3 | {
4 |
5 |
6 | public class SyslogTcpSession
7 | : NetCoreServer.TcpSession
8 | {
9 | protected MessageHandler m_messageHandler;
10 |
11 | public SyslogTcpSession(NetCoreServer.TcpServer server, MessageHandler handler)
12 | : base(server)
13 | {
14 | this.m_messageHandler = handler;
15 | }
16 |
17 | protected override void OnConnected()
18 | {
19 | System.Console.WriteLine($"Syslog TCP session with Id {Id} connected!");
20 |
21 | // Send invite message
22 | string message = "Hello from Syslog TCP session ! Please send a message or '!' to disconnect the client!";
23 | SendAsync(message);
24 | } // End Sub OnConnected
25 |
26 |
27 | protected override void OnDisconnected()
28 | {
29 | System.Console.WriteLine($"Syslog TCP session with Id {Id} disconnected!");
30 | } // End Sub OnDisconnected
31 |
32 |
33 |
34 |
35 |
36 | protected override void OnReceived(byte[] buffer, long offset, long size)
37 | {
38 | this.m_messageHandler.OnReceived(this.Socket.RemoteEndPoint, buffer, offset, size);
39 |
40 | // Multicast message to all connected sessions
41 | // Server.Multicast(message);
42 |
43 | // If the buffer starts with '!' the disconnect the current session
44 | // if (message == "!")
45 | // Disconnect();
46 |
47 | } // End Sub OnReceived
48 |
49 |
50 | protected override void OnError(System.Net.Sockets.SocketError error)
51 | {
52 | // System.Console.WriteLine($"Syslog TCP session caught an error with code {error}");
53 | this.m_messageHandler.OnError(error);
54 | } // End Sub OnError
55 |
56 |
57 | } // End Class SyslogTcpSession
58 |
59 |
60 | public class TcpSyslogServer
61 | : NetCoreServer.TcpServer
62 | {
63 | protected MessageHandler m_messageHandler;
64 |
65 | public TcpSyslogServer(
66 | System.Net.IPAddress address
67 | , int port
68 | ,MessageHandler handler
69 | )
70 | : base(address, port)
71 | {
72 | this.m_messageHandler = handler;
73 | }
74 |
75 |
76 | protected override NetCoreServer.TcpSession CreateSession()
77 | {
78 | return new SyslogTcpSession(this, this.m_messageHandler);
79 | } // End Function CreateSession
80 |
81 |
82 | protected override void OnError(System.Net.Sockets.SocketError error)
83 | {
84 | // System.Console.WriteLine($"Syslog TCP server caught an error with code {error}");
85 | this.m_messageHandler.OnError(error);
86 | } // End Sub OnError
87 |
88 |
89 | public static void Test()
90 | {
91 | // TCP server port
92 | int port = 1468;
93 |
94 | System.Console.WriteLine($"TCP server port: {port}");
95 |
96 | System.Console.WriteLine();
97 |
98 | // Create a new TCP Syslog server
99 | TcpSyslogServer server =
100 | new TcpSyslogServer(System.Net.IPAddress.Any, port, MessageHandler.CreateInstance(123, port));
101 |
102 | // Start the server
103 | System.Console.Write("Server starting...");
104 | server.Start();
105 | System.Console.WriteLine("Done!");
106 |
107 | System.Console.WriteLine("Press Enter to stop the server or '!' to restart the server...");
108 |
109 | // Perform text input
110 | for (; ; )
111 | {
112 | string line = System.Console.ReadLine();
113 | if (string.IsNullOrEmpty(line))
114 | break;
115 |
116 | // Restart the server
117 | if (line == "!")
118 | {
119 | System.Console.Write("Server restarting...");
120 | server.Restart();
121 | System.Console.WriteLine("Done!");
122 | continue;
123 | } // End if (line == "!")
124 |
125 | // Multicast admin message to all sessions
126 | line = "(admin) " + line;
127 | server.Multicast(line);
128 | } // Next
129 |
130 | // Stop the server
131 | System.Console.Write("Server stopping...");
132 | server.Stop();
133 | System.Console.WriteLine("Done!");
134 | } // End Sub Test
135 |
136 |
137 | } // End Class TcpSyslogServer
138 |
139 |
140 | } // End Namespace SyslogServer
141 |
--------------------------------------------------------------------------------
/SyslogServer/syslog_info.txt:
--------------------------------------------------------------------------------
1 |
2 | https://tools.ietf.org/html/rfc6587
3 | https://tools.ietf.org/html/rfc5426
4 | https://tools.ietf.org/html/rfc5424
5 | https://tools.ietf.org/html/rfc3164
6 |
7 |
8 | RFC 5425 - TLS for Syslog is not supported yet
9 |
10 |
11 | RFC 6587 Transmission of Syslog Messages over TCP
12 | RFC 5426 Transmission of Syslog Messages over UDP
13 | RFC 5424 The Syslog Protocol - Obsoletes: RFC 3164
14 | RFC 3164 - The BSD syslog Protocol - Obsoleted by RFC 5424
15 | YOU SHOULD NO LONGER FOLLOW RFC 3164 except for legacy reasons (i.e. backwards compatibility).
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | RFC5424 removed the requirement of using only UDP for log sending,
24 | but still mandates UDP be supported (for at least backwards compatibility).
25 |
26 | One option available starting with RFC 5424 is TCP.
27 |
28 | To guarantee message delivery, right?
29 | WRONG! TCP DOES NOT GUARANTEE MESSAGE DELIVERY.
30 | VERY IMPORTANT: Message receipt acknowledgment (i.e. TCP handshake) != guaranteed message delivery
31 |
32 | But one knows that the server is up and running
33 | UDP doesn't give an error !
34 |
35 |
36 |
37 | receivedData = Encoding.ASCII.GetString(receivedBytes, 0, receivedBytes.Length);
38 |
39 | https://labs.rebex.net/syslog
40 | https://sflanders.net/2018/08/22/syslog-and-what-protocol-to-send-events-over/
41 | https://github.com/chronoxor/NetCoreServer#example-ssl-chat-client
42 | https://stackify.com/syslog-101
43 | http://web.archive.org/web/20201205213311/https://sflanders.net/2018/08/22/syslog-and-what-protocol-to-send-events-over/
44 |
45 | https://github.com/jchristn/WatsonSyslogServer
46 | https://github.com/emertechie/SyslogNet
47 | https://gunnarpeipman.com/aspnet-core-syslog/
48 | https://github.com/mguinness/syslogserver
49 | https://github.com/mguinness/syslog-framework-logging
50 |
51 | https://github.com/YallaDotNet/syslog
52 | http://yalladotnet.github.io/syslog/html/7b08f132-b375-4232-94b9-6df3585c206e.htm
53 | https://github.com/ststeiger/SyslogSharp
54 | http://syslogsharp.sourceforge.net/
55 |
56 |
57 |
58 | https://www.alibabacloud.com/help/doc-detail/135042.htm
59 | Two Syslog protocols are commonly used in the industry:
60 | RFC 5424 issued in 2009 and RFC 3164 issued in 2001.
61 | This section describes the differences between the two protocols
62 |
63 |
64 | =============================================================================
65 | RFC 5424
66 | Syslog messages that use the RFC 5424 protocol contain the following fields.
67 | For more information, see RFC 5424 - The Syslog Protocol.
68 | PRI VERSION SP TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID
69 | =============================================================================
70 |
71 | The following examples describe these fields:
72 | """
73 | Example1:
74 | <34>1 2019-07-11T22:14:15.003Z aliyun.example.com ali - ID47 - BOM'su root' failed for lonvick on /dev/pts/8
75 | """
76 | PRI -- 34
77 | VERSION -- 1
78 | TIMESTAMP -- 2019-07-11T22:14:15.003Z
79 | HOSTNAME -- aliyun.example.com
80 | APP-NAME -- ali
81 | PROCID -- None
82 | MSGID -- ID47
83 | MESSAGE -- 'su root' failed for lonvick on /dev/pts/8
84 | """
85 | Example2:
86 | <165>1 2019-07-11T22:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts.
87 | """
88 | PRI -- 165
89 | VERSION -- 1
90 | TIMESTAMP -- 2019-07-11T05:14:15.000003-07:00
91 | HOSTNAME -- 192.0.2.1
92 | APP-NAME -- myproc
93 | PROCID -- 8710
94 | STRUCTURED-DATA -- "-"
95 | MSGID -- "-"
96 | MESSAGE -- "%% It's time to make the do-nuts."
97 | """
98 | Example3: - with STRUCTURED-DATA
99 | <165>1 2019-07-11T22:14:15.003Z aliyun.example.com
100 | evntslog - ID47 [exampleSDID@32473 iut="3" eventSource=
101 | "Application" eventID="1011"] BOMAn application
102 | event log entry...
103 | """
104 | PRI -- 165
105 | VERSION -- 1
106 | TIMESTAMP -- 2019-07-11T22:14:15.003Z
107 | HOSTNAME -- aliyun.example.com
108 | APP-NAME -- evntslog
109 | PROCID -- "-"
110 | MSGID -- ID47
111 | STRUCTURED-DATA -- [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"]
112 | MESSAGE -- An application event log entry...
113 |
114 |
115 | =============================================================================
116 | RFC 3164
117 | Syslog messages that use the RFC 3164 protocol contain the following fields.
118 | For more information, see RFC 3164 - The BSD Syslog Protocol.
119 | PRI HEADER[TIME HOSTNAME] MSG
120 | =============================================================================
121 |
122 | The following example describes these fields:
123 | """
124 | <30>Oct 9 22:33:20 hlfedora auditd[1787]: The audit daemon is exiting.
125 | """
126 | PRI -- 30
127 | HEADER
128 | - TIME -- Oct 9 22:33:20
129 | - HOSTNAME -- hlfedora
130 | MSG
131 | - TAG -- auditd[1787]
132 | - Content --The audit daemon is exiting.
133 |
--------------------------------------------------------------------------------
/SyslogServer/Common/Rfc3164SyslogMessage.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SyslogServer
3 | {
4 |
5 | public class Rfc3164SyslogMessage
6 | {
7 | public FacilityType Facility { get; set; }
8 | public SeverityType Severity { get; set; }
9 | public System.DateTime Datestamp { get; set; }
10 | public string Hostname { get; set; }
11 | public string Content { get; set; }
12 | public string RemoteIP { get; set; }
13 | public System.DateTime LocalDate { get; set; }
14 |
15 | private const string RegexExpression = @"^
16 | (?\<\d{1,3}\>)?
17 | (?
18 | (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s
19 | [0-3][0-9]\s
20 | [0-9]{2}\:[0-9]{2}\:[0-9]{2}\s
21 | [^ ]+?\s
22 | )?
23 | (?.+)
24 | ";
25 |
26 |
27 | // Rfc3164SyslogMessage.IsRfc3164SyslogMessage
28 | public static bool IsRfc3164SyslogMessage(string syslogMessage)
29 | {
30 | System.Text.RegularExpressions.Regex _re =
31 | new System.Text.RegularExpressions.Regex(
32 | RegexExpression
33 | , System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace
34 | | System.Text.RegularExpressions.RegexOptions.Singleline
35 | | System.Text.RegularExpressions.RegexOptions.Compiled
36 | );
37 |
38 | System.Text.RegularExpressions.Match m = _re.Match(syslogMessage);
39 | return m.Success;
40 | }
41 |
42 |
43 | public static Rfc3164SyslogMessage Parse(string syslogMessage)
44 | {
45 | Rfc3164SyslogMessage msg = null;
46 |
47 | System.Text.RegularExpressions.Regex _re =
48 | new System.Text.RegularExpressions.Regex(RegexExpression, System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace
49 | | System.Text.RegularExpressions.RegexOptions.Singleline
50 | | System.Text.RegularExpressions.RegexOptions.Compiled);
51 |
52 |
53 | System.Text.RegularExpressions.Match m = _re.Match(syslogMessage);
54 | if (!m.Success)
55 | return msg;
56 |
57 | msg = new Rfc3164SyslogMessage();
58 |
59 | if (m.Groups["PRI"].Success)
60 | {
61 | string pri = m.Groups["PRI"].Value;
62 | int priority = int.Parse(pri.Substring(1, pri.Length - 2));
63 | msg.Facility = (FacilityType)System.Math.Floor((double)priority / 8);
64 | msg.Severity = (SeverityType)(priority % 8);
65 | }
66 | else
67 | {
68 | msg.Facility = FacilityType.User;
69 | msg.Severity = SeverityType.Notice;
70 | }
71 |
72 | if (m.Groups["HDR"].Success)
73 | {
74 | string hdr = m.Groups["HDR"].Value.TrimEnd();
75 | int idx = hdr.LastIndexOf(' ');
76 | msg.Datestamp = System.DateTime.ParseExact(hdr.Substring(0, idx), "MMM dd HH:mm:ss", null);
77 | msg.Hostname = hdr.Substring(idx + 1);
78 | }
79 | else
80 | {
81 | msg.Datestamp = System.DateTime.Now;
82 |
83 | try
84 | {
85 | // IPHostEntry he = Dns.GetHostEntry(receiveResult.RemoteEndPoint.Address);
86 | // msg.Hostname = he.HostName;
87 | }
88 | catch (System.Net.Sockets.SocketException)
89 | {
90 | // msg.Hostname = receiveResult.RemoteEndPoint.Address.ToString();
91 | }
92 | } // End else of if (m.Groups["HDR"].Success)
93 |
94 | msg.Content = m.Groups["MSG"].Value;
95 | // msg.RemoteIP = receiveResult.RemoteEndPoint.Address.ToString();
96 | msg.LocalDate = System.DateTime.Now;
97 |
98 | // if (MessageReceived != null) MessageReceived(msg);
99 |
100 | msg.IsValid = true;
101 | msg.RawMessage = syslogMessage;
102 | msg.MessageReceivedTime = System.DateTime.UtcNow;
103 |
104 | return msg;
105 | } // End Function ParseMessage
106 |
107 |
108 | public string RawMessage { get; private set; }
109 | public System.Exception Exception { get; private set; }
110 | public bool IsValid { get; private set; }
111 | public System.DateTime MessageReceivedTime { get; private set; }
112 |
113 |
114 | public static Rfc3164SyslogMessage Invalid(string rawMessage, System.Exception ex)
115 | {
116 | return new Rfc3164SyslogMessage
117 | {
118 | RawMessage = rawMessage,
119 | IsValid = false,
120 | MessageReceivedTime = System.DateTime.UtcNow,
121 | Exception = ex
122 | };
123 | }
124 |
125 |
126 | }
127 |
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/NetCoreSyslogServer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30804.86
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "libSyslogServer", "libSyslogServer\libSyslogServer.csproj", "{3F003BC6-96BC-46D7-9BA4-59EFA5ECA430}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SyslogServer", "SyslogServer\SyslogServer.csproj", "{D9576E71-6909-460B-963A-0F6514213E4D}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleTlsServer", "SimpleTlsServer\SimpleTlsServer.csproj", "{C6B00692-3805-4B38-B80F-374D66755C7E}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleTcpServer", "SimpleTcpServer\SimpleTcpServer.csproj", "{7425DC58-2A92-4587-855C-B6703FAA0F09}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCoreServer", "NetCoreServer\NetCoreServer.csproj", "{12B646D2-96E3-449A-8AC5-9C0E0DC833DE}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SelfSignedCertificate", "SelfSignedCertificate\SelfSignedCertificate.csproj", "{652125DB-ECD4-4693-919B-054CE32A4772}"
17 | EndProject
18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{614FEBA8-85B2-449F-A3A9-40C128AB7EAF}"
19 | ProjectSection(SolutionItems) = preProject
20 | README.md = README.md
21 | EndProjectSection
22 | EndProject
23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SyslogParser", "SyslogParser\SyslogParser.csproj", "{45D341B4-1355-4581-B17B-16009D534888}"
24 | EndProject
25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreamExtended", "StreamExtended\StreamExtended.csproj", "{C8424BCB-2AF7-40A2-84CA-D6BB0A1CAC66}"
26 | EndProject
27 | Global
28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
29 | Debug|Any CPU = Debug|Any CPU
30 | Release|Any CPU = Release|Any CPU
31 | EndGlobalSection
32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
33 | {3F003BC6-96BC-46D7-9BA4-59EFA5ECA430}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {3F003BC6-96BC-46D7-9BA4-59EFA5ECA430}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {3F003BC6-96BC-46D7-9BA4-59EFA5ECA430}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {3F003BC6-96BC-46D7-9BA4-59EFA5ECA430}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {D9576E71-6909-460B-963A-0F6514213E4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {D9576E71-6909-460B-963A-0F6514213E4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {D9576E71-6909-460B-963A-0F6514213E4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {D9576E71-6909-460B-963A-0F6514213E4D}.Release|Any CPU.Build.0 = Release|Any CPU
41 | {C6B00692-3805-4B38-B80F-374D66755C7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {C6B00692-3805-4B38-B80F-374D66755C7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {C6B00692-3805-4B38-B80F-374D66755C7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {C6B00692-3805-4B38-B80F-374D66755C7E}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {7425DC58-2A92-4587-855C-B6703FAA0F09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 | {7425DC58-2A92-4587-855C-B6703FAA0F09}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 | {7425DC58-2A92-4587-855C-B6703FAA0F09}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {7425DC58-2A92-4587-855C-B6703FAA0F09}.Release|Any CPU.Build.0 = Release|Any CPU
49 | {12B646D2-96E3-449A-8AC5-9C0E0DC833DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {12B646D2-96E3-449A-8AC5-9C0E0DC833DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {12B646D2-96E3-449A-8AC5-9C0E0DC833DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
52 | {12B646D2-96E3-449A-8AC5-9C0E0DC833DE}.Release|Any CPU.Build.0 = Release|Any CPU
53 | {652125DB-ECD4-4693-919B-054CE32A4772}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
54 | {652125DB-ECD4-4693-919B-054CE32A4772}.Debug|Any CPU.Build.0 = Debug|Any CPU
55 | {652125DB-ECD4-4693-919B-054CE32A4772}.Release|Any CPU.ActiveCfg = Release|Any CPU
56 | {652125DB-ECD4-4693-919B-054CE32A4772}.Release|Any CPU.Build.0 = Release|Any CPU
57 | {45D341B4-1355-4581-B17B-16009D534888}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
58 | {45D341B4-1355-4581-B17B-16009D534888}.Debug|Any CPU.Build.0 = Debug|Any CPU
59 | {45D341B4-1355-4581-B17B-16009D534888}.Release|Any CPU.ActiveCfg = Release|Any CPU
60 | {45D341B4-1355-4581-B17B-16009D534888}.Release|Any CPU.Build.0 = Release|Any CPU
61 | {C8424BCB-2AF7-40A2-84CA-D6BB0A1CAC66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
62 | {C8424BCB-2AF7-40A2-84CA-D6BB0A1CAC66}.Debug|Any CPU.Build.0 = Debug|Any CPU
63 | {C8424BCB-2AF7-40A2-84CA-D6BB0A1CAC66}.Release|Any CPU.ActiveCfg = Release|Any CPU
64 | {C8424BCB-2AF7-40A2-84CA-D6BB0A1CAC66}.Release|Any CPU.Build.0 = Release|Any CPU
65 | EndGlobalSection
66 | GlobalSection(SolutionProperties) = preSolution
67 | HideSolutionNode = FALSE
68 | EndGlobalSection
69 | GlobalSection(ExtensibilityGlobals) = postSolution
70 | SolutionGuid = {7E185415-7455-410D-8AAD-3EB9A54407AF}
71 | EndGlobalSection
72 | GlobalSection(MonoDevelopProperties) = preSolution
73 | StartupItem = WatsonSyslog\SyslogServer.csproj
74 | EndGlobalSection
75 | EndGlobal
76 |
--------------------------------------------------------------------------------
/StreamExtended/Network/CopyStream.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace StreamExtended.Network
6 | {
7 | ///
8 | /// Copies the source stream to destination stream.
9 | /// But this let users to peek and read the copying process.
10 | ///
11 | public class CopyStream : ICustomStreamReader, IDisposable
12 | {
13 | private readonly ICustomStreamReader reader;
14 |
15 | private readonly ICustomStreamWriter writer;
16 |
17 | private readonly IBufferPool bufferPool;
18 |
19 | public int BufferSize { get; }
20 |
21 | private int bufferLength;
22 |
23 | private byte[] buffer;
24 |
25 | private bool disposed;
26 |
27 | public int Available => reader.Available;
28 |
29 | public bool DataAvailable => reader.DataAvailable;
30 |
31 | public long ReadBytes { get; private set; }
32 |
33 | public CopyStream(ICustomStreamReader reader, ICustomStreamWriter writer, IBufferPool bufferPool, int bufferSize)
34 | {
35 | this.reader = reader;
36 | this.writer = writer;
37 | BufferSize = bufferSize;
38 | buffer = bufferPool.GetBuffer(bufferSize);
39 | }
40 |
41 | public async Task FillBufferAsync(CancellationToken cancellationToken = default(CancellationToken))
42 | {
43 | await FlushAsync(cancellationToken);
44 | return await reader.FillBufferAsync(cancellationToken);
45 | }
46 |
47 | public byte PeekByteFromBuffer(int index)
48 | {
49 | return reader.PeekByteFromBuffer(index);
50 | }
51 |
52 | public Task PeekByteAsync(int index, CancellationToken cancellationToken = default(CancellationToken))
53 | {
54 | return reader.PeekByteAsync(index, cancellationToken);
55 | }
56 |
57 | public Task PeekBytesAsync(int index, int size, CancellationToken cancellationToken = default(CancellationToken))
58 | {
59 | return reader.PeekBytesAsync(index, size, cancellationToken);
60 | }
61 |
62 | public void Flush()
63 | {
64 | //send out the current data from from the buffer
65 | if (bufferLength > 0)
66 | {
67 | writer.Write(buffer, 0, bufferLength);
68 | bufferLength = 0;
69 | }
70 | }
71 |
72 | public async Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
73 | {
74 | //send out the current data from from the buffer
75 | if (bufferLength > 0)
76 | {
77 | await writer.WriteAsync(buffer, 0, bufferLength, cancellationToken);
78 | bufferLength = 0;
79 | }
80 | }
81 |
82 | public byte ReadByteFromBuffer()
83 | {
84 | byte b = reader.ReadByteFromBuffer();
85 | buffer[bufferLength++] = b;
86 | ReadBytes++;
87 | return b;
88 | }
89 |
90 | public int Read(byte[] buffer, int offset, int count)
91 | {
92 | int result = reader.Read(buffer, offset, count);
93 | if (result > 0)
94 | {
95 | if (bufferLength + result > BufferSize)
96 | {
97 | Flush();
98 | }
99 |
100 | Buffer.BlockCopy(buffer, offset, this.buffer, bufferLength, result);
101 | bufferLength += result;
102 | ReadBytes += result;
103 | Flush();
104 | }
105 |
106 | return result;
107 | }
108 |
109 | public async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken = default(CancellationToken))
110 | {
111 | int result = await reader.ReadAsync(buffer, offset, count, cancellationToken);
112 | if (result > 0)
113 | {
114 | if (bufferLength + result > BufferSize)
115 | {
116 | await FlushAsync(cancellationToken);
117 | }
118 |
119 | Buffer.BlockCopy(buffer, offset, this.buffer, bufferLength, result);
120 | bufferLength += result;
121 | ReadBytes += result;
122 | await FlushAsync(cancellationToken);
123 | }
124 |
125 | return result;
126 | }
127 |
128 | public Task ReadLineAsync(CancellationToken cancellationToken = default(CancellationToken))
129 | {
130 | return CustomBufferedStream.ReadLineInternalAsync(this, bufferPool, cancellationToken);
131 | }
132 |
133 | public void Dispose()
134 | {
135 | if (!disposed)
136 | {
137 | disposed = true;
138 | var b = buffer;
139 | buffer = null;
140 | bufferPool.ReturnBuffer(b);
141 | }
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/StreamExtended/Network/ServerHelloAlpnAdderStream.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.IO;
3 | using System.Threading;
4 |
5 | namespace StreamExtended.Network
6 | {
7 | public class ServerHelloAlpnAdderStream : Stream
8 | {
9 | private readonly IBufferPool bufferPool;
10 | private readonly CustomBufferedStream stream;
11 |
12 | private bool called;
13 |
14 | public ServerHelloAlpnAdderStream(CustomBufferedStream stream, IBufferPool bufferPool)
15 | {
16 | this.bufferPool = bufferPool;
17 | this.stream = stream;
18 | }
19 |
20 | public override void Flush()
21 | {
22 | stream.Flush();
23 | }
24 |
25 | public override long Seek(long offset, SeekOrigin origin)
26 | {
27 | return stream.Seek(offset, origin);
28 | }
29 |
30 | public override void SetLength(long value)
31 | {
32 | stream.SetLength(value);
33 | }
34 |
35 | [DebuggerStepThrough]
36 | public override int Read(byte[] buffer, int offset, int count)
37 | {
38 | return stream.Read(buffer, offset, count);
39 | }
40 |
41 | public override void Write(byte[] buffer, int offset, int count)
42 | {
43 | if (called)
44 | {
45 | stream.Write(buffer, offset, count);
46 | return;
47 | }
48 |
49 | called = true;
50 | var ms = new MemoryStream(buffer, offset, count);
51 |
52 | //this can be non async, because reads from a memory stream
53 | var cts = new CancellationTokenSource();
54 | var serverHello = SslTools.PeekServerHello(new CustomBufferedStream(ms, bufferPool, (int)ms.Length), bufferPool, cts.Token).Result;
55 | if (serverHello != null)
56 | {
57 | // 0x00 0x10: ALPN identifier
58 | // 0x00 0x0e: length of ALPN data
59 | // 0x00 0x0c: length of ALPN data again:)
60 | var dataToAdd = new byte[]
61 | {
62 | 0x0, 0x10, 0x0, 0x5, 0x0, 0x3,
63 | 2, (byte)'h', (byte)'2'
64 | };
65 |
66 | int newByteCount = serverHello.Extensions == null ? dataToAdd.Length + 2 : dataToAdd.Length;
67 | var buffer2 = new byte[buffer.Length + newByteCount];
68 |
69 | for (int i = 0; i < buffer.Length; i++)
70 | {
71 | buffer2[i] = buffer[i];
72 | }
73 |
74 | //this is a hacky solution, but works
75 | int length = (buffer[offset + 3] << 8) + buffer[offset + 4];
76 | length += newByteCount;
77 | buffer2[offset + 3] = (byte)(length >> 8);
78 | buffer2[offset + 4] = (byte)length;
79 |
80 | length = (buffer[offset + 6] << 16) + (buffer[offset + 7] << 8) + buffer[offset + 8];
81 | length += newByteCount;
82 | buffer2[offset + 6] = (byte)(length >> 16);
83 | buffer2[offset + 7] = (byte)(length >> 8);
84 | buffer2[offset + 8] = (byte)length;
85 |
86 | int pos = offset + serverHello.EntensionsStartPosition;
87 | int endPos = offset + serverHello.ServerHelloLength;
88 | if (serverHello.Extensions != null)
89 | {
90 | // update ALPN length
91 | length = (buffer[pos] << 8) + buffer[pos + 1];
92 | length += newByteCount;
93 | buffer2[pos] = (byte)(length >> 8);
94 | buffer2[pos + 1] = (byte)length;
95 | }
96 | else
97 | {
98 | // add ALPN length
99 | length = dataToAdd.Length;
100 | buffer2[pos] = (byte)(length >> 8);
101 | buffer2[pos + 1] = (byte)length;
102 | endPos += 2;
103 | }
104 |
105 | for (int i = 0; i < dataToAdd.Length; i++)
106 | {
107 | buffer2[endPos + i] = dataToAdd[i];
108 | }
109 |
110 | // copy the reamining data if any
111 | for (int i = serverHello.ServerHelloLength; i < count; i++)
112 | {
113 | buffer2[offset + newByteCount + i] = buffer[offset + i];
114 | }
115 |
116 | buffer = buffer2;
117 | count += newByteCount;
118 | }
119 |
120 | stream.Write(buffer, offset, count);
121 | }
122 |
123 | public override bool CanRead => stream.CanRead;
124 |
125 | public override bool CanSeek => stream.CanSeek;
126 |
127 | public override bool CanWrite => stream.CanWrite;
128 |
129 | public override long Length => stream.Length;
130 |
131 | public override long Position
132 | {
133 | get => stream.Position;
134 | set => stream.Position = value;
135 | }
136 | }
137 | }
--------------------------------------------------------------------------------
/StreamExtended/Network/ClientHelloAlpnAdderStream.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.IO;
3 | using System.Threading;
4 |
5 | namespace StreamExtended.Network
6 | {
7 | public class ClientHelloAlpnAdderStream : Stream
8 | {
9 | private readonly CustomBufferedStream stream;
10 | private readonly IBufferPool bufferPool;
11 |
12 | private bool called;
13 |
14 | public ClientHelloAlpnAdderStream(CustomBufferedStream stream, IBufferPool bufferPool)
15 | {
16 | this.stream = stream;
17 | }
18 |
19 | public override void Flush()
20 | {
21 | stream.Flush();
22 | }
23 |
24 | public override long Seek(long offset, SeekOrigin origin)
25 | {
26 | return stream.Seek(offset, origin);
27 | }
28 |
29 | public override void SetLength(long value)
30 | {
31 | stream.SetLength(value);
32 | }
33 |
34 | [DebuggerStepThrough]
35 | public override int Read(byte[] buffer, int offset, int count)
36 | {
37 | return stream.Read(buffer, offset, count);
38 | }
39 |
40 | public override void Write(byte[] buffer, int offset, int count)
41 | {
42 | if (called)
43 | {
44 | stream.Write(buffer, offset, count);
45 | return;
46 | }
47 |
48 | called = true;
49 | var ms = new MemoryStream(buffer, offset, count);
50 |
51 | //this can be non async, because reads from a memory stream
52 | var cts = new CancellationTokenSource();
53 | var clientHello = SslTools.PeekClientHello(new CustomBufferedStream(ms, bufferPool, (int)ms.Length), bufferPool, cts.Token).Result;
54 | if (clientHello != null)
55 | {
56 | // 0x00 0x10: ALPN identifier
57 | // 0x00 0x0e: length of ALPN data
58 | // 0x00 0x0c: length of ALPN data again:)
59 | var dataToAdd = new byte[]
60 | {
61 | 0x0, 0x10, 0x0, 0xE, 0x0, 0xC,
62 | 2, (byte)'h', (byte)'2',
63 | 8, (byte)'h', (byte)'t', (byte)'t', (byte)'p', (byte)'/', (byte)'1', (byte)'.', (byte)'1'
64 | };
65 |
66 | int newByteCount = clientHello.Extensions == null ? dataToAdd.Length + 2 : dataToAdd.Length;
67 | var buffer2 = new byte[buffer.Length + newByteCount];
68 |
69 | for (int i = 0; i < buffer.Length; i++)
70 | {
71 | buffer2[i] = buffer[i];
72 | }
73 |
74 | //this is a hacky solution, but works
75 | int length = (buffer[offset + 3] << 8) + buffer[offset + 4];
76 | length += newByteCount;
77 | buffer2[offset + 3] = (byte)(length >> 8);
78 | buffer2[offset + 4] = (byte)length;
79 |
80 | length = (buffer[offset + 6] << 16) + (buffer[offset + 7] << 8) + buffer[offset + 8];
81 | length += newByteCount;
82 | buffer2[offset + 6] = (byte)(length >> 16);
83 | buffer2[offset + 7] = (byte)(length >> 8);
84 | buffer2[offset + 8] = (byte)length;
85 |
86 | int pos = offset + clientHello.EntensionsStartPosition;
87 | int endPos = offset + clientHello.ClientHelloLength;
88 | if (clientHello.Extensions != null)
89 | {
90 | // update ALPN length
91 | length = (buffer[pos] << 8) + buffer[pos + 1];
92 | length += newByteCount;
93 | buffer2[pos] = (byte)(length >> 8);
94 | buffer2[pos + 1] = (byte)length;
95 | }
96 | else
97 | {
98 | // add ALPN length
99 | length = dataToAdd.Length;
100 | buffer2[pos] = (byte)(length >> 8);
101 | buffer2[pos + 1] = (byte)length;
102 | endPos += 2;
103 | }
104 |
105 | for (int i = 0; i < dataToAdd.Length; i++)
106 | {
107 | buffer2[endPos + i] = dataToAdd[i];
108 | }
109 |
110 | // copy the reamining data if any
111 | for (int i = clientHello.ClientHelloLength; i < count; i++)
112 | {
113 | buffer2[offset + newByteCount + i] = buffer[offset + i];
114 | }
115 |
116 | buffer = buffer2;
117 | count += newByteCount;
118 | }
119 |
120 | stream.Write(buffer, offset, count);
121 | }
122 |
123 | public override bool CanRead => stream.CanRead;
124 |
125 | public override bool CanSeek => stream.CanSeek;
126 |
127 | public override bool CanWrite => stream.CanWrite;
128 |
129 | public override long Length => stream.Length;
130 |
131 | public override long Position
132 | {
133 | get => stream.Position;
134 | set => stream.Position = value;
135 | }
136 | }
137 | }
--------------------------------------------------------------------------------
/libSyslogServer/Classes/Common.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace libSyslogServer
3 | {
4 |
5 |
6 | ///
7 | /// Commonly used static methods.
8 | ///
9 | public static class Common
10 | {
11 |
12 |
13 | public static string SerializeJson(object obj)
14 | {
15 | if (obj == null) return null;
16 | string json = Newtonsoft.Json.JsonConvert.SerializeObject(
17 | obj,
18 | Newtonsoft.Json.Formatting.Indented,
19 | new Newtonsoft.Json.JsonSerializerSettings
20 | {
21 | DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc
22 | });
23 |
24 | return json;
25 | }
26 |
27 | public static T DeserializeJson(string json)
28 | {
29 | if (string.IsNullOrEmpty(json)) throw new System.ArgumentNullException(nameof(json));
30 |
31 | try
32 | {
33 | return Newtonsoft.Json.JsonConvert.DeserializeObject(json);
34 | }
35 | catch (System.Exception)
36 | {
37 | System.Console.WriteLine("");
38 | System.Console.WriteLine("Exception while deserializing:");
39 | System.Console.WriteLine(json);
40 | System.Console.WriteLine("");
41 | throw;
42 | }
43 | }
44 |
45 | public static T DeserializeJson(byte[] data)
46 | {
47 | if (data == null || data.Length < 1) throw new System.ArgumentNullException(nameof(data));
48 | return DeserializeJson(System.Text.Encoding.UTF8.GetString(data));
49 | }
50 |
51 | public static bool InputBoolean(string question, bool yesDefault)
52 | {
53 | System.Console.Write(question);
54 |
55 | if (yesDefault) System.Console.Write(" [Y/n]? ");
56 | else System.Console.Write(" [y/N]? ");
57 |
58 | string userInput = System.Console.ReadLine();
59 |
60 | if (string.IsNullOrEmpty(userInput))
61 | {
62 | if (yesDefault) return true;
63 | return false;
64 | }
65 |
66 | userInput = userInput.ToLower();
67 |
68 | if (yesDefault)
69 | {
70 | if (
71 | (System.String.Compare(userInput, "n") == 0)
72 | || (System.String.Compare(userInput, "no") == 0)
73 | )
74 | {
75 | return false;
76 | }
77 |
78 | return true;
79 | }
80 | else
81 | {
82 | if (
83 | (System.String.Compare(userInput, "y") == 0)
84 | || (System.String.Compare(userInput, "yes") == 0)
85 | )
86 | {
87 | return true;
88 | }
89 |
90 | return false;
91 | }
92 | }
93 |
94 | public static string InputString(string question, string defaultAnswer, bool allowNull)
95 | {
96 | while (true)
97 | {
98 | System.Console.Write(question);
99 |
100 | if (!string.IsNullOrEmpty(defaultAnswer))
101 | {
102 | System.Console.Write(" [" + defaultAnswer + "]");
103 | }
104 |
105 | System.Console.Write(" ");
106 |
107 | string userInput = System.Console.ReadLine();
108 |
109 | if (string.IsNullOrEmpty(userInput))
110 | {
111 | if (!string.IsNullOrEmpty(defaultAnswer)) return defaultAnswer;
112 | if (allowNull) return null;
113 | else continue;
114 | }
115 |
116 | return userInput;
117 | }
118 | }
119 |
120 | public static int InputInteger(string question, int defaultAnswer, bool positiveOnly, bool allowZero)
121 | {
122 | while (true)
123 | {
124 | System.Console.Write(question);
125 | System.Console.Write(" [" + defaultAnswer + "] ");
126 |
127 | string userInput = System.Console.ReadLine();
128 |
129 | if (string.IsNullOrEmpty(userInput))
130 | {
131 | return defaultAnswer;
132 | }
133 |
134 | int ret = 0;
135 | if (!int.TryParse(userInput, out ret))
136 | {
137 | System.Console.WriteLine("Please enter a valid integer.");
138 | continue;
139 | }
140 |
141 | if (ret == 0)
142 | {
143 | if (allowZero)
144 | {
145 | return 0;
146 | }
147 | }
148 |
149 | if (ret < 0)
150 | {
151 | if (positiveOnly)
152 | {
153 | System.Console.WriteLine("Please enter a value greater than zero.");
154 | continue;
155 | }
156 | }
157 |
158 | return ret;
159 | }
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/StreamExtended/Network/CustomBufferedPeekStream.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace StreamExtended.Network
5 | {
6 | internal class CustomBufferedPeekStream : ICustomStreamReader
7 | {
8 | private readonly IBufferPool bufferPool;
9 | private readonly ICustomStreamReader baseStream;
10 |
11 | internal int Position { get; private set; }
12 |
13 | internal CustomBufferedPeekStream(ICustomStreamReader baseStream, IBufferPool bufferPool, int startPosition = 0)
14 | {
15 | this.bufferPool = bufferPool;
16 | this.baseStream = baseStream;
17 | Position = startPosition;
18 | }
19 |
20 | int ICustomStreamReader.BufferSize => baseStream.BufferSize;
21 |
22 | ///
23 | /// Gets a value indicating whether data is available.
24 | ///
25 | bool ICustomStreamReader.DataAvailable => Available > 0;
26 |
27 | ///
28 | /// Gets the available data size.
29 | ///
30 | public int Available => baseStream.Available - Position;
31 |
32 | internal async Task EnsureBufferLength(int length, CancellationToken cancellationToken)
33 | {
34 | var val = await baseStream.PeekByteAsync(Position + length - 1, cancellationToken);
35 | return val != -1;
36 | }
37 |
38 | internal byte ReadByte()
39 | {
40 | return baseStream.PeekByteFromBuffer(Position++);
41 | }
42 |
43 | internal int ReadInt16()
44 | {
45 | int i1 = ReadByte();
46 | int i2 = ReadByte();
47 | return (i1 << 8) + i2;
48 | }
49 |
50 | internal int ReadInt24()
51 | {
52 | int i1 = ReadByte();
53 | int i2 = ReadByte();
54 | int i3 = ReadByte();
55 | return (i1 << 16) + (i2 << 8) + i3;
56 | }
57 |
58 | internal byte[] ReadBytes(int length)
59 | {
60 | var buffer = new byte[length];
61 | for (int i = 0; i < buffer.Length; i++)
62 | {
63 | buffer[i] = ReadByte();
64 | }
65 |
66 | return buffer;
67 | }
68 |
69 | ///
70 | /// Fills the buffer asynchronous.
71 | ///
72 | ///
73 | Task ICustomStreamReader.FillBufferAsync(CancellationToken cancellationToken)
74 | {
75 | return baseStream.FillBufferAsync(cancellationToken);
76 | }
77 |
78 | ///
79 | /// Peeks a byte from buffer.
80 | ///
81 | /// The index.
82 | ///
83 | byte ICustomStreamReader.PeekByteFromBuffer(int index)
84 | {
85 | return baseStream.PeekByteFromBuffer(index);
86 | }
87 |
88 | ///
89 | /// Peeks bytes asynchronous.
90 | ///
91 | /// The index.
92 | /// The cancellation token.
93 | ///
94 | Task ICustomStreamReader.PeekBytesAsync(int index, int size, CancellationToken cancellationToken)
95 | {
96 | return baseStream.PeekBytesAsync(index, size, cancellationToken);
97 | }
98 |
99 | ///
100 | /// Peeks a byte asynchronous.
101 | ///
102 | /// The index.
103 | /// The cancellation token.
104 | ///
105 | Task ICustomStreamReader.PeekByteAsync(int index, CancellationToken cancellationToken)
106 | {
107 | return baseStream.PeekByteAsync(index, cancellationToken);
108 | }
109 |
110 | ///
111 | /// Reads a byte from buffer.
112 | ///
113 | ///
114 | /// Buffer is empty
115 | byte ICustomStreamReader.ReadByteFromBuffer()
116 | {
117 | return ReadByte();
118 | }
119 |
120 | int ICustomStreamReader.Read(byte[] buffer, int offset, int count)
121 | {
122 | return baseStream.Read(buffer, offset, count);
123 | }
124 |
125 | ///
126 | /// Reads the asynchronous.
127 | ///
128 | /// The buffer.
129 | /// The offset.
130 | /// The count.
131 | /// The cancellation token.
132 | ///
133 | Task ICustomStreamReader.ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
134 | {
135 | return baseStream.ReadAsync(buffer, offset, count, cancellationToken);
136 | }
137 |
138 | ///
139 | /// Read a line from the byte stream
140 | ///
141 | ///
142 | ///
143 | Task ICustomStreamReader.ReadLineAsync(CancellationToken cancellationToken)
144 | {
145 | return CustomBufferedStream.ReadLineInternalAsync(this, bufferPool, cancellationToken);
146 | }
147 |
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
--------------------------------------------------------------------------------
/NetCoreServer/WsServer.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Text;
3 |
4 | namespace NetCoreServer
5 | {
6 | ///
7 | /// WebSocket server
8 | ///
9 | /// WebSocket server is used to communicate with clients using WebSocket protocol. Thread-safe.
10 | public class WsServer : HttpServer, IWebSocket
11 | {
12 | internal readonly WebSocket WebSocket;
13 |
14 | ///
15 | /// Initialize WebSocket server with a given IP address and port number
16 | ///
17 | /// IP address
18 | /// Port number
19 | public WsServer(IPAddress address, int port) : base(address, port) { WebSocket = new WebSocket(this); }
20 | ///
21 | /// Initialize WebSocket server with a given IP address and port number
22 | ///
23 | /// IP address
24 | /// Port number
25 | public WsServer(string address, int port) : base(address, port) { WebSocket = new WebSocket(this); }
26 | ///
27 | /// Initialize WebSocket server with a given IP endpoint
28 | ///
29 | /// IP endpoint
30 | public WsServer(IPEndPoint endpoint) : base(endpoint) { WebSocket = new WebSocket(this); }
31 |
32 | public virtual bool CloseAll(int status)
33 | {
34 | lock (WebSocket.WsSendLock)
35 | {
36 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_CLOSE, false, null, 0, 0, status);
37 | if (!Multicast(WebSocket.WsSendBuffer.ToArray()))
38 | return false;
39 |
40 | return base.DisconnectAll();
41 | }
42 | }
43 |
44 | public override bool Multicast(byte[] buffer, long offset, long size)
45 | {
46 | if (!IsStarted)
47 | return false;
48 |
49 | if (size == 0)
50 | return true;
51 |
52 | // Multicast data to all WebSocket sessions
53 | foreach (var session in Sessions.Values)
54 | {
55 | if (session is WsSession wsSession)
56 | {
57 | if (wsSession.WebSocket.WsHandshaked)
58 | wsSession.SendAsync(buffer, offset, size);
59 | }
60 | }
61 |
62 | return true;
63 | }
64 |
65 | #region WebSocket multicast text methods
66 |
67 | public bool MulticastText(byte[] buffer, long offset, long size)
68 | {
69 | lock (WebSocket.WsSendLock)
70 | {
71 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_TEXT, false, buffer, offset, size);
72 | return Multicast(WebSocket.WsSendBuffer.ToArray());
73 | }
74 | }
75 |
76 | public bool MulticastText(string text)
77 | {
78 | lock (WebSocket.WsSendLock)
79 | {
80 | var data = Encoding.UTF8.GetBytes(text);
81 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_TEXT, false, data, 0, data.Length);
82 | return Multicast(WebSocket.WsSendBuffer.ToArray());
83 | }
84 | }
85 |
86 | #endregion
87 |
88 | #region WebSocket multicast binary methods
89 |
90 | public bool MulticastBinary(byte[] buffer, long offset, long size)
91 | {
92 | lock (WebSocket.WsSendLock)
93 | {
94 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_BINARY, false, buffer, offset, size);
95 | return Multicast(WebSocket.WsSendBuffer.ToArray());
96 | }
97 | }
98 |
99 | public bool MulticastBinary(string text)
100 | {
101 | lock (WebSocket.WsSendLock)
102 | {
103 | var data = Encoding.UTF8.GetBytes(text);
104 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_BINARY, false, data, 0, data.Length);
105 | return Multicast(WebSocket.WsSendBuffer.ToArray());
106 | }
107 | }
108 |
109 | #endregion
110 |
111 | #region WebSocket multicast ping methods
112 |
113 | public bool SendPing(byte[] buffer, long offset, long size)
114 | {
115 | lock (WebSocket.WsSendLock)
116 | {
117 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_PING, false, buffer, offset, size);
118 | return Multicast(WebSocket.WsSendBuffer.ToArray());
119 | }
120 | }
121 |
122 | public bool SendPing(string text)
123 | {
124 | lock (WebSocket.WsSendLock)
125 | {
126 | var data = Encoding.UTF8.GetBytes(text);
127 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_PING, false, data, 0, data.Length);
128 | return Multicast(WebSocket.WsSendBuffer.ToArray());
129 | }
130 | }
131 |
132 | #endregion
133 |
134 | #region WebSocket multicast pong methods
135 |
136 | public bool SendPong(byte[] buffer, long offset, long size)
137 | {
138 | lock (WebSocket.WsSendLock)
139 | {
140 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_PONG, false, buffer, offset, size);
141 | return Multicast(WebSocket.WsSendBuffer.ToArray());
142 | }
143 | }
144 |
145 | public bool SendPong(string text)
146 | {
147 | lock (WebSocket.WsSendLock)
148 | {
149 | var data = Encoding.UTF8.GetBytes(text);
150 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_PONG, false, data, 0, data.Length);
151 | return Multicast(WebSocket.WsSendBuffer.ToArray());
152 | }
153 | }
154 |
155 | #endregion
156 |
157 | protected override TcpSession CreateSession() { return new WsSession(this); }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/SelfSignedCertificate/Helpers/NonBackdooredPrng.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SelfSignedCertificate
3 | {
4 |
5 |
6 | public abstract class NonBackdooredPrng : Org.BouncyCastle.Crypto.Prng.IRandomGenerator
7 | {
8 | public abstract void AddSeedMaterial(byte[] seed);
9 | public abstract void AddSeedMaterial(long seed);
10 | public abstract void NextBytes(byte[] bytes);
11 | public abstract void NextBytes(byte[] bytes, int start, int len);
12 |
13 |
14 | public static NonBackdooredPrng Create()
15 | {
16 | bool isWindows =
17 | System.Runtime.InteropServices.RuntimeInformation
18 | .IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows);
19 |
20 | if (isWindows)
21 | return new WindowsPrng();
22 |
23 | return new PosixPrng();
24 | } // End Function Create
25 |
26 |
27 | public static Org.BouncyCastle.Security.SecureRandom SecureRandom
28 | {
29 | get
30 | {
31 | return new Org.BouncyCastle.Security.SecureRandom(
32 | NonBackdooredPrng.Create()
33 | );
34 | }
35 | }
36 |
37 |
38 | } // End Class NonBackdooredPrng
39 |
40 |
41 |
42 | public class WindowsPrng : NonBackdooredPrng
43 | {
44 | protected Org.BouncyCastle.Crypto.Prng.IRandomGenerator m_rnd;
45 |
46 | public WindowsPrng()
47 | {
48 | // this.m_rnd = new Org.BouncyCastle.Crypto.Prng.CryptoApiRandomGenerator();
49 |
50 | const string digestName = "SHA256";
51 | Org.BouncyCastle.Crypto.IDigest digest = Org.BouncyCastle.Security.DigestUtilities.GetDigest(digestName);
52 | if (digest == null)
53 | return;
54 |
55 | Org.BouncyCastle.Crypto.Prng.DigestRandomGenerator prng =
56 | new Org.BouncyCastle.Crypto.Prng.DigestRandomGenerator(digest);
57 |
58 | const bool autoSeed = true;
59 | if (autoSeed)
60 | {
61 | // prng.AddSeedMaterial(NextCounterValue());
62 | // prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize()));
63 | }
64 |
65 | this.m_rnd = prng;
66 | }
67 |
68 |
69 | /// Add more seed material to the generator.
70 | /// A byte array to be mixed into the generator's state.
71 | public override void AddSeedMaterial(byte[] seed)
72 | {
73 | this.m_rnd.AddSeedMaterial(seed);
74 | } // End Sub AddSeedMaterial
75 |
76 |
77 | /// Add more seed material to the generator.
78 | /// A long value to be mixed into the generator's state.
79 | public override void AddSeedMaterial(long seed)
80 | {
81 | this.m_rnd.AddSeedMaterial(seed);
82 | } // End Sub AddSeedMaterial
83 |
84 |
85 | /// Fill byte array with random values.
86 | /// Array to be filled.
87 | public override void NextBytes(byte[] bytes)
88 | {
89 | this.m_rnd.NextBytes(bytes);
90 | } // End Sub NextBytes
91 |
92 |
93 | /// Fill byte array with random values.
94 | /// Array to receive bytes.
95 | /// Index to start filling at.
96 | /// Length of segment to fill.
97 | public override void NextBytes(byte[] bytes, int start, int len)
98 | {
99 | this.m_rnd.NextBytes(bytes, start, len);
100 | } // End Sub NextBytes
101 |
102 | } // End Class WindowsPrng
103 |
104 |
105 | public class PosixPrng : NonBackdooredPrng
106 | {
107 | // Early boot on a very low entropy device.
108 | // The /dev/urandom device cannot guarantee
109 | // that it has received enough initial entropy,
110 | // while when using /dev/random that is guaranteed
111 | // (even if it may block).
112 | // therefore, use /dev/urandom
113 |
114 | // /dev/random // potentially blocking
115 | // /dev/urandom
116 |
117 |
118 | /// Add more seed material to the generator.
119 | /// A byte array to be mixed into the generator's state.
120 | public override void AddSeedMaterial(byte[] seed)
121 | {
122 | // throw new System.NotImplementedException();
123 | } // End Sub AddSeedMaterial
124 |
125 |
126 | /// Add more seed material to the generator.
127 | /// A long value to be mixed into the generator's state.
128 | public override void AddSeedMaterial(long seed)
129 | {
130 | // throw new System.NotImplementedException();
131 | } // End Sub AddSeedMaterial
132 |
133 |
134 | /// Fill byte array with random values.
135 | /// Array to be filled.
136 | public override void NextBytes(byte[] bytes)
137 | {
138 | using (System.IO.FileStream fs =
139 | new System.IO.FileStream(
140 | "/dev/urandom"
141 | , System.IO.FileMode.Open
142 | , System.IO.FileAccess.Read))
143 | {
144 | fs.Read(bytes, 0, bytes.Length);
145 | }
146 |
147 | } // End Sub NextBytes
148 |
149 |
150 | /// Fill byte array with random values.
151 | /// Array to receive bytes.
152 | /// Index to start filling at.
153 | /// Length of segment to fill.
154 | public override void NextBytes(byte[] bytes, int start, int len)
155 | {
156 | using (System.IO.FileStream fs =
157 | new System.IO.FileStream(
158 | "/dev/urandom"
159 | , System.IO.FileMode.Open
160 | , System.IO.FileAccess.Read))
161 | {
162 | fs.Read(bytes, start, len);
163 | }
164 |
165 | } // End Sub NextBytes
166 |
167 |
168 | } // End Class LinuxPrng
169 |
170 |
171 | } // End Namespace CoreCMS.JWT
172 |
--------------------------------------------------------------------------------
/NetCoreServer/WssServer.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Text;
3 |
4 | namespace NetCoreServer
5 | {
6 | ///
7 | /// WebSocket secure server
8 | ///
9 | /// WebSocket secure server is used to communicate with clients using WebSocket protocol. Thread-safe.
10 | public class WssServer : HttpsServer, IWebSocket
11 | {
12 | internal readonly WebSocket WebSocket;
13 |
14 | ///
15 | /// Initialize WebSocket server with a given IP address and port number
16 | ///
17 | /// SSL context
18 | /// IP address
19 | /// Port number
20 | public WssServer(SslContext context, IPAddress address, int port) : base(context, address, port) { WebSocket = new WebSocket(this); }
21 | ///
22 | /// Initialize WebSocket server with a given IP address and port number
23 | ///
24 | /// SSL context
25 | /// IP address
26 | /// Port number
27 | public WssServer(SslContext context, string address, int port) : base(context, address, port) { WebSocket = new WebSocket(this); }
28 | ///
29 | /// Initialize WebSocket server with a given IP endpoint
30 | ///
31 | /// SSL context
32 | /// IP endpoint
33 | public WssServer(SslContext context, IPEndPoint endpoint) : base(context, endpoint) { WebSocket = new WebSocket(this); }
34 |
35 | public virtual bool CloseAll(int status)
36 | {
37 | lock (WebSocket.WsSendLock)
38 | {
39 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_CLOSE, false, null, 0, 0, status);
40 | if (!Multicast(WebSocket.WsSendBuffer.ToArray()))
41 | return false;
42 |
43 | return base.DisconnectAll();
44 | }
45 | }
46 |
47 | public override bool Multicast(byte[] buffer, long offset, long size)
48 | {
49 | if (!IsStarted)
50 | return false;
51 |
52 | if (size == 0)
53 | return true;
54 |
55 | // Multicast data to all WebSocket sessions
56 | foreach (var session in Sessions.Values)
57 | {
58 | if (session is WssSession wssSession)
59 | {
60 | if (wssSession.WebSocket.WsHandshaked)
61 | wssSession.SendAsync(buffer, offset, size);
62 | }
63 | }
64 |
65 | return true;
66 | }
67 |
68 | #region WebSocket multicast text methods
69 |
70 | public bool MulticastText(byte[] buffer, long offset, long size)
71 | {
72 | lock (WebSocket.WsSendLock)
73 | {
74 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_TEXT, false, buffer, offset, size);
75 | return Multicast(WebSocket.WsSendBuffer.ToArray());
76 | }
77 | }
78 |
79 | public bool MulticastText(string text)
80 | {
81 | lock (WebSocket.WsSendLock)
82 | {
83 | var data = Encoding.UTF8.GetBytes(text);
84 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_TEXT, false, data, 0, data.Length);
85 | return Multicast(WebSocket.WsSendBuffer.ToArray());
86 | }
87 | }
88 |
89 | #endregion
90 |
91 | #region WebSocket multicast binary methods
92 |
93 | public bool MulticastBinary(byte[] buffer, long offset, long size)
94 | {
95 | lock (WebSocket.WsSendLock)
96 | {
97 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_BINARY, false, buffer, offset, size);
98 | return Multicast(WebSocket.WsSendBuffer.ToArray());
99 | }
100 | }
101 |
102 | public bool MulticastBinary(string text)
103 | {
104 | lock (WebSocket.WsSendLock)
105 | {
106 | var data = Encoding.UTF8.GetBytes(text);
107 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_BINARY, false, data, 0, data.Length);
108 | return Multicast(WebSocket.WsSendBuffer.ToArray());
109 | }
110 | }
111 |
112 | #endregion
113 |
114 | #region WebSocket multicast ping methods
115 |
116 | public bool SendPing(byte[] buffer, long offset, long size)
117 | {
118 | lock (WebSocket.WsSendLock)
119 | {
120 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_PING, false, buffer, offset, size);
121 | return Multicast(WebSocket.WsSendBuffer.ToArray());
122 | }
123 | }
124 |
125 | public bool SendPing(string text)
126 | {
127 | lock (WebSocket.WsSendLock)
128 | {
129 | var data = Encoding.UTF8.GetBytes(text);
130 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_PING, false, data, 0, data.Length);
131 | return Multicast(WebSocket.WsSendBuffer.ToArray());
132 | }
133 | }
134 |
135 | #endregion
136 |
137 | #region WebSocket multicast pong methods
138 |
139 | public bool SendPong(byte[] buffer, long offset, long size)
140 | {
141 | lock (WebSocket.WsSendLock)
142 | {
143 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_PONG, false, buffer, offset, size);
144 | return Multicast(WebSocket.WsSendBuffer.ToArray());
145 | }
146 | }
147 |
148 | public bool SendPong(string text)
149 | {
150 | lock (WebSocket.WsSendLock)
151 | {
152 | var data = Encoding.UTF8.GetBytes(text);
153 | WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_PONG, false, data, 0, data.Length);
154 | return Multicast(WebSocket.WsSendBuffer.ToArray());
155 | }
156 | }
157 |
158 | #endregion
159 |
160 | protected override SslSession CreateSession() { return new WssSession(this); }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/SyslogServer/Common/Rfc5424SyslogMessage.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Text.RegularExpressions;
3 |
4 |
5 | namespace SyslogServer
6 | {
7 |
8 |
9 | // https://stackoverflow.com/a/53617099/155077
10 | public class Rfc5424SyslogMessage
11 | {
12 | private static readonly string _SyslogMsgHeaderPattern = @"\<(?\d{1,3})\>(?[1-9]{0,2}) (?(\S|\w)+) (?-|(\S|\w){1,255}) (?-|(\S|\w){1,48}) (?-|(\S|\w){1,128}) (?-|(\S|\w){1,32})";
13 | private static readonly string _SyslogMsgStructuredDataPattern = @"(?-|\[[^\[\=\x22\]\x20]{1,32}( ([^\[\=\x22\]\x20]{1,32}=\x22.+\x22))?\])";
14 | private static readonly string _SyslogMsgMessagePattern = @"( (?.+))?";
15 | private static Regex _Expression = new Regex($@"^{_SyslogMsgHeaderPattern} {_SyslogMsgStructuredDataPattern}{_SyslogMsgMessagePattern}$"
16 | , RegexOptions.None
17 | , new System.TimeSpan(0, 0, 5)
18 | );
19 |
20 |
21 | // Rfc5424SyslogMessage.IsRfc5424SyslogMessage(message);
22 | public static bool IsRfc5424SyslogMessage(string syslogMessage)
23 | {
24 | Match match = _Expression.Match(syslogMessage);
25 | return match.Success;
26 | }
27 |
28 |
29 | public FacilityType Facility
30 | {
31 | get
32 | {
33 | return (FacilityType)System.Math.Floor((double)this.Prival / 8);
34 | // return FacilityType.User; // wenn nix
35 | }
36 | }
37 |
38 | public SeverityType Severity
39 | {
40 | get
41 | {
42 | return (SeverityType)(this.Prival % 8);
43 | // return SeverityType.Notice; // wenn nix
44 | }
45 | }
46 |
47 |
48 | public bool IsValid { get; private set; }
49 |
50 | public int Prival { get; private set; }
51 | public int Version { get; private set; }
52 | public System.DateTime TimeStamp { get; private set; }
53 | public string HostName { get; private set; }
54 | public string AppName { get; private set; }
55 | public string ProcId { get; private set; }
56 | public string MessageId { get; private set; }
57 | public string StructuredData { get; private set; }
58 | public string Message { get; private set; }
59 | public string RawMessage { get; private set; }
60 | public System.Exception Exception { get; private set; }
61 | public System.Exception EndpointException { get; private set; }
62 |
63 | public System.Guid PrimaryKey { get; private set; }
64 | public string SourceEndpoint { get; private set; }
65 | public string SourceIP { get; private set; }
66 | public string SourceHost { get; private set; }
67 | public System.DateTime MessageReceivedTime { get; private set; }
68 |
69 |
70 | public static Rfc5424SyslogMessage Invalid(string rawMessage, System.Exception ex)
71 | {
72 | return new Rfc5424SyslogMessage
73 | {
74 | RawMessage = rawMessage,
75 | IsValid = false,
76 | MessageReceivedTime = System.DateTime.UtcNow,
77 | Exception = ex
78 | };
79 | }
80 |
81 |
82 |
83 | public void SetSourceEndpoint(System.Net.EndPoint remoteEndpoint)
84 | {
85 | try
86 | {
87 | this.PrimaryKey = System.Guid.NewGuid();
88 | this.SourceEndpoint = remoteEndpoint.ToString();
89 | System.Net.IPEndPoint ipEndPoint = remoteEndpoint as System.Net.IPEndPoint;
90 | this.SourceIP = ipEndPoint.Address.ToString();
91 | this.SourceHost = System.Net.Dns.GetHostEntry(ipEndPoint.Address).HostName;
92 | }
93 | catch (System.Exception ex)
94 | {
95 | this.EndpointException = ex;
96 | }
97 | }
98 |
99 | public static Rfc5424SyslogMessage Invalid(string rawMessage)
100 | {
101 | return Invalid(rawMessage, null);
102 | }
103 |
104 |
105 |
106 | ///
107 | /// Parses a Syslog message in RFC 5424 format.
108 | ///
109 | ///
110 | ///
111 | ///
112 | ///
113 | public static Rfc5424SyslogMessage Parse(string rawMessage)
114 | {
115 | if (string.IsNullOrWhiteSpace(rawMessage))
116 | {
117 | throw new System.ArgumentNullException("message");
118 | }
119 |
120 | Match match = _Expression.Match(rawMessage);
121 | if (match.Success)
122 | {
123 | return new Rfc5424SyslogMessage
124 | {
125 | MessageReceivedTime = System.DateTime.UtcNow,
126 | Prival = System.Convert.ToInt32(match.Groups["PRIVAL"].Value),
127 | Version = System.Convert.ToInt32(match.Groups["VERSION"].Value),
128 | TimeStamp = System.Convert.ToDateTime(match.Groups["TIMESTAMP"].Value),
129 | HostName = match.Groups["HOSTNAME"].Value,
130 | AppName = match.Groups["APPNAME"].Value,
131 | ProcId = match.Groups["PROCID"].Value,
132 | MessageId = match.Groups["MSGID"].Value,
133 | StructuredData = match.Groups["STRUCTUREDDATA"].Value,
134 | Message = match.Groups["MESSAGE"].Value,
135 | RawMessage = rawMessage,
136 | IsValid = true
137 | };
138 | }
139 | else
140 | {
141 | return Invalid(rawMessage);
142 | }
143 | }
144 |
145 |
146 | public override string ToString()
147 | {
148 | System.Text.StringBuilder message =
149 | new System.Text.StringBuilder($@"<{Prival:###}>{Version:##} {TimeStamp.ToString("yyyy-MM-ddTHH:mm:ss.fffK")} {HostName} {AppName} {ProcId} {MessageId} {StructuredData}");
150 |
151 | if (!string.IsNullOrWhiteSpace(Message))
152 | {
153 | message.Append($" {Message}");
154 | }
155 |
156 | return message.ToString();
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/NetCoreServer/Buffer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Text;
4 |
5 | namespace NetCoreServer
6 | {
7 | ///
8 | /// Dynamic byte buffer
9 | ///
10 | public class Buffer
11 | {
12 | private byte[] _data;
13 | private long _size;
14 | private long _offset;
15 |
16 | ///
17 | /// Is the buffer empty?
18 | ///
19 | public bool IsEmpty => (_data == null) || (_size == 0);
20 | ///
21 | /// Bytes memory buffer
22 | ///
23 | public byte[] Data => _data;
24 | ///
25 | /// Bytes memory buffer capacity
26 | ///
27 | public long Capacity => _data.Length;
28 | ///
29 | /// Bytes memory buffer size
30 | ///
31 | public long Size => _size;
32 | ///
33 | /// Bytes memory buffer offset
34 | ///
35 | public long Offset => _offset;
36 |
37 | ///
38 | /// Buffer indexer operator
39 | ///
40 | public byte this[int index] => _data[index];
41 |
42 | ///
43 | /// Initialize a new expandable buffer with zero capacity
44 | ///
45 | public Buffer() { _data = new byte[0]; _size = 0; _offset = 0; }
46 | ///
47 | /// Initialize a new expandable buffer with the given capacity
48 | ///
49 | public Buffer(long capacity) { _data = new byte[capacity]; _size = 0; _offset = 0; }
50 | ///
51 | /// Initialize a new expandable buffer with the given data
52 | ///
53 | public Buffer(byte[] data) { _data = data; _size = data.Length; _offset = 0; }
54 |
55 | #region Memory buffer methods
56 |
57 | ///
58 | /// Get string from the current buffer
59 | ///
60 | public override string ToString()
61 | {
62 | return ExtractString(0, _size);
63 | }
64 |
65 | // Clear the current buffer and its offset
66 | public void Clear()
67 | {
68 | _size = 0;
69 | _offset = 0;
70 | }
71 |
72 | ///
73 | /// Extract the string from buffer of the given offset and size
74 | ///
75 | public string ExtractString(long offset, long size)
76 | {
77 | Debug.Assert(((offset + size) <= Size), "Invalid offset & size!");
78 | if ((offset + size) > Size)
79 | throw new ArgumentException("Invalid offset & size!", nameof(offset));
80 |
81 | return Encoding.UTF8.GetString(_data, (int)offset, (int)size);
82 | }
83 |
84 | ///
85 | /// Remove the buffer of the given offset and size
86 | ///
87 | public void Remove(long offset, long size)
88 | {
89 | Debug.Assert(((offset + size) <= Size), "Invalid offset & size!");
90 | if ((offset + size) > Size)
91 | throw new ArgumentException("Invalid offset & size!", nameof(offset));
92 |
93 | Array.Copy(_data, offset + size, _data, offset, _size - size - offset);
94 | _size -= size;
95 | if (_offset >= (offset + size))
96 | _offset -= size;
97 | else if (_offset >= offset)
98 | {
99 | _offset -= _offset - offset;
100 | if (_offset > Size)
101 | _offset = Size;
102 | }
103 | }
104 |
105 | ///
106 | /// Reserve the buffer of the given capacity
107 | ///
108 | public void Reserve(long capacity)
109 | {
110 | Debug.Assert((capacity >= 0), "Invalid reserve capacity!");
111 | if (capacity < 0)
112 | throw new ArgumentException("Invalid reserve capacity!", nameof(capacity));
113 |
114 | if (capacity > Capacity)
115 | {
116 | byte[] data = new byte[Math.Max(capacity, 2 * Capacity)];
117 | Array.Copy(_data, 0, data, 0, _size);
118 | _data = data;
119 | }
120 | }
121 |
122 | // Resize the current buffer
123 | public void Resize(long size)
124 | {
125 | Reserve(size);
126 | _size = size;
127 | if (_offset > _size)
128 | _offset = _size;
129 | }
130 |
131 | // Shift the current buffer offset
132 | public void Shift(long offset) { _offset += offset; }
133 | // Unshift the current buffer offset
134 | public void Unshift(long offset) { _offset -= offset; }
135 |
136 | #endregion
137 |
138 | #region Buffer I/O methods
139 |
140 | ///
141 | /// Append the given buffer
142 | ///
143 | /// Buffer to append
144 | /// Count of append bytes
145 | public long Append(byte[] buffer)
146 | {
147 | Reserve(_size + buffer.Length);
148 | Array.Copy(buffer, 0, _data, _size, buffer.Length);
149 | _size += buffer.Length;
150 | return buffer.Length;
151 | }
152 |
153 | ///
154 | /// Append the given buffer fragment
155 | ///
156 | /// Buffer to append
157 | /// Buffer offset
158 | /// Buffer size
159 | /// Count of append bytes
160 | public long Append(byte[] buffer, long offset, long size)
161 | {
162 | Reserve(_size + size);
163 | Array.Copy(buffer, offset, _data, _size, size);
164 | _size += size;
165 | return size;
166 | }
167 |
168 | ///
169 | /// Append the given text in UTF-8 encoding
170 | ///
171 | /// Text to append
172 | /// Count of append bytes
173 | public long Append(string text)
174 | {
175 | Reserve(_size + Encoding.UTF8.GetMaxByteCount(text.Length));
176 | long result = Encoding.UTF8.GetBytes(text, 0, text.Length, _data, (int)_size);
177 | _size += result;
178 | return result;
179 | }
180 |
181 | #endregion
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/SyslogServer/Common/MessageHandler.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SyslogServer
3 | {
4 |
5 | public enum ServerType
6 | {
7 | UDP,TCP, SSL_TLS
8 | }
9 |
10 | public abstract class MessageHandler
11 | {
12 | public virtual void OnReceived(System.Net.EndPoint endpoint, byte[] buffer, long offset, long size)
13 | {
14 | throw new System.NotImplementedException("OnReceived");
15 | }
16 |
17 |
18 | public virtual void OnError(System.Net.Sockets.SocketError error)
19 | {
20 | System.Console.WriteLine($"server caught an error with code {error}");
21 | }
22 |
23 |
24 | public static MessageHandler CreateInstance(int serverType, int port)
25 | {
26 | return new DefaultMessageHandler();
27 | }
28 |
29 | }
30 |
31 |
32 | public class DefaultMessageHandler
33 | : MessageHandler
34 | {
35 |
36 | public int ServerPort = 0;
37 | public ServerType ServerType = ServerType.TCP;
38 |
39 |
40 | private static char[] trimChars = new char[] { ' ', '\t', '\f', '\v', '\r', '\n' };
41 |
42 |
43 |
44 | private static bool IsNumber(string s)
45 | {
46 | foreach (char c in s)
47 | {
48 | if (!char.IsDigit(c))
49 | return false;
50 | }
51 |
52 | return true;
53 | }
54 |
55 |
56 | public override void OnReceived(System.Net.EndPoint endpoint, byte[] buffer, long offset, long size)
57 | {
58 | bool octetCounting = false;
59 | bool isRfc5424 = false;
60 | bool isRfc3164 = false;
61 | string rawMessage = null;
62 |
63 | try
64 | {
65 | rawMessage = System.Text.Encoding.UTF8.GetString(buffer, (int)offset, (int)size);
66 | System.Console.WriteLine("Incoming: " + rawMessage);
67 |
68 | if (string.IsNullOrWhiteSpace(rawMessage))
69 | return;
70 |
71 | string message = rawMessage.TrimStart();
72 |
73 |
74 | if (IsNumber(message))
75 | return; // Discard - this is just the length of a message
76 |
77 |
78 | // rfc_5424_octet_counting: "218 <134>1 2021-09-16T21:44:22.395060+02:00 DESKTOP-6CN7QMR TestSerilog 31308 - [meta MessageNumber="2" AProperty="0.8263707183424247"] TCP: This is test message 00002
79 | // rfc_5424_nontransparent_framing: "<134>1 2021-09-16T21:44:22.395060+02:00 DESKTOP-6CN7QMR TestSerilog 31308 - [meta MessageNumber="2" AProperty="0.8263707183424247"] TCP: This is test message 00002
80 |
81 | // rfc_3164_octet_counting: "218 <30>Oct
82 | // rfc_3164_nontransparent_framing: "<30>Oct
83 |
84 | // p = ((int)facility * 8) + (int)severity;
85 | // ==> severity = p % 8
86 | // ==> faciliy = p \ 8
87 |
88 | // Probe octet-framing and message-type
89 | // Let's do this WITHOUT regex - for speed !
90 | int ind = message.IndexOf('<');
91 | if (ind != 0)
92 | {
93 | if (ind != -1)
94 | {
95 | octetCounting = true;
96 | string octet = message.Substring(0, ind - 1);
97 | octet = octet.TrimEnd(trimChars);
98 | if (!IsNumber(octet))
99 | {
100 | throw new System.IO.InvalidDataException("Invalid octet framing ! \r\nMessage: " + rawMessage);
101 | }
102 |
103 | message = message.Substring(ind);
104 | }
105 | else
106 | throw new System.IO.InvalidDataException(rawMessage);
107 |
108 | }
109 |
110 | int closeAngleBracketIndex = message.IndexOf('>');
111 | if (closeAngleBracketIndex != -1)
112 | {
113 | closeAngleBracketIndex++;
114 | string messageContent = message.Substring(closeAngleBracketIndex);
115 | messageContent = messageContent.TrimStart(trimChars);
116 | System.Console.WriteLine(messageContent);
117 |
118 | if (messageContent.Length > 0)
119 | {
120 | if (char.IsDigit(messageContent[0]))
121 | {
122 | isRfc5424 = true;
123 | }
124 | else
125 | {
126 | isRfc3164 = true;
127 | }
128 | }
129 | else
130 | throw new System.IO.InvalidDataException(rawMessage);
131 | }
132 | else
133 | throw new System.IO.InvalidDataException(rawMessage);
134 |
135 |
136 | System.Console.WriteLine("Octet counting: {0}", octetCounting);
137 |
138 | if (isRfc5424)
139 | {
140 | System.Console.WriteLine("rfc_5424");
141 | Rfc5424SyslogMessage msg5424 = Rfc5424SyslogMessage.Parse(message);
142 | msg5424.SetSourceEndpoint(endpoint);
143 | System.Console.WriteLine(msg5424);
144 | }
145 | else if (isRfc3164)
146 | {
147 | System.Console.WriteLine("rfc_3164");
148 | Rfc3164SyslogMessage msg3164 = Rfc3164SyslogMessage.Parse(message);
149 | msg3164.RemoteIP = endpoint.ToString();
150 | System.Console.WriteLine(msg3164);
151 | }
152 |
153 | }
154 | catch (System.Exception ex)
155 | {
156 | System.Console.WriteLine(ex.Message);
157 | System.Console.WriteLine(ex.StackTrace);
158 |
159 | // bool octetCounting = false;
160 |
161 | if (isRfc5424)
162 | {
163 | Rfc5424SyslogMessage msg5424 = Rfc5424SyslogMessage.Invalid(rawMessage, ex);
164 | }
165 | else if (isRfc3164)
166 | {
167 | Rfc3164SyslogMessage msg3164 = Rfc3164SyslogMessage.Invalid(rawMessage, ex);
168 | }
169 | else
170 | {
171 |
172 | }
173 | }
174 |
175 | }
176 |
177 |
178 | }
179 | }
180 |
181 |
--------------------------------------------------------------------------------
/SyslogServer/TlsSyslogServer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SyslogServer
3 | {
4 |
5 | public class SyslogTlsSession
6 | : NetCoreServer.SslSession
7 | {
8 | protected MessageHandler m_messageHandler;
9 |
10 | public SyslogTlsSession(NetCoreServer.SslServer server, MessageHandler handler)
11 | : base(server)
12 | { }
13 |
14 | protected override void OnConnected()
15 | {
16 | System.Console.WriteLine($"Syslog SSL session with Id {Id} connected!");
17 | } // End Sub OnConnected
18 |
19 |
20 | protected override void OnHandshaked()
21 | {
22 | System.Console.WriteLine($"Syslog SSL session with Id {Id} handshaked!");
23 |
24 | // Send invite message
25 | // string message = "Hello from SSL Syslog! Please send a message or '!' to disconnect the client!";
26 | // Send(message);
27 | } // End Sub OnHandshaked
28 |
29 |
30 | protected override void OnDisconnected()
31 | {
32 | System.Console.WriteLine($"Syslog SSL session with Id {Id} disconnected!");
33 | } // End Sub OnDisconnected
34 |
35 |
36 | protected override void OnReceived(byte[] buffer, long offset, long size)
37 | {
38 | // string message = System.Text.Encoding.UTF8.GetString(buffer, (int)offset, (int)size);
39 | // System.Console.WriteLine("Incoming: " + message);
40 | this.m_messageHandler.OnReceived(this.Socket.RemoteEndPoint, buffer, offset, size);
41 |
42 | // Multicast message to all connected sessions
43 | // Server.Multicast(message);
44 |
45 | // If the buffer starts with '!' the disconnect the current session
46 | // if (message == "!") Disconnect();
47 |
48 | } // End Sub OnReceived
49 |
50 |
51 | protected override void OnError(System.Net.Sockets.SocketError error)
52 | {
53 | // System.Console.WriteLine($"Syslog SSL session caught an error with code {error}");
54 | this.m_messageHandler.OnError(error);
55 | } // End Sub OnError
56 |
57 |
58 | } // End Class SyslogTlsSession
59 |
60 |
61 | public class TlsSyslogServer
62 | : NetCoreServer.SslServer
63 | {
64 |
65 | protected MessageHandler m_messageHandler;
66 |
67 |
68 | public TlsSyslogServer(
69 | NetCoreServer.SslContext context
70 | , System.Net.IPAddress address
71 | , int port
72 | , MessageHandler handler
73 | )
74 | : base(context, address, port)
75 | {
76 | this.m_messageHandler = handler;
77 | }
78 |
79 | protected override NetCoreServer.SslSession CreateSession()
80 | {
81 | return new SyslogTlsSession(this, this.m_messageHandler);
82 | } // End Function CreateSession
83 |
84 |
85 | protected override void OnError(System.Net.Sockets.SocketError error)
86 | {
87 | System.Console.WriteLine($"Syslog SSL server caught an error with code {error}");
88 | }
89 |
90 | public static bool AllowAnything(
91 | object sender
92 | , System.Security.Cryptography.X509Certificates.X509Certificate certificate
93 | , System.Security.Cryptography.X509Certificates.X509Chain chain
94 | , System.Net.Security.SslPolicyErrors sslPolicyErrors)
95 | {
96 | return true;
97 | } // End Function AllowAnything
98 |
99 |
100 | public static void Test()
101 | {
102 | System.Net.ServicePointManager.ServerCertificateValidationCallback =
103 | new System.Net.Security.RemoteCertificateValidationCallback(AllowAnything);
104 |
105 | // SSL server port
106 | int port = 6514;
107 |
108 | System.Console.WriteLine($"SSL server port: {port}");
109 |
110 | System.Console.WriteLine();
111 |
112 |
113 | string[] altNames = SelfSignedCertificate.SelfSigned.GetAlternativeNames(new string[0]);
114 | byte[] pfx = SelfSignedCertificate.SelfSigned.CreateSelfSignedCertificate(altNames, "");
115 |
116 | System.Security.Cryptography.X509Certificates.X509Certificate2 cert =
117 | new System.Security.Cryptography.X509Certificates.X509Certificate2(pfx,"",
118 | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable
119 | // https://github.com/dotnet/runtime/issues/23749
120 | // | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.EphemeralKeySet // Error !
121 | );
122 |
123 | // Create and prepare a new SSL server context
124 | NetCoreServer.SslContext context = new NetCoreServer.SslContext(
125 | // System.Security.Authentication.SslProtocols.Tls
126 | // System.Security.Authentication.SslProtocols.Tls13
127 | System.Security.Authentication.SslProtocols.Tls12
128 | , cert
129 | );
130 |
131 | // Create a new SSL Syslog server
132 | TlsSyslogServer server =
133 | new TlsSyslogServer(context, System.Net.IPAddress.Any, port, MessageHandler.CreateInstance(123, port));
134 |
135 | // Start the server
136 | System.Console.Write("Server starting...");
137 | server.Start();
138 | System.Console.WriteLine("Done!");
139 |
140 | System.Console.WriteLine("Press Enter to stop the server or '!' to restart the server...");
141 |
142 | // Perform text input
143 | for (; ; )
144 | {
145 | string line = System.Console.ReadLine();
146 | if (string.IsNullOrEmpty(line))
147 | break;
148 |
149 | // Restart the server
150 | if (line == "!")
151 | {
152 | System.Console.Write("Server restarting...");
153 | server.Restart();
154 | System.Console.WriteLine("Done!");
155 | continue;
156 | } // End if (line == "!")
157 |
158 | // Multicast admin message to all sessions
159 | line = "(admin) " + line;
160 | server.Multicast(line);
161 | } // Next
162 |
163 | // Stop the server
164 | System.Console.Write("Server stopping...");
165 | server.Stop();
166 | System.Console.WriteLine("Done!");
167 | } // End Sub Test
168 |
169 |
170 | } // End Class TlsSyslogServer
171 |
172 |
173 | } // End Namespace SyslogServer
174 |
--------------------------------------------------------------------------------
/NetCoreServer/Utilities.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace NetCoreServer
5 | {
6 | ///
7 | /// Conversion metrics utilities
8 | ///
9 | public class Utilities
10 | {
11 | ///
12 | /// Generate data size string. Will return a pretty string of bytes, KiB, MiB, GiB, TiB based on the given bytes.
13 | ///
14 | /// Data size in bytes
15 | /// String with data size representation
16 | public static string GenerateDataSize(double b)
17 | {
18 | var sb = new StringBuilder();
19 |
20 | long bytes = (long)b;
21 | long absBytes = Math.Abs(bytes);
22 |
23 | if (absBytes >= (1024L * 1024L * 1024L * 1024L))
24 | {
25 | long tb = bytes / (1024L * 1024L * 1024L * 1024L);
26 | long gb = (bytes % (1024L * 1024L * 1024L * 1024L)) / (1024 * 1024 * 1024);
27 | sb.Append(tb);
28 | sb.Append('.');
29 | sb.Append((gb < 100) ? "0" : "");
30 | sb.Append((gb < 10) ? "0" : "");
31 | sb.Append(gb);
32 | sb.Append(" TiB");
33 | }
34 | else if (absBytes >= (1024 * 1024 * 1024))
35 | {
36 | long gb = bytes / (1024 * 1024 * 1024);
37 | long mb = (bytes % (1024 * 1024 * 1024)) / (1024 * 1024);
38 | sb.Append(gb);
39 | sb.Append('.');
40 | sb.Append((mb < 100) ? "0" : "");
41 | sb.Append((mb < 10) ? "0" : "");
42 | sb.Append(mb);
43 | sb.Append(" GiB");
44 | }
45 | else if (absBytes >= (1024 * 1024))
46 | {
47 | long mb = bytes / (1024 * 1024);
48 | long kb = (bytes % (1024 * 1024)) / 1024;
49 | sb.Append(mb);
50 | sb.Append('.');
51 | sb.Append((kb < 100) ? "0" : "");
52 | sb.Append((kb < 10) ? "0" : "");
53 | sb.Append(kb);
54 | sb.Append(" MiB");
55 | }
56 | else if (absBytes >= 1024)
57 | {
58 | long kb = bytes / 1024;
59 | bytes = bytes % 1024;
60 | sb.Append(kb);
61 | sb.Append('.');
62 | sb.Append((bytes < 100) ? "0" : "");
63 | sb.Append((bytes < 10) ? "0" : "");
64 | sb.Append(bytes);
65 | sb.Append(" KiB");
66 | }
67 | else
68 | {
69 | sb.Append(bytes);
70 | sb.Append(" bytes");
71 | }
72 |
73 | return sb.ToString();
74 | }
75 |
76 | ///
77 | /// Generate time period string. Will return a pretty string of ns, mcs, ms, s, m, h based on the given nanoseconds.
78 | ///
79 | /// Milliseconds
80 | /// String with time period representation
81 | public static string GenerateTimePeriod(double ms)
82 | {
83 | var sb = new StringBuilder();
84 |
85 | long nanoseconds = (long) (ms * 1000.0 * 1000.0);
86 | long absNanoseconds = Math.Abs(nanoseconds);
87 |
88 | if (absNanoseconds >= (60 * 60 * 1000000000L))
89 | {
90 | long hours = nanoseconds / (60 * 60 * 1000000000L);
91 | long minutes = ((nanoseconds % (60 * 60 * 1000000000L)) / 1000000000) / 60;
92 | long seconds = ((nanoseconds % (60 * 60 * 1000000000L)) / 1000000000) % 60;
93 | long milliseconds = ((nanoseconds % (60 * 60 * 1000000000L)) % 1000000000) / 1000000;
94 | sb.Append(hours);
95 | sb.Append(':');
96 | sb.Append((minutes < 10) ? "0" : "");
97 | sb.Append(minutes);
98 | sb.Append(':');
99 | sb.Append((seconds < 10) ? "0" : "");
100 | sb.Append(seconds);
101 | sb.Append('.');
102 | sb.Append((milliseconds < 100) ? "0" : "");
103 | sb.Append((milliseconds < 10) ? "0" : "");
104 | sb.Append(milliseconds);
105 | sb.Append(" h");
106 | }
107 | else if (absNanoseconds >= (60 * 1000000000L))
108 | {
109 | long minutes = nanoseconds / (60 * 1000000000L);
110 | long seconds = (nanoseconds % (60 * 1000000000L)) / 1000000000;
111 | long milliseconds = ((nanoseconds % (60 * 1000000000L)) % 1000000000) / 1000000;
112 | sb.Append(minutes);
113 | sb.Append(':');
114 | sb.Append((seconds < 10) ? "0" : "");
115 | sb.Append(seconds);
116 | sb.Append('.');
117 | sb.Append((milliseconds < 100) ? "0" : "");
118 | sb.Append((milliseconds < 10) ? "0" : "");
119 | sb.Append(milliseconds);
120 | sb.Append(" m");
121 | }
122 | else if (absNanoseconds >= 1000000000)
123 | {
124 | long seconds = nanoseconds / 1000000000;
125 | long milliseconds = (nanoseconds % 1000000000) / 1000000;
126 | sb.Append(seconds);
127 | sb.Append('.');
128 | sb.Append((milliseconds < 100) ? "0" : "");
129 | sb.Append((milliseconds < 10) ? "0" : "");
130 | sb.Append(milliseconds);
131 | sb.Append(" s");
132 | }
133 | else if (absNanoseconds >= 1000000)
134 | {
135 | long milliseconds = nanoseconds / 1000000;
136 | long microseconds = (nanoseconds % 1000000) / 1000;
137 | sb.Append(milliseconds);
138 | sb.Append('.');
139 | sb.Append((microseconds < 100) ? "0" : "");
140 | sb.Append((microseconds < 10) ? "0" : "");
141 | sb.Append(microseconds);
142 | sb.Append(" ms");
143 | }
144 | else if (absNanoseconds >= 1000)
145 | {
146 | long microseconds = nanoseconds / 1000;
147 | nanoseconds = nanoseconds % 1000;
148 | sb.Append(microseconds);
149 | sb.Append('.');
150 | sb.Append((nanoseconds < 100) ? "0" : "");
151 | sb.Append((nanoseconds < 10) ? "0" : "");
152 | sb.Append(nanoseconds);
153 | sb.Append(" mcs");
154 | }
155 | else
156 | {
157 | sb.Append(nanoseconds);
158 | sb.Append(" ns");
159 | }
160 |
161 | return sb.ToString();
162 | }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/SyslogServer/Program.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SyslogServer
3 | {
4 |
5 | public class GeneralSyslogServer
6 | {
7 |
8 | protected UpdSyslogServer m_udpServer;
9 | protected TcpSyslogServer m_tcpServer;
10 | protected TlsSyslogServer m_tlsServer;
11 |
12 |
13 |
14 | public ServerType ServerType;
15 | public int Port;
16 | public System.Net.IPAddress ListenAddress;
17 | public System.Security.Authentication.SslProtocols Protocol;
18 | public System.Security.Cryptography.X509Certificates.X509Certificate2 Certificate;
19 |
20 |
21 | private static int GetDefaultPort(ServerType serverType)
22 | {
23 | if (serverType == ServerType.UDP)
24 | return 514;
25 |
26 | if (serverType == ServerType.TCP)
27 | return 1468;
28 |
29 | if (serverType == ServerType.SSL_TLS)
30 | return 6514;
31 |
32 | return -1;
33 | }
34 |
35 |
36 | public GeneralSyslogServer(
37 | ServerType serverType,
38 | int port,
39 | System.Net.IPAddress listenIP,
40 | System.Security.Authentication.SslProtocols protocol,
41 | System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
42 | {
43 | this.ServerType = serverType;
44 | this.Port = port;
45 | this.ListenAddress = listenIP;
46 | this.Protocol = protocol;
47 | this.Certificate = certificate;
48 | }
49 |
50 |
51 | public GeneralSyslogServer(
52 | ServerType serverType,
53 | int port,
54 | System.Net.IPAddress listenIP
55 | )
56 | : this(serverType, port, listenIP, System.Security.Authentication.SslProtocols.None, null)
57 | {
58 | }
59 |
60 |
61 | public GeneralSyslogServer(
62 | ServerType serverType,
63 | System.Net.IPAddress listenIP
64 | )
65 | : this(serverType, GetDefaultPort(serverType), listenIP, System.Security.Authentication.SslProtocols.None, null)
66 | {
67 | }
68 |
69 |
70 |
71 | public GeneralSyslogServer(
72 | ServerType serverType,
73 | System.Net.IPAddress listenIP,
74 | System.Security.Authentication.SslProtocols protocol,
75 | System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
76 | : this(serverType, GetDefaultPort(serverType), listenIP, protocol, certificate)
77 | {
78 | }
79 |
80 |
81 |
82 |
83 | public bool Start()
84 | {
85 | // Create a new UDP echo server
86 | if (this.ServerType == ServerType.UDP)
87 | this.m_udpServer = new UpdSyslogServer(this.ListenAddress, this.Port, MessageHandler.CreateInstance(123, this.Port));
88 |
89 | // Create a new TCP Syslog server
90 | if (this.ServerType == ServerType.TCP)
91 | this.m_tcpServer = new TcpSyslogServer(this.ListenAddress, this.Port, MessageHandler.CreateInstance(123, this.Port));
92 |
93 | if (this.ServerType == ServerType.SSL_TLS)
94 | {
95 |
96 | if (this.Certificate != null && this.Protocol != System.Security.Authentication.SslProtocols.None)
97 | {
98 | // Create and prepare a new SSL server context
99 | NetCoreServer.SslContext context = new NetCoreServer.SslContext(this.Protocol, this.Certificate);
100 | // Create a new SSL Syslog server
101 | this.m_tlsServer = new TlsSyslogServer(context, this.ListenAddress, this.Port, MessageHandler.CreateInstance(123, this.Port));
102 | }
103 | }
104 |
105 |
106 |
107 | if (this.m_udpServer == null && this.m_tcpServer == null && this.m_tlsServer == null)
108 | {
109 | // Can't start the server
110 | System.Console.Write("Server NOT starting...");
111 | return false;
112 | }
113 |
114 | // Start the server
115 | System.Console.Write("Server starting...");
116 |
117 | if (this.m_udpServer != null)
118 | this.m_udpServer.Start();
119 |
120 | if (this.m_tcpServer != null)
121 | this.m_tcpServer.Start();
122 |
123 | if (this.m_tlsServer != null)
124 | this.m_tlsServer.Start();
125 |
126 | System.Console.WriteLine("Done!");
127 | return true;
128 | }
129 |
130 | public void Run()
131 | {
132 | if (!this.Start())
133 | return;
134 |
135 | System.Console.WriteLine("Press Enter to stop the server or '!' to restart the server...");
136 |
137 | // Perform text input
138 | for (; ; )
139 | {
140 | string line = System.Console.ReadLine();
141 | if (string.IsNullOrEmpty(line))
142 | break;
143 |
144 | // Restart the server
145 | if (line == "!")
146 | {
147 | System.Console.Write("Server restarting...");
148 |
149 | if (this.m_udpServer != null)
150 | this.m_udpServer.Restart();
151 |
152 | if (this.m_tcpServer != null)
153 | this.m_tcpServer.Restart();
154 |
155 | if (this.m_tlsServer != null)
156 | this.m_tlsServer.Restart();
157 |
158 | System.Console.WriteLine("Done!");
159 | continue;
160 | } // End if (line == "!")
161 |
162 | } // Next
163 |
164 | // Stop the server
165 | System.Console.Write("Server stopping...");
166 |
167 | if (this.m_udpServer != null)
168 | this.m_udpServer.Stop();
169 |
170 | if (this.m_tcpServer != null)
171 | this.m_tcpServer.Stop();
172 |
173 | if (this.m_tlsServer != null)
174 | this.m_tlsServer.Stop();
175 |
176 | System.Console.WriteLine("Done!");
177 | }
178 |
179 | }
180 |
181 |
182 |
183 | public class Program
184 | {
185 |
186 |
187 | public static void Main(string[] args)
188 | {
189 | // TODO: Use a performant TCP/UPD/TLS libary
190 | // https://github.com/chronoxor/NetCoreServer
191 | // https://chronoxor.github.io/NetCoreServer/
192 |
193 |
194 | // var gsl = new GeneralSyslogServer(ServerType.SSL_TLS, System.Net.IPAddress.Any, System.Security.Authentication.SslProtocols.None, null);
195 | // var gsl = new GeneralSyslogServer(ServerType.UDP, System.Net.IPAddress.Any);
196 | var gsl = new GeneralSyslogServer(ServerType.TCP, System.Net.IPAddress.Any);
197 |
198 | gsl.Run();
199 |
200 | // UpdSyslogServer.Test();
201 | // TlsSyslogServer.Test();
202 | // TcpSyslogServer.Test();
203 |
204 | // libSyslogServer.SyslogServer.StartServer();
205 | } // End Sub Main
206 |
207 |
208 | } // End Class Program
209 |
210 |
211 | } // End Namespace SyslogServer
212 |
--------------------------------------------------------------------------------
/NetCoreServer/HttpSession.cs:
--------------------------------------------------------------------------------
1 | namespace NetCoreServer
2 | {
3 | ///
4 | /// HTTP session is used to receive/send HTTP requests/responses from the connected HTTP client.
5 | ///
6 | /// Thread-safe.
7 | public class HttpSession : TcpSession
8 | {
9 | public HttpSession(HttpServer server) : base(server)
10 | {
11 | Cache = server.Cache;
12 | Request = new HttpRequest();
13 | Response = new HttpResponse();
14 | }
15 |
16 | ///
17 | /// Get the static content cache
18 | ///
19 | public FileCache Cache { get; }
20 |
21 | ///
22 | /// Get the HTTP request
23 | ///
24 | protected HttpRequest Request { get; }
25 |
26 | ///
27 | /// Get the HTTP response
28 | ///
29 | public HttpResponse Response { get; }
30 |
31 | #region Send response / Send response body
32 |
33 | ///
34 | /// Send the current HTTP response (synchronous)
35 | ///
36 | /// Size of sent data
37 | public long SendResponse() { return SendResponse(Response); }
38 | ///
39 | /// Send the HTTP response (synchronous)
40 | ///
41 | /// HTTP response
42 | /// Size of sent data
43 | public long SendResponse(HttpResponse response) { return Send(response.Cache.Data, response.Cache.Offset, response.Cache.Size); }
44 |
45 | ///
46 | /// Send the HTTP response body (synchronous)
47 | ///
48 | /// HTTP response body
49 | /// Size of sent data
50 | public long SendResponseBody(string body) { return Send(body); }
51 | ///
52 | /// Send the HTTP response body (synchronous)
53 | ///
54 | /// HTTP response body buffer
55 | /// Size of sent data
56 | public long SendResponseBody(byte[] buffer) { return Send(buffer); }
57 | ///
58 | /// Send the HTTP response body (synchronous)
59 | ///
60 | /// HTTP response body buffer
61 | /// HTTP response body buffer offset
62 | /// HTTP response body size
63 | /// Size of sent data
64 | public long SendResponseBody(byte[] buffer, long offset, long size) { return Send(buffer, offset, size); }
65 |
66 | ///
67 | /// Send the current HTTP response (asynchronous)
68 | ///
69 | /// 'true' if the current HTTP response was successfully sent, 'false' if the session is not connected
70 | public bool SendResponseAsync() { return SendResponseAsync(Response); }
71 | ///
72 | /// Send the HTTP response (asynchronous)
73 | ///
74 | /// HTTP response
75 | /// 'true' if the current HTTP response was successfully sent, 'false' if the session is not connected
76 | public bool SendResponseAsync(HttpResponse response) { return SendAsync(response.Cache.Data, response.Cache.Offset, response.Cache.Size); }
77 |
78 | ///
79 | /// Send the HTTP response body (asynchronous)
80 | ///
81 | /// HTTP response body
82 | /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected
83 | public bool SendResponseBodyAsync(string body) { return SendAsync(body); }
84 | ///
85 | /// Send the HTTP response body (asynchronous)
86 | ///
87 | /// HTTP response body buffer
88 | /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected
89 | public bool SendResponseBodyAsync(byte[] buffer) { return SendAsync(buffer); }
90 | ///
91 | /// Send the HTTP response body (asynchronous)
92 | ///
93 | /// HTTP response body buffer
94 | /// HTTP response body buffer offset
95 | /// HTTP response body size
96 | /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected
97 | public bool SendResponseBodyAsync(byte[] buffer, long offset, long size) { return SendAsync(buffer, offset, size); }
98 |
99 | #endregion
100 |
101 | #region Session handlers
102 |
103 | protected override void OnReceived(byte[] buffer, long offset, long size)
104 | {
105 | // Receive HTTP request header
106 | if (Request.IsPendingHeader())
107 | {
108 | if (Request.ReceiveHeader(buffer, (int)offset, (int)size))
109 | OnReceivedRequestHeader(Request);
110 |
111 | size = 0;
112 | }
113 |
114 | // Check for HTTP request error
115 | if (Request.IsErrorSet)
116 | {
117 | OnReceivedRequestError(Request, "Invalid HTTP request!");
118 | Request.Clear();
119 | Disconnect();
120 | return;
121 | }
122 |
123 | // Receive HTTP request body
124 | if (Request.ReceiveBody(buffer, (int)offset, (int)size))
125 | {
126 | OnReceivedRequestInternal(Request);
127 | Request.Clear();
128 | return;
129 | }
130 |
131 | // Check for HTTP request error
132 | if (Request.IsErrorSet)
133 | {
134 | OnReceivedRequestError(Request, "Invalid HTTP request!");
135 | Request.Clear();
136 | Disconnect();
137 | return;
138 | }
139 | }
140 |
141 | protected override void OnDisconnected()
142 | {
143 | // Receive HTTP request body
144 | if (Request.IsPendingBody())
145 | {
146 | OnReceivedRequestInternal(Request);
147 | Request.Clear();
148 | return;
149 | }
150 | }
151 |
152 | ///
153 | /// Handle HTTP request header received notification
154 | ///
155 | /// Notification is called when HTTP request header was received from the client.
156 | /// HTTP request
157 | protected virtual void OnReceivedRequestHeader(HttpRequest request) {}
158 |
159 | ///
160 | /// Handle HTTP request received notification
161 | ///
162 | /// Notification is called when HTTP request was received from the client.
163 | /// HTTP request
164 | protected virtual void OnReceivedRequest(HttpRequest request) {}
165 |
166 | ///
167 | /// Handle HTTP request error notification
168 | ///
169 | /// Notification is called when HTTP request error was received from the client.
170 | /// HTTP request
171 | /// HTTP request error
172 | protected virtual void OnReceivedRequestError(HttpRequest request, string error) {}
173 |
174 | #endregion
175 |
176 | private void OnReceivedRequestInternal(HttpRequest request)
177 | {
178 | // Try to get the cached response
179 | if (request.Method == "GET")
180 | {
181 | var response = Cache.Find(request.Url);
182 | if (response.Item1)
183 | {
184 | SendAsync(response.Item2);
185 | return;
186 | }
187 | }
188 |
189 | // Process the request
190 | OnReceivedRequest(request);
191 | }
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/NetCoreServer/HttpsSession.cs:
--------------------------------------------------------------------------------
1 | namespace NetCoreServer
2 | {
3 | ///
4 | /// HTTPS session is used to receive/send HTTP requests/responses from the connected HTTPS client.
5 | ///
6 | /// Thread-safe.
7 | public class HttpsSession : SslSession
8 | {
9 | public HttpsSession(HttpsServer server) : base(server)
10 | {
11 | Cache = server.Cache;
12 | Request = new HttpRequest();
13 | Response = new HttpResponse();
14 | }
15 |
16 | ///
17 | /// Get the static content cache
18 | ///
19 | public FileCache Cache { get; }
20 |
21 | ///
22 | /// Get the HTTP request
23 | ///
24 | protected HttpRequest Request { get; }
25 |
26 | ///
27 | /// Get the HTTP response
28 | ///
29 | public HttpResponse Response { get; }
30 |
31 | #region Send response / Send response body
32 |
33 | ///
34 | /// Send the current HTTP response (synchronous)
35 | ///
36 | /// Size of sent data
37 | public long SendResponse() { return SendResponse(Response); }
38 | ///
39 | /// Send the HTTP response (synchronous)
40 | ///
41 | /// HTTP response
42 | /// Size of sent data
43 | public long SendResponse(HttpResponse response) { return Send(response.Cache.Data, response.Cache.Offset, response.Cache.Size); }
44 |
45 | ///
46 | /// Send the HTTP response body (synchronous)
47 | ///
48 | /// HTTP response body
49 | /// Size of sent data
50 | public long SendResponseBody(string body) { return Send(body); }
51 | ///
52 | /// Send the HTTP response body (synchronous)
53 | ///
54 | /// HTTP response body buffer
55 | /// Size of sent data
56 | public long SendResponseBody(byte[] buffer) { return Send(buffer); }
57 | ///
58 | /// Send the HTTP response body (synchronous)
59 | ///
60 | /// HTTP response body buffer
61 | /// HTTP response body buffer offset
62 | /// HTTP response body size
63 | /// Size of sent data
64 | public long SendResponseBody(byte[] buffer, long offset, long size) { return Send(buffer, offset, size); }
65 |
66 | ///
67 | /// Send the current HTTP response (asynchronous)
68 | ///
69 | /// 'true' if the current HTTP response was successfully sent, 'false' if the session is not connected
70 | public bool SendResponseAsync() { return SendResponseAsync(Response); }
71 | ///
72 | /// Send the HTTP response (asynchronous)
73 | ///
74 | /// HTTP response
75 | /// 'true' if the current HTTP response was successfully sent, 'false' if the session is not connected
76 | public bool SendResponseAsync(HttpResponse response) { return SendAsync(response.Cache.Data, response.Cache.Offset, response.Cache.Size); }
77 |
78 | ///
79 | /// Send the HTTP response body (asynchronous)
80 | ///
81 | /// HTTP response body
82 | /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected
83 | public bool SendResponseBodyAsync(string body) { return SendAsync(body); }
84 | ///
85 | /// Send the HTTP response body (asynchronous)
86 | ///
87 | /// HTTP response body buffer
88 | /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected
89 | public bool SendResponseBodyAsync(byte[] buffer) { return SendAsync(buffer); }
90 | ///
91 | /// Send the HTTP response body (asynchronous)
92 | ///
93 | /// HTTP response body buffer
94 | /// HTTP response body buffer offset
95 | /// HTTP response body size
96 | /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected
97 | public bool SendResponseBodyAsync(byte[] buffer, long offset, long size) { return SendAsync(buffer, offset, size); }
98 |
99 | #endregion
100 |
101 | #region Session handlers
102 |
103 | protected override void OnReceived(byte[] buffer, long offset, long size)
104 | {
105 | // Receive HTTP request header
106 | if (Request.IsPendingHeader())
107 | {
108 | if (Request.ReceiveHeader(buffer, (int)offset, (int)size))
109 | OnReceivedRequestHeader(Request);
110 |
111 | size = 0;
112 | }
113 |
114 | // Check for HTTP request error
115 | if (Request.IsErrorSet)
116 | {
117 | OnReceivedRequestError(Request, "Invalid HTTP request!");
118 | Request.Clear();
119 | Disconnect();
120 | return;
121 | }
122 |
123 | // Receive HTTP request body
124 | if (Request.ReceiveBody(buffer, (int)offset, (int)size))
125 | {
126 | OnReceivedRequestInternal(Request);
127 | Request.Clear();
128 | return;
129 | }
130 |
131 | // Check for HTTP request error
132 | if (Request.IsErrorSet)
133 | {
134 | OnReceivedRequestError(Request, "Invalid HTTP request!");
135 | Request.Clear();
136 | Disconnect();
137 | return;
138 | }
139 | }
140 |
141 | protected override void OnDisconnected()
142 | {
143 | // Receive HTTP request body
144 | if (Request.IsPendingBody())
145 | {
146 | OnReceivedRequestInternal(Request);
147 | Request.Clear();
148 | return;
149 | }
150 | }
151 |
152 | ///
153 | /// Handle HTTP request header received notification
154 | ///
155 | /// Notification is called when HTTP request header was received from the client.
156 | /// HTTP request
157 | protected virtual void OnReceivedRequestHeader(HttpRequest request) { }
158 |
159 | ///
160 | /// Handle HTTP request received notification
161 | ///
162 | /// Notification is called when HTTP request was received from the client.
163 | /// HTTP request
164 | protected virtual void OnReceivedRequest(HttpRequest request) { }
165 |
166 | ///
167 | /// Handle HTTP request error notification
168 | ///
169 | /// Notification is called when HTTP request error was received from the client.
170 | /// HTTP request
171 | /// HTTP request error
172 | protected virtual void OnReceivedRequestError(HttpRequest request, string error) { }
173 |
174 | #endregion
175 |
176 | private void OnReceivedRequestInternal(HttpRequest request)
177 | {
178 | // Try to get the cached response
179 | if (request.Method == "GET")
180 | {
181 | var response = Cache.Find(request.Url);
182 | if (response.Item1)
183 | {
184 | SendAsync(response.Item2);
185 | return;
186 | }
187 | }
188 |
189 | // Process the request
190 | OnReceivedRequest(request);
191 | }
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/SelfSignedCertificate/Helpers/CertificateInfo.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SelfSignedCertificate
3 | {
4 |
5 |
6 | public class CertificateInfo
7 | {
8 |
9 | public string CountryIso2Characters;
10 | public string StateOrProvince;
11 | public string LocalityOrCity;
12 | public string CompanyName;
13 | public string Division;
14 | public string DomainName;
15 | public string EMail;
16 |
17 | public System.DateTime ValidFrom;
18 | public System.DateTime ValidTo;
19 |
20 | // public PrivatePublicPemKeyPair SubjectKeyPair;
21 | // public PrivatePublicPemKeyPair IssuerKeyPair;
22 |
23 | public string[] AlternativeNames;
24 |
25 |
26 | public System.Collections.Generic.Dictionary NonCriticalExtensions;
27 | public System.Collections.Generic.Dictionary CriticalExtensions;
28 |
29 |
30 |
31 | public Org.BouncyCastle.Asn1.X509.X509Name Subject
32 | {
33 | get
34 | {
35 | return CreateSubject(
36 | this.CountryIso2Characters
37 | , this.StateOrProvince
38 | , this.LocalityOrCity
39 | , this.CompanyName
40 | , this.Division
41 | , this.DomainName
42 | , this.EMail
43 | );
44 | }
45 | } // End Property Subject
46 |
47 |
48 | public Org.BouncyCastle.Asn1.DerSequence SubjectAlternativeNames
49 | {
50 | get
51 | {
52 | return CreateSubjectAlternativeNames(this.AlternativeNames);
53 | }
54 | } // End Property SubjectAlternativeNames
55 |
56 |
57 | public static Org.BouncyCastle.Asn1.DerSequence CreateSubjectAlternativeNames(string[] names)
58 | {
59 | Org.BouncyCastle.Asn1.Asn1Encodable[] alternativeNames = new Org.BouncyCastle.Asn1.Asn1Encodable[names.Length];
60 |
61 | for (int i = 0; i < names.Length; ++i)
62 | {
63 | System.Net.IPAddress ipa;
64 | if (System.Net.IPAddress.TryParse(names[i], out ipa))
65 | alternativeNames[i] = new Org.BouncyCastle.Asn1.X509.GeneralName(Org.BouncyCastle.Asn1.X509.GeneralName.IPAddress, names[i]);
66 | else
67 | alternativeNames[i] = new Org.BouncyCastle.Asn1.X509.GeneralName(Org.BouncyCastle.Asn1.X509.GeneralName.DnsName, names[i]);
68 | } // Next i
69 |
70 | Org.BouncyCastle.Asn1.DerSequence subjectAlternativeNames = new Org.BouncyCastle.Asn1.DerSequence(alternativeNames);
71 | return subjectAlternativeNames;
72 | } // End Function CreateSubjectAlternativeNames
73 |
74 | #if false
75 | private static void BuildAlternativeNameNetCoreVariant(System.Security.Cryptography.X509Certificates.X509Certificate2 cert)
76 | {
77 | // Certificate Policies
78 | // https://stackoverflow.com/questions/12147986/how-to-extract-the-authoritykeyidentifier-from-a-x509certificate2-in-net/12148637
79 | System.Security.Cryptography.X509Certificates.SubjectAlternativeNameBuilder sb =
80 | new System.Security.Cryptography.X509Certificates.SubjectAlternativeNameBuilder();
81 | sb.AddDnsName("example.com");
82 | sb.AddEmailAddress("webmaster@example.com");
83 | sb.AddIpAddress(System.Net.IPAddress.Parse("127.0.0.1"));
84 | sb.AddUri(new System.Uri("https://www.google.com/bot.html"));
85 | sb.AddUserPrincipalName("domain\\username");
86 | sb.Build();
87 | System.Security.Cryptography.X509Certificates.X509Extension san = sb.Build();
88 | cert.Extensions.Add(san);
89 | } // End Sub BuildAlternativeNameNetCoreVariant
90 | #endif
91 |
92 | // https://codereview.stackexchange.com/questions/84752/net-bouncycastle-csr-and-private-key-generation
93 | public static Org.BouncyCastle.Asn1.X509.X509Name CreateSubject(
94 | string countryIso2Characters
95 | , string stateOrProvince
96 | , string localityOrCity
97 | , string companyName
98 | , string division
99 | , string domainName
100 | , string email)
101 | {
102 | // https://people.eecs.berkeley.edu/~jonah/bc/org/bouncycastle/asn1/x509/X509Name.html
103 | KeyValuePairList attrs =
104 | new KeyValuePairList();
105 |
106 |
107 | if (!string.IsNullOrEmpty(countryIso2Characters) && countryIso2Characters.Trim() != string.Empty)
108 | attrs.Add(Org.BouncyCastle.Asn1.X509.X509Name.C, countryIso2Characters);
109 |
110 | if (!string.IsNullOrEmpty(stateOrProvince) && stateOrProvince.Trim() != string.Empty)
111 | attrs.Add(Org.BouncyCastle.Asn1.X509.X509Name.ST, stateOrProvince);
112 |
113 | if (!string.IsNullOrEmpty(localityOrCity) && localityOrCity.Trim() != string.Empty)
114 | attrs.Add(Org.BouncyCastle.Asn1.X509.X509Name.L, localityOrCity);
115 |
116 | if (!string.IsNullOrEmpty(companyName) && companyName.Trim() != string.Empty)
117 | attrs.Add(Org.BouncyCastle.Asn1.X509.X509Name.O, companyName);
118 |
119 | if (!string.IsNullOrEmpty(division) && division.Trim() != string.Empty)
120 | attrs.Add(Org.BouncyCastle.Asn1.X509.X509Name.OU, division);
121 |
122 | // Must have ?
123 | if (!string.IsNullOrEmpty(domainName) && domainName.Trim() != string.Empty)
124 | attrs.Add(Org.BouncyCastle.Asn1.X509.X509Name.CN, domainName);
125 |
126 | if (!string.IsNullOrEmpty(email) && email.Trim() != string.Empty)
127 | {
128 | //attrs.Add(Org.BouncyCastle.Asn1.X509.X509Name.E, email); // email address in Verisign certificates
129 | attrs.Add(Org.BouncyCastle.Asn1.X509.X509Name.EmailAddress, email); // Email address (RSA PKCS#9 extension)
130 | }
131 |
132 | Org.BouncyCastle.Asn1.X509.X509Name subject =
133 | new Org.BouncyCastle.Asn1.X509.X509Name(attrs.Keys, attrs.Values);
134 |
135 | return subject;
136 | } // End Function CreateSubject
137 |
138 |
139 | public CertificateInfo()
140 | {
141 | this.NonCriticalExtensions = new System.Collections.Generic.Dictionary(System.StringComparer.OrdinalIgnoreCase);
142 | this.CriticalExtensions = new System.Collections.Generic.Dictionary(System.StringComparer.OrdinalIgnoreCase);
143 | } // End Constructor
144 |
145 |
146 | public CertificateInfo(
147 | string countryIso2Characters
148 | , string stateOrProvince
149 | , string localityOrCity
150 | , string companyName
151 | , string division
152 | , string domainName
153 | , string email
154 | , System.DateTime validFrom
155 | , System.DateTime validTo
156 | ) : this()
157 | {
158 | this.CountryIso2Characters = countryIso2Characters;
159 | this.StateOrProvince = stateOrProvince;
160 | this.LocalityOrCity = localityOrCity;
161 | this.CompanyName = companyName;
162 | this.Division = division;
163 | this.DomainName = domainName;
164 | this.EMail = email;
165 | this.ValidFrom = validFrom;
166 | this.ValidTo = validTo;
167 | } // End Constructor
168 |
169 |
170 | public void AddAlternativeNames(params string[] names)
171 | {
172 | this.AlternativeNames = names;
173 | } // End Sub AddAlternativeNames
174 |
175 |
176 | public void AddExtension(
177 | string oid
178 | , bool critical
179 | , Org.BouncyCastle.Asn1.Asn1Encodable extensionValue)
180 | {
181 | if (critical)
182 | this.CriticalExtensions.Add(oid, extensionValue);
183 | else
184 | this.NonCriticalExtensions.Add(oid, extensionValue);
185 | } // End Sub AddExtension
186 |
187 |
188 | } // End Class
189 |
190 |
191 | } // End Namespace
192 |
--------------------------------------------------------------------------------