Example #1
0
        /// <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);
        }
Example #2
0
        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);
                    }
                }
            }
        }