using System.Net; using System.Threading.Tasks; using System.Web; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Middleware; /// /// Validates the IP of requests coming from local networks wrt. remote access. /// public class IPBasedAccessValidationMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// The next delegate in the pipeline. /// The logger to log to. public IPBasedAccessValidationMiddleware(RequestDelegate next, ILogger logger) { _next = next; _logger = logger; } /// /// Executes the middleware action. /// /// The current HTTP context. /// The network manager. /// The async task. public async Task Invoke(HttpContext httpContext, INetworkManager networkManager) { if (httpContext.IsLocal()) { // Accessing from the same machine as the server. await _next(httpContext).ConfigureAwait(false); return; } var remoteIP = httpContext.GetNormalizedRemoteIP(); var result = networkManager.ShouldAllowServerAccess(remoteIP); if (result != RemoteAccessPolicyResult.Allow) { // No access from network, respond with 503 instead of 200. _logger.LogWarning( "Blocking request to {Path} by {RemoteIP} due to IP filtering rule, reason: {Reason}", // url-encode to block log injection HttpUtility.UrlEncode(httpContext.Request.Path), remoteIP, result); httpContext.Response.StatusCode = StatusCodes.Status503ServiceUnavailable; return; } await _next(httpContext).ConfigureAwait(false); } }