From 0419f315e5689e043f311203ab8e61f69f1ee1d6 Mon Sep 17 00:00:00 2001 From: vnugent Date: Sun, 4 Aug 2024 17:14:10 -0400 Subject: Squashed commit of the following: commit bf6085a67a25c0242e3f170c3e617a08498d9ad0 Author: vnugent Date: Sun Aug 4 16:58:09 2024 -0400 fix compression source tree and source package commit 4eb2cf913495e8a7c8c9ad3fceb3bff2a1b2a072 Author: vnugent Date: Sun Aug 4 15:49:27 2024 -0400 push to codeberg commit 0b69bc760f87efab73ca6efb454b30a3393be269 Author: vnugent Date: Sun Aug 4 15:36:26 2024 -0400 consolidate log config commit b8841c2218133bb8692e30cee0cfc719bfa5e9a0 Author: vnugent Date: Thu Aug 1 21:30:59 2024 -0400 update compression copyright data and add package.json commit 08020ccace1474e27702ad6575259e799ca56b63 Merge: 904560a ff1765d Author: vnugent Date: Thu Aug 1 21:26:47 2024 -0400 Merge branch 'develop' into slurp-webserver commit ff1765d3aa4d98fd223c47d16fca8e3e13a4d894 Author: vnugent Date: Thu Aug 1 21:26:05 2024 -0400 set trasnport manager setters private for debug commit 904560a7b5eafd7580fb0a03e778d1751e72a503 Author: vnugent Date: Thu Aug 1 21:13:04 2024 -0400 build(app): swallow vnlib.webserver into core & build updates commit 6af95e61212611908d39235222474d4038e10fcd Author: vnugent Date: Wed Jul 31 15:14:07 2024 -0400 ci: clean up heapapi header & better formalize taskfiles commit 52965ce8bb0b06f59b07c7f6b5a9de6bfbc22b40 Author: vnugent Date: Mon Jul 29 12:26:32 2024 -0400 move dev-init to module level for vnbuild module init commit e66b75642f654f623a3115bd3586d567d1554726 Merge: a4dacd2 7be5d66 Author: vnugent Date: Sun Jul 28 19:16:13 2024 -0400 Merge branch 'master' into develop commit a4dacd2909426bf628c1eee1253cc5c8a01e2691 Author: vnugent Date: Sat Jul 27 22:41:04 2024 -0400 package updates commit f836e09981866f5c9f2ae46990d11b186a7d12bb Author: vnugent Date: Wed Jul 24 19:15:54 2024 -0400 chore: Remove argon2 docs & optional tcp resuse commit b9b892ab2143b0ab92e4dcf0a8b043c5c6c17271 Author: vnugent Date: Sun Jul 21 20:57:01 2024 -0400 fix spelling Enqueue and deprecate mispelled version commit 21ffa816f18be4b765ad740ed5d93346ec3b1fda Author: vnugent Date: Sat Jul 20 19:44:31 2024 -0400 static arugment list parsing functions commit 85cd6793818a3edd0a963bb4829a960ee6b0e022 Author: vnugent Date: Mon Jul 15 18:58:06 2024 -0400 chore: Just some minor checks and adjustments commit abfb5761ee381b7e1e5342a5525ceca8c8fd81dd Author: vnugent Date: Thu Jul 4 23:57:37 2024 -0400 analyzer pass commit 4a96dbb924f2b5bf80293e4054f221efe67151dd Author: vnugent Date: Thu Jul 4 22:45:28 2024 -0400 package updates commit 38ad7d923fa8d9e463d4aaa8e35f021086a03f2d Author: vnugent Date: Thu Jul 4 16:20:48 2024 -0400 mimalloc merge upstream upgrades commit 981ba286e4793de95bf65e6588313411344c4d53 Author: vnugent Date: Thu Jul 4 16:04:03 2024 -0400 refactor: Refactor extensions with perf updates commit 6b8c67888731f7dd210acdb2b1160cdbdbe30d47 Author: vnugent Date: Fri Jun 28 15:48:22 2024 -0400 refactor: Update service stack to reflect new loading patterns commit 12391e9a207b60b41a074600fc2373ad3eb1c3ab Author: vnugent Date: Wed Jun 26 21:01:15 2024 -0400 feat(server): Server arch update, Memory struct access commit 92e182ceaf843f8d859d38faa8b2c0ff53207ff6 Author: vnugent Date: Fri Jun 21 16:02:34 2024 -0400 feat: Multi transport listeners commit ee3620b8168a42c8e571e853c751ad5999a9b907 Author: vnugent Date: Tue Jun 18 21:17:28 2024 -0400 feat: Add file path caching support commit ff0926be56fc6eafdce36411847d73bf4ce9f183 Author: vnugent Date: Sun Jun 16 13:08:31 2024 -0400 feat: Allow multiple plugin loading directories commit 07ddf6738d32127926d07b1366e56d2a2308b53b Author: vnugent Date: Sun Jun 16 01:12:07 2024 -0400 perf: Absolutely yuge perf boosts commit ff15c05a9c3e632c39f3889820fb7d889342b452 Author: vnugent Date: Fri Jun 14 14:16:24 2024 -0400 fix: Improper request buffer property assignment commit 7d2987f1d4048c30808a85798e32c99747f6cfe3 Author: vnugent Date: Thu Jun 13 21:57:34 2024 -0400 perf: Async pre-buffer to avoid sync buffer commit 75c1d0cbf9a5a7856c544671a45f1b4312ffe7ce Author: vnugent Date: Tue Jun 11 22:11:45 2024 -0400 feat: Add a default site adapater and interceptors commit a7c739b7db9a17622cee751fe0e8a10e4b84b48b Author: vnugent Date: Sun Jun 9 13:05:12 2024 -0400 chore: Package updated commit b4b506a4b6c7c1e90b5b0980e4cfe0460e7546a2 Author: vnugent Date: Sat Jun 8 21:54:52 2024 -0400 some minor touchups commit 2160510fcc22a8574b0090fd91ca29072f45ab59 Author: vnugent Date: Fri May 31 15:12:20 2024 -0400 refactor: Immutable tcp listeners commit 51cb4eb93e4f1b4c47d35b105e72af1fe771abcc Author: vnugent Date: Thu May 30 17:31:16 2024 -0400 refactor: minor non-breaking changes to VNEncoding commit 768ddc1eb949266d693f96c67d734e881bd59374 Merge: 9a835fe 1b590c2 Author: vnugent Date: Wed May 22 17:50:57 2024 -0400 Merge branch 'main' into develop commit 9a835fe12c9586ab8dd44d7c96fef4a2d6017e4b Author: vnugent Date: Fri May 17 18:27:03 2024 -0400 chore: Update mimmaloc v2.1.6, update fPIC & cleanup commit 3b7004b88acfc7f7baa3a8857a5a2f7cf3dd560e Author: vnugent Date: Fri May 17 16:03:28 2024 -0400 feat: Added ReadFileDataAsync function commit 9a964795757bf0da4dd7fcab15ad304f4ea3fdf1 Author: vnugent Date: Wed May 15 21:57:39 2024 -0400 refactor: Harden some argon2 password hashing commit 4035c838c1508af0aa7e767a97431a692958ce1c Author: vnugent Date: Sun May 12 16:55:32 2024 -0400 perf: Utils + http perf mods commit f4f0d4f74250257991c57bfae74c4852c7e1ae46 Author: vnugent Date: Thu May 2 15:22:53 2024 -0400 feat: Buff middleware handlers | | Added implicit support for middleware post processing of files before the filehandler closes the connection. Also cleaned up some project file stuff commit f0b7dca107659df1d7d4631fdbd2aae9d716d053 Merge: 8c4a45e 107b058 Author: vnugent Date: Sat Apr 20 12:24:05 2024 -0400 Merge branch 'main' into develop commit 8c4a45e384accf92b1b6d748530e8d46f7de40d6 Author: vnugent Date: Sat Apr 20 11:10:30 2024 -0400 refactor: Overhaul C libraries and fix builds commit 42ff77080d10b0fc9fecbbc46141e8e23a1d066a Author: vnugent Date: Sat Apr 20 00:45:57 2024 -0400 fix!: Middlware array, multiple cookie set, and cookie check commit 97e82b9d66f387f9e6d21d88ddc7a8ab8693149c Merge: 4ca5791 e07537a Author: vnugent Date: Tue Apr 2 13:34:22 2024 -0400 Merge branch 'main' into develop commit 4ca5791ed67b9834bdbd010206b30373e4705e9b Author: vnugent Date: Tue Apr 2 13:32:12 2024 -0400 fix: Missed ! on null pointer check commit 9b4036377c52200c6488c98180d69a0e63321f97 Author: vnugent Date: Tue Apr 2 13:22:29 2024 -0400 fix: Fix _In_ macro for compression public api commit 53a7b4b5c5b67b4a4e06e1d9098cac4bcd6afd7c Merge: 448a93b 21130c8 Author: vnugent Date: Sun Mar 31 17:01:15 2024 -0400 Merge branch 'main' into develop commit 448a93bb1d18d032087afe2476ffccb98634a54c Author: vnugent Date: Sun Mar 31 16:56:51 2024 -0400 ci: fix third-party dir cleanup commit 9afed1427472da1ea13079f98dbe27339e55ee7d Author: vnugent Date: Sun Mar 31 16:43:15 2024 -0400 perf: Deprecate unsafememoryhandle span extensions commit 3ff90da4f02af47ea6d233fdd4445337ebe36452 Author: vnugent Date: Sat Mar 30 21:36:18 2024 -0400 refactor: Updates, advanced tracing, http optimizations commit 8d6b79b5ae309b36f265ba81529bcef8bfcd7414 Merge: 6c1667b 5585915 Author: vnugent Date: Sun Mar 24 21:01:31 2024 -0400 Merge branch 'main' into develop commit 6c1667be23597513537f8190e2f55d65eb9b7c7a Author: vnugent Date: Fri Mar 22 12:01:53 2024 -0400 refactor: Overhauled native library loading and lazy init commit ebf688f2f974295beabf7b5def7e6f6f150551d0 Author: vnugent Date: Wed Mar 20 22:16:17 2024 -0400 refactor: Update compression header files and macros + Ci build commit 9c7b564911080ccd5cbbb9851a0757b05e1e9047 Author: vnugent Date: Tue Mar 19 21:54:49 2024 -0400 refactor: JWK overhaul & add length getter to FileUpload commit 6d8c3444e09561e5957491b3cc1ae858e0abdd14 Author: vnugent Date: Mon Mar 18 16:13:20 2024 -0400 feat: Add FNV1a software checksum and basic correction tests commit 00d182088cecefc08ca80b1faee9bed3f215f40b Author: vnugent Date: Fri Mar 15 01:05:27 2024 -0400 chore: #6 Use utils filewatcher instead of built-in commit d513c10d9895c6693519ef1d459c6a5a76929436 Author: vnugent Date: Sun Mar 10 21:58:14 2024 -0400 source tree project location updated --- .../src/Middlewares/BenchmarkMiddleware.cs | 102 ++++++++++++ .../src/Middlewares/CORSMiddleware.cs | 182 +++++++++++++++++++++ .../src/Middlewares/ConnectionLogMiddleware.cs | 108 ++++++++++++ .../src/Middlewares/IpBlacklistMiddleware.cs | 49 ++++++ .../src/Middlewares/IpWhitelistMiddleware.cs | 53 ++++++ .../src/Middlewares/MainServerMiddlware.cs | 100 +++++++++++ 6 files changed, 594 insertions(+) create mode 100644 apps/VNLib.WebServer/src/Middlewares/BenchmarkMiddleware.cs create mode 100644 apps/VNLib.WebServer/src/Middlewares/CORSMiddleware.cs create mode 100644 apps/VNLib.WebServer/src/Middlewares/ConnectionLogMiddleware.cs create mode 100644 apps/VNLib.WebServer/src/Middlewares/IpBlacklistMiddleware.cs create mode 100644 apps/VNLib.WebServer/src/Middlewares/IpWhitelistMiddleware.cs create mode 100644 apps/VNLib.WebServer/src/Middlewares/MainServerMiddlware.cs (limited to 'apps/VNLib.WebServer/src/Middlewares') diff --git a/apps/VNLib.WebServer/src/Middlewares/BenchmarkMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/BenchmarkMiddleware.cs new file mode 100644 index 0000000..2e2020c --- /dev/null +++ b/apps/VNLib.WebServer/src/Middlewares/BenchmarkMiddleware.cs @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: BenchmarkMiddleware.cs +* +* BenchmarkMiddleware.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + + +using System; +using System.Net; +using System.Buffers; +using System.Diagnostics; +using System.Threading.Tasks; +using System.Security.Cryptography; + +using VNLib.Utils.Memory; +using VNLib.Utils.Extensions; +using VNLib.Net.Http; +using VNLib.Plugins.Essentials; +using VNLib.Plugins.Essentials.Middleware; + +using VNLib.WebServer.Config.Model; + +namespace VNLib.WebServer.Middlewares +{ + /* + * This is a cheatsy little syntethic benchmark middleware that will + * return a fixed size memory response for every request to simulate + * a file response for synthetic benchmarking. + * + * The buffer may optionally be filled with random data to put a + * load on the compressor instead of a zero filled buffer + */ + + internal sealed class BenchmarkMiddleware(BenchmarkConfig config) : IHttpMiddleware + { + private readonly MemoryManager data = AllocBuffer(config.Size, config.Random); + + public ValueTask ProcessAsync(HttpEntity entity) + { + entity.CloseResponse( + HttpStatusCode.OK, + ContentType.Binary, + new BenchmarkResponseData(data.Memory) + ); + + return ValueTask.FromResult(FileProcessArgs.VirtualSkip); + } + + private static MemoryManager AllocBuffer(int size, bool random) + { + /* + * Even though this is testing, the buffer is zeroed to avoid leaking + * any data that may be in heap memory after allocation. + */ + MemoryManager man = MemoryUtil.Shared.DirectAlloc(size, true); + + if (random) + { + RandomNumberGenerator.Fill(man.GetSpan()); + } + + return man; + } + + private sealed class BenchmarkResponseData(ReadOnlyMemory data) : IMemoryResponseReader + { + int read; + readonly int len = data.Length; + + public int Remaining => len - read; + + public void Advance(int written) + { + read += written; + Debug.Assert(Remaining >= 0); + } + + public void Close() + { } + + public ReadOnlyMemory GetMemory() => data.Slice(read, Remaining); + } + } +} \ No newline at end of file diff --git a/apps/VNLib.WebServer/src/Middlewares/CORSMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/CORSMiddleware.cs new file mode 100644 index 0000000..08b7cee --- /dev/null +++ b/apps/VNLib.WebServer/src/Middlewares/CORSMiddleware.cs @@ -0,0 +1,182 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: CORSMiddleware.cs +* +* CORSMiddleware.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System; +using System.Net; +using System.Threading.Tasks; +using System.Collections.Frozen; + +using VNLib.Net.Http; +using VNLib.Utils.Logging; +using VNLib.Plugins.Essentials; +using VNLib.Plugins.Essentials.Sessions; +using VNLib.Plugins.Essentials.Extensions; +using VNLib.Plugins.Essentials.Middleware; + +using VNLib.WebServer.Config.Model; + +namespace VNLib.WebServer.Middlewares +{ + + /// + /// Adds HTTP CORS protection to http servers + /// + /// + /// + [MiddlewareImpl(MiddlewareImplOptions.SecurityCritical)] + internal sealed class CORSMiddleware(ILogProvider Log, CorsSecurityConfig secConfig) : IHttpMiddleware + { + private readonly FrozenSet _corsAuthority = secConfig.AllowedCorsAuthority.ToFrozenSet(StringComparer.OrdinalIgnoreCase); + + public ValueTask ProcessAsync(HttpEntity entity) + { + //Check coors enabled + bool isCors = entity.Server.IsCors(); + bool isCrossSite = entity.Server.IsCrossSite(); + + /* + * Deny/allow cross site/cors requests at the site-level + */ + if (!secConfig.DenyCorsCons) + { + //Confirm the origin is allowed during cors connections + if (entity.Server.CrossOrigin && _corsAuthority.Count > 0) + { + //If the authority is not allowed, deny the connection + if (!_corsAuthority.Contains(entity.Server.Origin!.Authority)) + { + Log.Debug("Denied a connection from a cross-origin site {s}, the origin was not whitelisted", entity.Server.Origin); + return ValueTask.FromResult(FileProcessArgs.Deny); + } + } + + if (isCors) + { + //set the allow credentials header + entity.Server.Headers["Access-Control-Allow-Credentials"] = "true"; + + //If cross site flag is set, or the connection has cross origin flag set, set explicit origin + if (entity.Server.CrossOrigin || isCrossSite && entity.Server.Origin != null) + { + entity.Server.Headers["Access-Control-Allow-Origin"] = $"{entity.Server.RequestUri.Scheme}://{entity.Server.Origin!.Authority}"; + //Add origin to the response vary header when setting cors origin + entity.Server.Headers.Append(HttpResponseHeader.Vary, "Origin"); + } + } + + //Add sec vary headers for cors enabled sites + entity.Server.Headers.Append(HttpResponseHeader.Vary, "Sec-Fetch-Dest,Sec-Fetch-Mode,Sec-Fetch-Site"); + } + else if (isCors | isCrossSite) + { + Log.Verbose("Denied a cross-site/cors request from {con} because this site does not allow cross-site/cors requests", entity.TrustedRemoteIp); + return ValueTask.FromResult(FileProcessArgs.Deny); + } + + //If user-navigation is set and method is get, make sure it does not contain object/embed + if (entity.Server.IsNavigation() && entity.Server.Method == HttpMethod.GET) + { + string? dest = entity.Server.Headers["sec-fetch-dest"]; + if (dest != null && (dest.Contains("object", StringComparison.OrdinalIgnoreCase) || dest.Contains("embed", StringComparison.OrdinalIgnoreCase))) + { + Log.Debug("Denied a browser navigation request from {con} because it contained an object/embed", entity.TrustedRemoteIp); + return ValueTask.FromResult(FileProcessArgs.Deny); + } + } + + //If the connection is a cross-site, then an origin header must be supplied + if (isCrossSite && entity.Server.Origin is null) + { + Log.Debug("Denied cross-site request because origin header was not supplied"); + return ValueTask.FromResult(FileProcessArgs.Deny); + } + + //If same origin is supplied, enforce origin header on post/options/put/patch + if (string.Equals("same-origin", entity.Server.Headers["Sec-Fetch-Site"], StringComparison.OrdinalIgnoreCase)) + { + //If method is not get/head, then origin is required + if ((entity.Server.Method & (HttpMethod.GET | HttpMethod.HEAD)) == 0 && entity.Server.Origin == null) + { + Log.Debug("Denied same-origin POST/PUT... request because origin header was not supplied"); + return ValueTask.FromResult(FileProcessArgs.Deny); + } + } + + if(!IsSessionSecured(entity)) + { + return ValueTask.FromResult(FileProcessArgs.Deny); + } + + return ValueTask.FromResult(FileProcessArgs.Continue); + } + + private bool IsSessionSecured(HttpEntity entity) + { + ref readonly SessionInfo session = ref entity.Session; + + /* + * When sessions are created for connections that come from a different + * origin, their origin is stored for later. + * + * If the session was created from a different origin or the current connection + * is cross origin, then the origin must be allowed by the configuration + */ + + //No session loaded, nothing to check + if (!session.IsSet) + { + return true; + } + + if (entity.Server.Origin is null) + { + return true; + } + + if (session.IsNew || session.SessionType != SessionType.Web) + { + return true; + } + + bool sameOrigin = string.Equals( + entity.Server.Origin.Authority, + session.SpecifiedOrigin?.Authority, + StringComparison.OrdinalIgnoreCase + ); + + if (sameOrigin || _corsAuthority.Contains(entity.Server.Origin.Authority)) + { + return true; + } + + Log.Debug("Denied connection from {0} because the user's origin {org} changed to {other} and is not whitelisted.", + entity.TrustedRemoteIp, + session.SpecifiedOrigin?.Authority, + entity.Server.Origin.Authority + ); + + return false; + } + } +} \ No newline at end of file diff --git a/apps/VNLib.WebServer/src/Middlewares/ConnectionLogMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/ConnectionLogMiddleware.cs new file mode 100644 index 0000000..939fd0d --- /dev/null +++ b/apps/VNLib.WebServer/src/Middlewares/ConnectionLogMiddleware.cs @@ -0,0 +1,108 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: ConnectionLogMiddleware.cs +* +* ConnectionLogMiddleware.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +/* + * Provides an Nginx-style log of incoming connections. + */ + +using System.Threading.Tasks; +using System.Security.Authentication; + +using VNLib.Net.Http; +using VNLib.Utils.Logging; +using VNLib.Plugins.Essentials; +using VNLib.Plugins.Essentials.Middleware; + +namespace VNLib.WebServer.Middlewares +{ + internal sealed class ConnectionLogMiddleware(ILogProvider Log) : IHttpMiddleware + { + const string template = @"{ip} - {usr} [{local_time}] {tls} '{method} {url} {http_version}' {hostname} '{refer}' '{user_agent}' '{forwarded_for}'"; + + /// + public ValueTask ProcessAsync(HttpEntity entity) + { + if (Log.IsEnabled(LogLevel.Information)) + { + string userId = string.Empty; + if (entity.Session.IsSet) + { + userId = entity.Session.UserID; + } + + Log.Information(template, + entity.TrustedRemoteIp, + userId, + entity.RequestedTimeUtc.ToLocalTime().ToString("dd/MMM/yyyy:HH:mm:ss zzz", null), + GetTlsInfo(entity), + entity.Server.Method, + entity.Server.RequestUri.PathAndQuery, + GetProtocolVersionString(entity), + entity.RequestedRoot.Hostname, + entity.Server.Referer, + entity.Server.UserAgent, + entity.Server.Headers["X-Forwarded-For"] ?? string.Empty + ); + } + + return ValueTask.FromResult(FileProcessArgs.Continue); + } + + static string GetProtocolVersionString(HttpEntity entity) + { + return entity.Server.ProtocolVersion switch + { + HttpVersion.Http09 => "HTTP/0.9", + HttpVersion.Http1 => "HTTP/1.0", + HttpVersion.Http11 => "HTTP/1.1", + HttpVersion.Http2 => "HTTP/2.0", + HttpVersion.Http3 => "HTTP/3.0", + _ => "HTTP/1.1" + }; + } + + static string GetTlsInfo(HttpEntity entity) + { + ref readonly TransportSecurityInfo? secInfo = ref entity.Server.GetTransportSecurityInfo(); + + if(!secInfo.HasValue) + { + return string.Empty; + } + +#pragma warning disable CA5398, CA5397, SYSLIB0039 // Avoid hardcoded SslProtocols values + + return secInfo.Value.SslProtocol switch + { + SslProtocols.Tls => "TLSv1.0", + SslProtocols.Tls11 => "TLSv1.1", + SslProtocols.Tls12 => "TLSv1.2", + SslProtocols.Tls13 => "TLSv1.3", + _ => "Unknown" + }; + +#pragma warning restore CA5397, CA5398, SYSLIB0039 // Do not use deprecated SslProtocols values + } + } +} \ No newline at end of file diff --git a/apps/VNLib.WebServer/src/Middlewares/IpBlacklistMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/IpBlacklistMiddleware.cs new file mode 100644 index 0000000..5959a95 --- /dev/null +++ b/apps/VNLib.WebServer/src/Middlewares/IpBlacklistMiddleware.cs @@ -0,0 +1,49 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: WhitelistMiddleware.cs +* +* WhitelistMiddleware.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Net; +using System.Threading.Tasks; +using System.Collections.Frozen; + +using VNLib.Utils.Logging; +using VNLib.Plugins.Essentials; +using VNLib.Plugins.Essentials.Middleware; + +namespace VNLib.WebServer.Middlewares +{ + [MiddlewareImpl(MiddlewareImplOptions.SecurityCritical)] + internal sealed class IpBlacklistMiddleware(ILogProvider Log, FrozenSet Blacklist) : IHttpMiddleware + { + public ValueTask ProcessAsync(HttpEntity entity) + { + if (Blacklist.Contains(entity.TrustedRemoteIp)) + { + Log.Verbose("Client {ip} is blacklisted, blocked", entity.TrustedRemoteIp); + return ValueTask.FromResult(FileProcessArgs.Deny); + } + + return ValueTask.FromResult(FileProcessArgs.Continue); + } + } +} \ No newline at end of file diff --git a/apps/VNLib.WebServer/src/Middlewares/IpWhitelistMiddleware.cs b/apps/VNLib.WebServer/src/Middlewares/IpWhitelistMiddleware.cs new file mode 100644 index 0000000..bda754d --- /dev/null +++ b/apps/VNLib.WebServer/src/Middlewares/IpWhitelistMiddleware.cs @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: WhitelistMiddleware.cs +* +* WhitelistMiddleware.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Net; +using System.Threading.Tasks; +using System.Collections.Frozen; + +using VNLib.Utils.Logging; +using VNLib.Plugins.Essentials; +using VNLib.Plugins.Essentials.Middleware; + +namespace VNLib.WebServer.Middlewares +{ + /* + * Middelware that matches clients real ip addresses against a whitelist + * and blocks them if they are not on the list + */ + [MiddlewareImpl(MiddlewareImplOptions.SecurityCritical)] + internal sealed class IpWhitelistMiddleware(ILogProvider Log, FrozenSet WhiteList) : IHttpMiddleware + { + public ValueTask ProcessAsync(HttpEntity entity) + { + if (!WhiteList.Contains(entity.TrustedRemoteIp)) + { + Log.Verbose("Client {ip} is not whitelisted, blocked", entity.TrustedRemoteIp); + return ValueTask.FromResult(FileProcessArgs.Deny); + } + + return ValueTask.FromResult(FileProcessArgs.Continue); + } + } +} \ No newline at end of file diff --git a/apps/VNLib.WebServer/src/Middlewares/MainServerMiddlware.cs b/apps/VNLib.WebServer/src/Middlewares/MainServerMiddlware.cs new file mode 100644 index 0000000..da7eb3d --- /dev/null +++ b/apps/VNLib.WebServer/src/Middlewares/MainServerMiddlware.cs @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: MainServerMiddlware.cs +* +* MainServerMiddlware.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Net; +using System.Threading.Tasks; +using System.Collections.Generic; + +using VNLib.Net.Http; +using VNLib.Utils.Logging; +using VNLib.Plugins.Essentials; +using VNLib.Plugins.Essentials.Extensions; +using VNLib.Plugins.Essentials.Middleware; + +namespace VNLib.WebServer.Middlewares +{ + + /// + /// Provides required/essential server functionality as a middelware processor + /// + /// + /// + internal sealed class MainServerMiddlware(ILogProvider Log, VirtualHostConfig VirtualHostOptions, bool forcePorts) : IHttpMiddleware + { + public ValueTask ProcessAsync(HttpEntity entity) + { + //Set special server header + VirtualHostOptions.TrySetSpecialHeader(entity.Server, SpecialHeaders.Server); + + //Block websocket requests + if (entity.Server.IsWebSocketRequest) + { + Log.Verbose("Client {ip} made a websocket request", entity.TrustedRemoteIp); + } + + ref readonly TransportSecurityInfo? tlsSecInfo = ref entity.Server.GetTransportSecurityInfo(); + + //Check transport security if set + if (tlsSecInfo.HasValue) + { + + } + + //If not behind upstream server, uri ports and server ports must match + bool enforcePortCheck = !entity.IsBehindDownStreamServer && forcePorts; + + if (enforcePortCheck && !entity.Server.EnpointPortsMatch()) + { + Log.Debug("Connection {ip} received on port {p} but the client host port did not match at {pp}", + entity.TrustedRemoteIp, + entity.Server.LocalEndpoint.Port, + entity.Server.RequestUri.Port + ); + + return ValueTask.FromResult(FileProcessArgs.Deny); + } + + /* + * downstream server will handle the transport security, + * if the connection is not from an downstream server + * and is using transport security then we can specify HSTS + */ + if (entity.IsSecure) + { + VirtualHostOptions.TrySetSpecialHeader(entity.Server, SpecialHeaders.Hsts); + } + + //Add response headers from vh config + for (int i = 0; i < VirtualHostOptions.AdditionalHeaders.Length; i++) + { + //Get and append the client header value + ref KeyValuePair header = ref VirtualHostOptions.AdditionalHeaders[i]; + + entity.Server.Headers.Append(header.Key, header.Value); + } + + return ValueTask.FromResult(FileProcessArgs.Continue); + } + } +} \ No newline at end of file -- cgit