/// <summary> /// Called when each request is intercepted and has not gone to the server yet. /// </summary> internal ProxyNextAction OnBeforeRequest(GoproxyWrapper.Session args) { ProxyNextAction nextAction = ProxyNextAction.AllowAndIgnoreContent; int trackId = 0; lock (trackIdLock) { trackId = nextTrackId++; } // Don't allow filtering if our user has been denied access and they // have not logged back in. if (m_ipcServer != null && m_ipcServer.WaitingForAuth) { return(ProxyNextAction.AllowAndIgnoreContentAndResponse); } try { ZonedDateTime date = m_timeDetection.GetRealTime(); TimeRestrictionModel todayRestriction = null; if (m_policyConfiguration != null && m_policyConfiguration.TimeRestrictions != null && date != null) { todayRestriction = m_policyConfiguration.TimeRestrictions[(int)date.ToDateTimeOffset().DayOfWeek]; } string urlString = args.Request.Url; Uri url = new Uri(urlString); Uri serviceProviderPath = new Uri(CompileSecrets.ServiceProviderApiPath); if (url.Host == serviceProviderPath.Host) { return(ProxyNextAction.AllowAndIgnoreContentAndResponse); } else if (todayRestriction != null && todayRestriction.RestrictionsEnabled && !m_timeDetection.IsDateTimeAllowed(date, todayRestriction)) { sendBlockResponse(args, urlString, null, BlockType.TimeRestriction); return(ProxyNextAction.DropConnection); } } catch (Exception e) { LoggerUtil.RecursivelyLogException(m_logger, e); } return(nextAction); }
internal void OnBeforeResponse(GoproxyWrapper.Session args) { ProxyNextAction nextAction = ProxyNextAction.AllowButRequestContentInspection; bool shouldBlock = false; string customBlockResponseContentType = null; byte[] customBlockResponse = null; // Don't allow filtering if our user has been denied access and they // have not logged back in. if (m_ipcServer != null && m_ipcServer.WaitingForAuth) { return; } // The only thing we can really do in this callback, and the only thing we care to do, is // try to classify the content of the response payload, if there is any. try { Uri uri = new Uri(args.Request.Url); Uri serviceProviderPath = new Uri(CompileSecrets.ServiceProviderApiPath); if (uri.Host == serviceProviderPath.Host) { return; } // Check our certificate exemptions to see if we should allow this site through or not. if (args.Response.CertificateCount > 0 && !args.Response.IsCertificateVerified && !m_certificateExemptions.IsExempted(uri.Host, args.Response.Certificates[0])) { customBlockResponseContentType = "text/html"; customBlockResponse = m_templates.ResolveBadSslTemplate(new Uri(args.Request.Url), args.Response.Certificates[0].Thumbprint); nextAction = ProxyNextAction.DropConnection; return; } string contentType = null; if (args.Response.Headers.HeaderExists("Content-Type")) { contentType = args.Response.Headers.GetFirstHeader("Content-Type").Value; bool isHtml = contentType.IndexOf("html") != -1; bool isJson = contentType.IndexOf("json") != -1; bool isTextPlain = contentType.IndexOf("text/plain") != -1; // Is the response content type text/html or application/json? Inspect it, otherwise return before we do content classification. // Why enforce content classification on only these two? There are only a few MIME types which have a high risk of "carrying" explicit content. // Those are: // text/plain // text/html // application/json if (!(isHtml || isJson || isTextPlain)) { return; } } if (contentType != null && args.Response.HasBody) { contentType = contentType.ToLower(); BlockType blockType; string textTrigger; string textCategory; byte[] responseBody = args.Response.Body; var contentClassResult = OnClassifyContent(responseBody, contentType, out blockType, out textTrigger, out textCategory); if (contentClassResult > 0) { shouldBlock = true; List <MappedFilterListCategoryModel> categories = new List <MappedFilterListCategoryModel>(); nextAction = ProxyNextAction.DropConnection; if (contentType.IndexOf("html") != -1) { customBlockResponseContentType = "text/html"; customBlockResponse = m_templates.ResolveBlockedSiteTemplate(new Uri(args.Request.Url), contentClassResult, categories, blockType, textCategory); } else if (contentType.IndexOf("application/json", StringComparison.InvariantCultureIgnoreCase) != -1) { customBlockResponseContentType = "application/json"; customBlockResponse = new byte[0]; } RequestBlocked?.Invoke(contentClassResult, blockType, new Uri(args.Request.Url), ""); m_logger.Info("Response blocked by content classification."); } } } catch (Exception e) { LoggerUtil.RecursivelyLogException(m_logger, e); } finally { if (nextAction == ProxyNextAction.DropConnection) { // TODO: Do we really need this as Info? m_logger.Info("Response blocked: {0}", args.Request.Url); if (customBlockResponse != null) { args.SendCustomResponse((int)HttpStatusCode.OK, customBlockResponseContentType, customBlockResponse); } } } }