예제 #1
0
        /// <summary>
        /// Неудачная авторизация
        /// </summary>
        /// <param name="Settings"></param>
        /// <param name="memoryCache"></param>
        /// <param name="RemoteIpAddress">IP адрес пользователя</param>
        /// <param name="typeBlockIP">Блокировка IP в 'Брандмауэр' глобально или только для домена</param>
        /// <param name="host"></param>
        public static void FailAuthorization(string RemoteIpAddress, TypeBlockIP typeBlockIP, string host = null)
        {
            var    memoryCache = Service.Get <IMemoryCache>();
            string key         = KeyToMemoryCache.LimitLogin(RemoteIpAddress);

            if (memoryCache.TryGetValue(key, out List <DateTime> TimeArray))
            {
                // Актуальные записи
                var array = (from time in TimeArray where (DateTime.Now - time).TotalMinutes < 10 select time).ToList();

                // База JsonDB
                var jsonDB = Service.Get <JsonDB>();

                // Блокировка IP
                if ((array.Count + 1) >= jsonDB.Security.CountAccess)
                {
                    // Где именно блокировать IP
                    string keyIPtables = typeBlockIP == TypeBlockIP.domain ? KeyToMemoryCache.IPtables(RemoteIpAddress, host) : KeyToMemoryCache.IPtables(RemoteIpAddress);

                    // Записываем IP в кеш IPtables
                    memoryCache.Set(keyIPtables, new IPtables("Перебор паролей", DateTime.Now.AddMinutes(jsonDB.Security.BlockingTime)), TimeSpan.FromMinutes(jsonDB.Security.BlockingTime));

                    // Удаляем ключ LimitLogin
                    memoryCache.Remove(key);

                    // Дублируем информацию в SQL
                    WriteLogTo.SQL(new BlockedIP()
                    {
                        IP           = RemoteIpAddress,
                        BlockingTime = DateTime.Now.AddMinutes(jsonDB.Security.BlockingTime),
                        Description  = "Перебор паролей",
                        typeBlockIP  = typeBlockIP,
                        BlockedHost  = host
                    });
                    return;
                }

                // Обновление записей
                array.Add(DateTime.Now);
                memoryCache.Set(key, array, TimeSpan.FromMinutes(10));
            }
            else
            {
                memoryCache.Set(key, new List <DateTime>()
                {
                    DateTime.Now
                }, TimeSpan.FromMinutes(10));
            }
        }
예제 #2
0
        /// <summary>
        /// Разблокировать IPv4/6
        /// </summary>
        /// <param name="IP">IPv4/6</param>
        /// <param name="target">Цель</param>
        /// <param name="BlockedHost">Заблокированный домен</param>
        public static void RemoveIPv4Or6(string IP, TypeBlockIP target, string BlockedHost)
        {
            if (target == TypeBlockIP.domain)
            {
                memoryCache.Remove(KeyToMemoryCache.IPtables(IP, BlockedHost));
                Trigger.OnRemoveIPv4Or6((IP, BlockedHost));
            }
            else if (target != TypeBlockIP.UserAgent)
            {
                if (IPNetwork.CheckingSupportToIPv4Or6(IP, out var ipnetwork))
                {
                    // IPv6
                    if (IP.Contains(":"))
                    {
                        string ipRegex = IPNetwork.IPv6ToRegex(ipnetwork.FirstUsable);
                        IPv6ToRegex = Regex.Replace(IPv6ToRegex, $@"^\^\({ipRegex}\|?", "^(");
                        IPv6ToRegex = Regex.Replace(IPv6ToRegex, $@"\|{ipRegex}", "");
                        if (IPv6ToRegex == "^()")
                        {
                            IPv6ToRegex = "^$";
                        }

                        if (IPv6ToModels.TryRemove(ipRegex, out _))
                        {
                            Trigger.OnRemoveIPv4Or6((IP, BlockedHost));
                        }
                    }

                    // IPv4
                    else
                    {
                        if (IPNetwork.IPv4ToRange(ipnetwork.FirstUsable, ipnetwork.LastUsable) is var item && item.FirstUsable != 0)
                        {
                            IPv4ToRange.RemoveAll(i => i.FirstUsable == item.FirstUsable && i.LastUsable == item.LastUsable);
                            if (IPv4ToModels.TryRemove(item.FirstUsable, out _))
                            {
                                Trigger.OnRemoveIPv4Or6((IP, BlockedHost));
                            }
                        }
                    }
                }
            }
        }
예제 #3
0
        public static bool CheckIP(string RemoteIpAddress, IMemoryCache memoryCache, out IPtables data, string BlockedHost = null)
        {
            string[] mass;
            string   patch, tmp = "";

            // IPv6
            if (RemoteIpAddress.Contains(":"))
            {
                mass  = RemoteIpAddress.Split(':');
                patch = ":";
            }

            // IPv4
            else
            {
                mass  = RemoteIpAddress.Split('.');
                patch = ".";
            }

            // Проверяем IP в кеше
            foreach (var ip in mass)
            {
                tmp += patch + ip;
                if (BlockedHost == null)
                {
                    if (memoryCache.TryGetValue(KeyToMemoryCache.IPtables(tmp.Remove(0, 1)), out data))
                    {
                        return(true);
                    }
                }
                else
                {
                    if (memoryCache.TryGetValue(KeyToMemoryCache.IPtables(tmp.Remove(0, 1), BlockedHost), out data))
                    {
                        return(true);
                    }
                }
            }

            data = new IPtables();
            return(false);
        }
예제 #4
0
        public JsonResult Remove(int Id)
        {
            #region Демо режим
            if (Platform.IsDemo)
            {
                return(Json(new Text("Операция недоступна в демо-режиме")));
            }
            #endregion

            // Поиск ip
            var item = coreDB.BlockedsIP.Find(Id);
            if (item == null)
            {
                return(Json(new Text("Запись не найдена")));
            }

            string IP = item.IP.Replace(".*", "").Replace(":*", "");

            // Удаляем IP с кеша
            memoryCache.Remove(KeyToMemoryCache.IPtables(IP));
            memoryCache.Remove(KeyToMemoryCache.IPtables(IP, item.BlockedHost));

            // Удаляем IP
            coreDB.BlockedsIP.Remove(item);

            // Сохраняем базу
            coreDB.SaveChanges();

            // Очистка кеша IPtables
            if (item.typeBlockIP == TypeBlockIP.UserAgent)
            {
                IPtablesMiddleware.ClearCache();
            }

            // Отдаем результат
            return(Json(new TrueOrFalse(true)));
        }
예제 #5
0
        public JsonResult Add(string value, string Description, int BlockingTimeDay, TypeBlockIP typeBlockIP = TypeBlockIP.global, bool IsAPI = false)
        {
            #region Демо режим
            if (Platform.IsDemo)
            {
                return(Json(new Text("Операция недоступна в демо-режиме")));
            }
            #endregion

            // Коректировка
            if (typeBlockIP == TypeBlockIP.domain)
            {
                typeBlockIP = TypeBlockIP.global;
            }

            // Коректор времени
            if (BlockingTimeDay <= 0)
            {
                BlockingTimeDay = 1;
            }

            #region Проверка IP/UserAgent
            if (typeBlockIP == TypeBlockIP.global)
            {
                // IP-адрес
                string IP = value;

                // Проверка IP
                if (string.IsNullOrWhiteSpace(IP) || (!IP.Contains(".") && !IP.Contains(":")))
                {
                    return(Json(new Models.Response.Text("Поле 'Значение' имеет недопустимое значение")));
                }

                // IP для кеша и проверки
                string IPshort = IP.Replace(".*", "").Replace(":*", "");

                // Проверка IP на дубликат
                if (IPtablesMiddleware.CheckIP(IPshort, memoryCache, out _))
                {
                    return(Json(new Models.Response.Text("Данный IP-адрес уже заблокирован")));
                }

                // Записываем IP в кеш IPtables
                memoryCache.Set(KeyToMemoryCache.IPtables(IPshort), new IPtables(Description, DateTime.Now.AddDays(BlockingTimeDay)), TimeSpan.FromDays(BlockingTimeDay));
            }
            else
            {
                // Проверка UserAgent
                if (string.IsNullOrWhiteSpace(value))
                {
                    return(Json(new Models.Response.Text("Поле 'Значение' имеет недопустимое значение")));
                }
            }
            #endregion

            // Дублируем информацию в SQL
            var blockedIP = new BlockedIP()
            {
                IP           = value,
                Description  = Description,
                BlockingTime = DateTime.Now.AddDays(BlockingTimeDay),
                typeBlockIP  = typeBlockIP
            };
            coreDB.BlockedsIP.Add(blockedIP);

            // Сохраняем SQL
            coreDB.SaveChanges();

            // Очистка кеша IPtables
            if (typeBlockIP == TypeBlockIP.UserAgent)
            {
                IPtablesMiddleware.ClearCache();
            }

            if (IsAPI)
            {
                return(Json(new TrueOrFalse(true)));
            }

            // Отдаем результат
            return(Json(new Html($@"<tr class='elemDelete'>
                                        <td class='text-left table-products'>
                                            <strong>{value}</strong>
                                        </td>

                                        <td>{(typeBlockIP == TypeBlockIP.global ? "IP-адрес" : "User Agent")}</td>
                                        <td>{Description}</td>
                                        <td>{DateTime.Now.AddDays(BlockingTimeDay).ToString("dd.MM.yyyy H:mm")}</td>

                                        <td style='text-align: right;' class='table-products btn-icons'>" +
                                 "<a onclick=\"return deleteElement(this,'/security/iptables/remove',{Id:'" + blockedIP.Id + "'});\" class=\"btn nopadding-nomargin\"><i class=\"fa fa-trash-o\"></i></a>" +
                                 @"</td>
                                    </tr>")));
        }
예제 #6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="antiBotType"></param>
        /// <param name="HostConvert"></param>
        /// <param name="method"></param>
        /// <param name="HttpContext"></param>
        /// <param name="domain"></param>
        /// <param name="outHtml"></param>
        public static bool ValidRequest(AntiBotType antiBotType, string HostConvert, string method, string uri, HttpContext HttpContext, Models.core.Cache.CheckLink.Domain domain, out string outHtml)
        {
            // По умолчанию null
            outHtml = null;

            // Не выбран способ проверки
            if (antiBotType == AntiBotType.Off)
            {
                return(true);
            }

            //IMemoryCache
            var memoryCache = Service.Get <IMemoryCache>();

            // IP адрес
            string IP = HttpContext.Connection.RemoteIpAddress.ToString();

            // Проверка Cookie
            if (IsValidCookie(HttpContext, IP))
            {
                return(true);
            }

            // База
            var jsonDB = Service.Get <JsonDB>();

            // Достаем настройки AntiBot из кеша
            var antiBotToGlobalConf = GlobalConf(jsonDB.AntiBot);

            #region Проверка User-Agent
            string SearchBot = "(" +
                               // https://yandex.ru/support/webmaster/robot-workings/check-yandex-robots.html
                               "YandexBot|YandexAccessibilityBot|YandexMobileBot|YandexDirectDyn|YandexScreenshotBot|YandexImages|YandexVideo|YandexVideoParser|YandexMedia|YandexBlogs|YandexFavicons|YandexWebmaster|YandexPagechecker|YandexImageResizer|YandexAdNet|YandexDirect|YaDirectFetcher|YandexCalendar|YandexSitelinks|YandexMetrika|YandexNews|YandexCatalog|YandexMarket|YandexVertis|YandexForDomain|YandexSpravBot|YandexSearchShop|YandexMedianaBot|YandexOntoDB|YandexVerticals" +
                               "|" +
                               // https://support.google.com/webmasters/answer/1061943
                               "APIs-Google|Mediapartners-Google|AdsBot-Google|Googlebot" +
                               "|" +
                               // https://help.mail.ru/webmaster/indexing/robots/robot_log
                               // https://www.bing.com/webmaster/help/how-to-verify-bingbot-3905dc26
                               "Mail.RU_Bot|Bingbot|msnbot" +
                               ")";

            // Достаем User-Agent
            if (HttpContext.Request.Headers.TryGetValue("User-Agent", out var userAgent))
            {
                // Проверка User-Agent на поискового бота
                if (Regex.IsMatch(userAgent, SearchBot, RegexOptions.IgnoreCase))
                {
                    #region Локальный метод - "DNSLookup"
                    bool DNSLookup()
                    {
                        try
                        {
                            // Получаем имя хоста по IP
                            var host = Dns.GetHostEntryAsync(IP).Result;

                            // Получаем IP хоста по имени
                            host = Dns.GetHostEntryAsync(host.HostName).Result;

                            // Проверяем имя хоста и IP на совпадение
                            if (host.AddressList.Where(i => i.ToString() == IP).FirstOrDefault() != null)
                            {
                                // Проверяем имя хоста на белый список DNSLookup
                                if (Regex.IsMatch(host.HostName, @".*\.(yandex.(ru|net|com)|googlebot.com|google.com|mail.ru|search.msn.com)$", RegexOptions.IgnoreCase))
                                {
                                    // Добовляем IP в белый
                                    WhitePtr.Add(IP, DateTime.Now.AddHours(IsGlobalConf() ? antiBotToGlobalConf.conf.HourCacheToBot : domain.AntiBot.HourCacheToBot));
                                    return(true);
                                }
                            }
                        }
                        catch { }

                        #region  Блокируем IP и записываем в журнал
                        // Данные для статистики
                        Check.Request.SetCountRequestToHour(TypeRequest._401, HostConvert, domain.confToLog.EnableCountRequest);

                        // Информация по блокировке
                        DateTime Expires = DateTime.Now.AddMinutes(40);
                        string   Msg     = "AntiBot";

                        // Записываем IP в кеш IPtables
                        memoryCache.Set(KeyToMemoryCache.IPtables(IP, HostConvert), new IPtables(Msg, Expires), Expires);

                        // Дублируем информацию в SQL
                        WriteLogTo.SQL(new BlockedIP()
                        {
                            IP           = IP,
                            BlockingTime = Expires,
                            Description  = Msg,
                            typeBlockIP  = TypeBlockIP.domain,
                            BlockedHost  = HostConvert
                        });

                        // Лог запроса
                        if (domain.confToLog.IsActive)
                        {
                            var geoIP = (Country : "Disabled", City : "Disabled", Region : "Disabled");
                            if (domain.confToLog.EnableGeoIP)
                            {
                                geoIP = GeoIP2.City(IP);
                            }

                            // Модель
                            Jurnal401 model = new Jurnal401()
                            {
                                Host      = HostConvert,
                                IP        = IP,
                                Msg       = Msg,
                                Ptr       = null,
                                UserAgent = userAgent,
                                Country   = geoIP.Country,
                                City      = geoIP.City,
                                Region    = geoIP.Region,
                                Time      = DateTime.Now
                            };

                            // Записываем данные в журнал
                            switch (domain.confToLog.Jurn401)
                            {
                            case WriteLogMode.File:
                                WriteLogTo.FileStream(model);
                                break;

                            case WriteLogMode.SQL:
                                WriteLogTo.SQL(model);
                                break;

                            case WriteLogMode.all:
                                WriteLogTo.SQL(model);
                                WriteLogTo.FileStream(model);
                                break;
                            }
                        }
                        #endregion

                        // Не удалось проверить PTR-запись
                        return(false);
                    }

                    #endregion

                    #region  ежим проверки поискового бота
                    if (IsGlobalConf() ? antiBotToGlobalConf.conf.FirstSkipToBot : domain.AntiBot.FirstSkipToBot)
                    {
                        // Проверяем DNSLookup в потоке
                        ThreadPool.QueueUserWorkItem(i => DNSLookup());
                    }
                    else
                    {
                        // Плохой бот
                        if (!DNSLookup())
                        {
                            outHtml = "Не удалось проверить PTR-запись";
                            return(false);
                        }
                    }
                    #endregion

                    // Бот может зайти на сайт
                    return(true);
                }

                // Достаем настройки WhiteList из кеша
                var whiteList = Engine.Base.SqlAndCache.WhiteList.GetCache(jsonDB.WhiteList);

                // Проверка пользовательского User-Agent
                if (Regex.IsMatch(userAgent, whiteList.UserAgentRegex, RegexOptions.IgnoreCase))
                {
                    return(true);
                }
            }
            #endregion

            // Нужна капча или нет
            bool IsRecaptcha = antiBotType == AntiBotType.reCAPTCHA;

            // Если капча установлена глобально, то нужно проверить домен в списке
            if (IsRecaptcha && IsGlobalConf() && antiBotToGlobalConf.conf.type == AntiBotType.reCAPTCHA)
            {
                IsRecaptcha = Regex.IsMatch(HostConvert, antiBotToGlobalConf.DomainsToreCaptchaRegex, RegexOptions.IgnoreCase);
            }

            // Выбираем настройки какого конфига использовать
            AntiBotBase antiBotConf = IsGlobalConf() ? (AntiBotBase)antiBotToGlobalConf.conf : (AntiBotBase)domain.AntiBot;

            #region Проверка пользователя в фоновом режиме
            if (antiBotConf.BackgroundCheck)
            {
                // Ключ для проверки запросов
                string memKey = $"Core:AntiBot/CountBackgroundRequest-{IP}";

                if (method != "GET")
                {
                    // Если до этого был GET запрос
                    if (memoryCache.TryGetValue(memKey, out _))
                    {
                        return(true);
                    }
                }
                else
                {
                    int CountBackgroundRequest;
                    if (!memoryCache.TryGetValue(memKey, out CountBackgroundRequest))
                    {
                        CountBackgroundRequest = 0;
                    }

                    // Пользователь не привысил значение
                    if (antiBotConf.CountBackgroundRequest > CountBackgroundRequest)
                    {
                        // Увеличиваем количиство запросов
                        if (!uri.Contains(".") || Regex.IsMatch(uri, antiBotConf.BackgroundCheckToAddExtensions, RegexOptions.IgnoreCase))
                        {
                            // Записываем/Перезаписываем количиство запросов
                            memoryCache.Set(memKey, ++CountBackgroundRequest, TimeSpan.FromHours(antiBotConf.BackgroundHourCacheToIP));
                        }

                        // Без заглушки AntiBot
                        return(true);
                    }
                }
            }
            #endregion


            // reCAPTCHA, SignalR или JavaScript
            var tplName = (!IsRecaptcha && antiBotType == AntiBotType.reCAPTCHA) ? AntiBotType.SignalR : antiBotType;
            outHtml = Html(tplName.ToString(), antiBotConf, jsonDB.Base.CoreAPI, IP, HostConvert, jsonDB.Base.reCAPTCHASitekey);
            return(false);

            #region Локальный метод - "IsGlobalConf"
            bool IsGlobalConf()
            {
                return(antiBotToGlobalConf.conf.Enabled || domain.AntiBot.UseGlobalConf);
            }

            #endregion
        }
예제 #7
0
        public static bool SetBlockedToIPtables(ModelCache.Domain Domain, string IP, string host, string Msg, DateTime Expires, string uri, string userAgent, string PtrHostName)
        {
            if (Domain.typeBlockIP == TypeBlockIP.Triggers)
            {
                // Что-бы в статистике не считать лишний раз +1 к блокировке
                string memKey = $"local-fb482608:SetBlockedToIPtables-{IP}";
                if (memoryCache.TryGetValue(memKey, out _))
                {
                    return(false); // Уже заблокирован
                }
                // Данные для статистики
                SetCountRequestToHour(TypeRequest._401, host, Domain.confToLog.EnableCountRequest);
                memoryCache.Set(memKey, (byte)0, Expires);
            }
            else
            {
                // Если IP уже заблокирован
                if ((Domain.typeBlockIP == TypeBlockIP.domain && memoryCache.TryGetValue(KeyToMemoryCache.IPtables(IP, host), out _)) ||
                    (Domain.typeBlockIP == TypeBlockIP.global && Engine.Security.IPtables.CheckIP(IP, out _)))
                {
                    return(false);
                }

                // Записываем IP в кеш IPtables
                IPtables.AddIPv4Or6(IP, new ModelIPtables(Msg, Expires), Domain.typeBlockIP, host);

                // Данные для статистики
                SetCountRequestToHour(TypeRequest._401, host, Domain.confToLog.EnableCountRequest);

                // Дублируем информацию в SQL
                WriteLogTo.SQL(new BlockedIP()
                {
                    IP           = IP,
                    BlockingTime = Expires,
                    Description  = Msg,
                    typeBlockIP  = Domain.typeBlockIP,
                    BlockedHost  = host
                });
            }

            // Игнорирование логов
            if (Domain.confToLog.IsActive && !Regex.IsMatch(uri, Domain.IgnoreLogToRegex, RegexOptions.IgnoreCase))
            {
                var geoIP = (Country : "Disabled", City : "Disabled", Region : "Disabled");
                if (Domain.confToLog.EnableGeoIP)
                {
                    geoIP = GeoIP2.City(IP);
                }

                // Модель
                Jurnal401 model = new Jurnal401()
                {
                    Host      = host,
                    IP        = IP,
                    Msg       = Msg,
                    Ptr       = PtrHostName,
                    UserAgent = userAgent,
                    Country   = geoIP.Country,
                    City      = geoIP.City,
                    Region    = geoIP.Region,
                    Time      = DateTime.Now
                };

                // Записываем данные в журнал
                switch (Domain.confToLog.Jurn401)
                {
                case WriteLogMode.File:
                    WriteLogTo.FileStream(model);
                    break;

                case WriteLogMode.SQL:
                    WriteLogTo.SQL(model);
                    break;

                case WriteLogMode.all:
                    WriteLogTo.SQL(model);
                    WriteLogTo.FileStream(model);
                    break;
                }
            }

            //
            return(true);
        }
예제 #8
0
        /// <summary>
        /// Проверить IPv4/6
        /// </summary>
        /// <param name="RemoteIpAddress">IPv4/6</param>
        /// <param name="data">Время и причина блокировки</param>
        /// <param name="BlockedHost">Домен для которого делать проверку</param>
        public static bool CheckIP(string RemoteIpAddress, out ModelIPtables data, string BlockedHost = null)
        {
            data = null;

            // Блокировка по домену
            if (BlockedHost != null)
            {
                if (memoryCache.TryGetValue(KeyToMemoryCache.IPtables(RemoteIpAddress, BlockedHost), out data))
                {
                    Trigger.OnReturn401((RemoteIpAddress, BlockedHost, "IP"));
                    return(true);
                }
            }

            // IPv6
            if (RemoteIpAddress.Contains(":"))
            {
                #region Локальный метод - "IsMatch"
                bool IsMatch(out string matchIP)
                {
                    var match = Regex.Match(RemoteIpAddress, IPv6ToRegex);

                    if (match.Length > 0 && RemoteIpAddress.Contains(match.Groups[1].Value))
                    {
                        matchIP = match.Groups[1].Value;
                        return(true);
                    }

                    matchIP = null;
                    return(false);
                }

                #endregion

                if (IPv6ToRegex != "^$" && IsMatch(out string matchIPv6))
                {
                    if (!IPv6ToModels.TryGetValue(matchIPv6, out data))
                    {
                        data = new ModelIPtables();
                    }
                    Trigger.OnReturn401((RemoteIpAddress, BlockedHost, "IP"));
                    return(true);
                }

                return(false);
            }

            // IPv4
            else
            {
                if (IPNetwork.CheckToIPv4(RemoteIpAddress, IPv4ToRange, out ulong FirstUsable))
                {
                    if (!IPv4ToModels.TryGetValue(FirstUsable, out data))
                    {
                        data = new ModelIPtables();
                    }
                    Trigger.OnReturn401((RemoteIpAddress, BlockedHost, "IP"));
                    return(true);
                }

                return(false);
            }
        }
예제 #9
0
        /// <summary>
        /// Заблокировать IPv4/6
        /// </summary>
        /// <param name="IP">IPv4/6</param>
        /// <param name="target">Цель</param>
        /// <param name="data">Время и причина блокировки</param>
        public static void AddIPv4Or6(string IP, ModelIPtables data, TypeBlockIP target, string BlockedHost = null)
        {
            if (target == TypeBlockIP.domain)
            {
                memoryCache.Set(KeyToMemoryCache.IPtables(IP, BlockedHost), data, data.TimeExpires);
                Trigger.OnAddIPv4Or6((IP, BlockedHost, data.Description, data.TimeExpires));
            }
            else if (target != TypeBlockIP.UserAgent)
            {
                if (IPNetwork.CheckingSupportToIPv4Or6(IP, out var ipnetwork))
                {
                    // Крон нужно запустить раньше
                    if (NextTimeClearDbAndCacheToIPv4Or6 > data.TimeExpires)
                    {
                        NextTimeClearDbAndCacheToIPv4Or6 = data.TimeExpires;
                    }

                    // IPv6
                    if (IP.Contains(":"))
                    {
                        string IPv6 = IPNetwork.IPv6ToRegex(ipnetwork.FirstUsable);

                        // Время и причина блокировки
                        IPv6ToModels.AddOrUpdate(IPv6, data, (s, e) => data);
                        Trigger.OnAddIPv4Or6((IP, BlockedHost, data.Description, data.TimeExpires));

                        #region Обновляем IPv6ToRegex
                        if (IPv6ToRegex == "^$")
                        {
                            IPv6ToRegex = $"^({IPv6})";
                        }
                        else
                        {
                            IPv6ToRegex = Regex.Replace(IPv6ToRegex, @"\)$", $"|{IPv6})");
                        }
                        #endregion
                    }

                    // IPv4
                    else
                    {
                        if (IPNetwork.IPv4ToRange(ipnetwork.FirstUsable, ipnetwork.LastUsable) is var item && item.FirstUsable != 0)
                        {
                            #region Находим число которое выше FirstUsable и ставим FirstUsable перед ним
                            int index = IPv4ToRange.FindIndex(0, IPv4ToRange.Count, i => i.FirstUsable > item.FirstUsable);

                            if (index == -1)
                            {
                                IPv4ToRange.Add(item);
                            }
                            else
                            {
                                IPv4ToRange.Insert(index, item);
                            }
                            #endregion

                            // Время и причина блокировки
                            IPv4ToModels.AddOrUpdate(item.FirstUsable, data, (s, e) => data);
                            Trigger.OnAddIPv4Or6((IP, BlockedHost, data.Description, data.TimeExpires));
                        }
                    }
                }
            }
        }
예제 #10
0
        public static Task Check(HttpContext context)
        {
            #region Получаем параметры запроса
            var    gRequest = new Regex(@"^(\?ip=([^&]+)&|\?)method=([^&]+)&host=([^&]+)&uri=([^\n\r]+)").Match(context.Request.QueryString.Value).Groups;
            string IP = gRequest[2].Value, method = gRequest[3].Value.ToUpper(), host = Regex.Replace(gRequest[4].Value, @"^www\.", "", RegexOptions.IgnoreCase), uri = WebUtility.UrlDecode(gRequest[5].Value);

            // Проверяем правильно ли мы спарсили данные
            if (string.IsNullOrWhiteSpace(host) || string.IsNullOrWhiteSpace(uri))
            {
                context.Response.ContentType = "text/html; charset=utf-8";
                return(context.Response.WriteAsync("Не сохранен порядок запроса<br />Пример: /core/check/request?ip=127.0.0.1&method=GET&host=test.com&uri=/", context.RequestAborted));
            }

            // IP адрес пользователя
            if (string.IsNullOrWhiteSpace(IP))
            {
                IP = context.Connection.RemoteIpAddress.ToString();
            }
            #endregion

            #region Получаем параметры POST запроса
            string FormData = string.Empty;
            if (context.Request.Method == "POST")
            {
                StringBuilder mass = new StringBuilder();
                foreach (var arg in context.Request.Form)
                {
                    // Удаляем из ключа массивы [] и проверяем на пустоту
                    string key = Regex.Replace(arg.Key, @"\[([^\]]+)?\]", "", RegexOptions.IgnoreCase);
                    if (string.IsNullOrWhiteSpace(key))
                    {
                        continue;
                    }

                    mass.Append($"&{key}={arg.Value[0]}");
                }

                FormData = mass.ToString();
            }
            #endregion

            #region ViewBag
            var viewBag = new ViewBag();
            viewBag.DebugEnabled = jsonDB.Base.DebugEnabled;       // Режим дебага, выводит json правил
            viewBag.IsErrorRule  = false;                          // Переменная для ловли ошибок regex
            #endregion

            // Если домена нету в базе, то выдаем 303 или заглушку
            if (ISPCache.DomainToID(host) is int DomainID && DomainID == 0)
            {
                return(jsonDB.Base.EnableToDomainNotFound ? ViewDomainNotFound(context) : View(context, viewBag, ActionCheckLink.allow));
            }

            // Если у IP есть полный доступ к сайтам или к сайту
            if (CheckLinkWhitelistToAllDomain())
            {
                return(View(context, viewBag, ActionCheckLink.allow));
            }

            #region Получаем User-Agent и Referer
            // User-Agent
            string userAgent = string.Empty;
            if (context.Request.Headers.TryGetValue("User-Agent", out var tmp_userAgent))
            {
                userAgent = tmp_userAgent.ToString();
            }

            // Referer
            string Referer = string.Empty;
            if (context.Request.Headers.TryGetValue("Referer", out var tmp_Referer))
            {
                Referer = tmp_Referer.ToString();
            }
            #endregion

            // Достаем данные домена
            var Domain = ISPCache.GetDomain(DomainID);

            // Достаем настройки AntiBot из кеша
            var antiBotToGlobalConf = AntiBot.GlobalConf(jsonDB.AntiBot);

            // Достаем настройки WhiteList из кеша
            var whiteList = Engine.Base.SqlAndCache.WhiteList.GetCache(jsonDB.WhiteList);

            #region Проверяем "IP/User-Agent" в блокировке IPtables
            // Проверяем IP в блокировке IPtables по домену
            if (IPtablesMiddleware.CheckIP(IP, memoryCache, out IPtables BlockedData, host))
            {
                // Логируем пользователя
                AddJurnalTo200(IsIPtables: true);
                SetCountRequestToHour(TypeRequest._200, host, Domain.confToLog.EnableCountRequest);

                // Отдаем ответ
                context.Response.StatusCode  = 401;
                context.Response.ContentType = "text/html; charset=utf-8";
                return(context.Response.WriteAsync(IPtablesMiddleware.BlockedToHtml(IP, BlockedData.Description, BlockedData.TimeExpires), context.RequestAborted));
            }

            // Проверяем User-Agent в блокировке IPtables
            if (IPtablesMiddleware.CheckUserAgent(userAgent))
            {
                // Логируем пользователя
                AddJurnalTo200(IsIPtables: true);
                SetCountRequestToHour(TypeRequest._200, host, Domain.confToLog.EnableCountRequest);

                // Отдаем ответ
                context.Response.StatusCode  = 401;
                context.Response.ContentType = "text/html; charset=utf-8";
                return(context.Response.WriteAsync(IPtablesMiddleware.BlockedHtmlToUserAgent(userAgent), context.RequestAborted));
            }
            #endregion

            // IP нету в пользовательском белом списке
            // IP нету в глобальном белом списке
            if (!Regex.IsMatch(IP, whiteList.IpRegex) &&
                !WhitePtr.IsWhiteIP(IP))
            {
                #region AntiBot
                if (!AntiBot.ValidRequest(((antiBotToGlobalConf.conf.Enabled || Domain.AntiBot.UseGlobalConf) ? antiBotToGlobalConf.conf.type : Domain.AntiBot.type), host, method, uri, context, Domain, out string outHtml))
                {
                    // Логируем пользователя
                    AddJurnalTo200(IsAntiBot: true);
                    SetCountRequestToHour(TypeRequest._200, host, Domain.confToLog.EnableCountRequest);

                    // Выводим html пользователю
                    context.Response.ContentType = "text/html; charset=utf-8";
                    return(context.Response.WriteAsync(outHtml, context.RequestAborted));
                }
                #endregion

                #region Лимит запросов
                if (Domain.limitRequest.IsEnabled || antiBotToGlobalConf.conf.limitRequest.IsEnabled)
                {
                    // Настройки лимита запросов
                    var limitRequest = (antiBotToGlobalConf.conf.limitRequest.IsEnabled || Domain.limitRequest.UseGlobalConf) ? antiBotToGlobalConf.conf.limitRequest : Domain.limitRequest;

                    // Проверяем белый список UserAgent
                    if (!Regex.IsMatch(userAgent, whiteList.UserAgentRegex, RegexOptions.IgnoreCase))
                    {
                        #region IsWhitePtr
                        bool IsWhitePtr(out string PtrHostName)
                        {
                            PtrHostName = null;

                            string KeyLimitRequestToBlockedWait = $"LimitRequestToBlockedWait-{IP}_{host}";

                            if (memoryCache.TryGetValue(KeyLimitRequestToBlockedWait, out _))
                            {
                                return(true);
                            }
                            memoryCache.Set(KeyLimitRequestToBlockedWait, (byte)0, TimeSpan.FromMinutes(5));

                            #region DNSLookup
                            try
                            {
                                // Белый список Ptr
                                string WhitePtrRegex = whiteList.PtrRegex;
                                if (WhitePtrRegex != "^$" && !string.IsNullOrWhiteSpace(WhitePtrRegex))
                                {
                                    // Получаем имя хоста по IP
                                    var DnsHost = Dns.GetHostEntryAsync(IP).Result;

                                    // Получаем IP хоста по имени
                                    DnsHost = Dns.GetHostEntryAsync(DnsHost.HostName).Result;

                                    // Проверяем имя хоста и IP на совпадение
                                    if (DnsHost.AddressList.Where(i => i.ToString() == IP).FirstOrDefault() != null)
                                    {
                                        PtrHostName = DnsHost.HostName;

                                        // Проверяем имя хоста на белый список DNSLookup
                                        if (Regex.IsMatch(DnsHost.HostName, WhitePtrRegex, RegexOptions.IgnoreCase))
                                        {
                                            // Добовляем IP в белый список на 9 дней
                                            WhitePtr.Add(IP, DateTime.Now.AddDays(9));
                                            memoryCache.Remove(KeyLimitRequestToBlockedWait);
                                            return(true);
                                        }
                                    }
                                }
                            }
                            catch { }
                            #endregion

                            // Сносим временную запись
                            memoryCache.Remove(KeyLimitRequestToBlockedWait);
                            return(false);
                        }

                        #endregion

                        #region Локальный метод - "СheckingToreCAPTCHA"
                        bool СheckingToreCAPTCHA(out Task content, int ExpiresToMinute)
                        {
                            content = null;

                            if (IsWhitePtr(out _))
                            {
                                return(false);
                            }

                            #region Валидный пользователь
                            if (memoryCache.TryGetValue(KeyToMemoryCache.LimitRequestToreCAPTCHA(IP), out (int countRequest, int ExpiresToMinute)item))
                            {
                                // Пользователь превысил допустимый лимит
                                if (item.countRequest >= limitRequest.MaxRequestToAgainСheckingreCAPTCHA)
                                {
                                    // Удаляем запись
                                    memoryCache.Remove(KeyToMemoryCache.LimitRequestToreCAPTCHA(IP));
                                    return(false);
                                }

                                // Считаем количество запросов
                                item.countRequest++;
                                memoryCache.Set(KeyToMemoryCache.LimitRequestToreCAPTCHA(IP), item, TimeSpan.FromMinutes(item.ExpiresToMinute));
                                return(false);
                            }
                            #endregion

                            #region Кеш шаблона
                            // Путь к шаблону
                            string SourceFile = $"{Folders.Tpl.LimitRequest}/reCAPTCHA.tpl";
                            if (!File.Exists(SourceFile))
                            {
                                SourceFile = $"{Folders.Tpl.LimitRequest}/default/reCAPTCHA.tpl";
                            }

                            // Время модификации файла
                            DateTime LastWriteTimeToFile = File.GetLastWriteTime(SourceFile);

                            // default value
                            (DateTime LastWriteTime, string Source)cacheTpl = (DateTime.Now, "");

                            // Обновляем кеш
                            if (!memoryCache.TryGetValue("core.Check.Request:LimitRequest-tpl", out cacheTpl) || LastWriteTimeToFile != cacheTpl.LastWriteTime)
                            {
                                cacheTpl.LastWriteTime = LastWriteTimeToFile;
                                cacheTpl.Source        = File.ReadAllText(SourceFile);
                                memoryCache.Set("core.Check.Request:LimitRequest-tpl", cacheTpl);
                            }
                            #endregion

                            #region Замена полей
                            string tpl = Regex.Replace(cacheTpl.Source, @"\{isp:([^\}]+)\}", key =>
                            {
                                switch (key.Groups[1].Value)
                                {
                                case "CoreApiUrl":
                                    return(jsonDB.Base.CoreAPI);

                                case "reCAPTCHASitekey":
                                    return(jsonDB.Base.reCAPTCHASitekey);

                                case "IP":
                                    return(IP);

                                case "ExpiresToMinute":
                                    return(ExpiresToMinute.ToString());

                                case "hash":
                                    return(md5.text($"{IP}{ExpiresToMinute}:{PasswdTo.salt}"));

                                default:
                                    return(string.Empty);
                                }
                            });
                            #endregion

                            // Ответ
                            context.Response.ContentType = "text/html; charset=utf-8";
                            content = context.Response.WriteAsync(tpl, context.RequestAborted);
                            return(true);
                        }

                        #endregion

                        #region Локальный метод - "CheckToLimit"
                        bool CheckToLimit(string keyName, int limit, int ExpiresToMinute, out CacheValue _cacheValue)
                        {
                            string key = $"LimitRequestTo{keyName}-{IP}_{host}";

                            if (memoryCache.TryGetValue(key, out CacheValue item))
                            {
                                item.value++;
                                _cacheValue = item;
                                if (item.value > limit)
                                {
                                    return(true);
                                }
                            }
                            else
                            {
                                _cacheValue = new CacheValue()
                                {
                                    value = 1, Expires = DateTime.Now.AddMinutes(ExpiresToMinute)
                                };
                                memoryCache.Set(key, _cacheValue, TimeSpan.FromMinutes(ExpiresToMinute));
                            }

                            return(false);
                        }

                        #endregion

                        #region Локальный метод - "BlockedToIP"
                        void BlockedToIP(string Msg, DateTime Expires)
                        {
                            if (IsWhitePtr(out string PtrHostName))
                            {
                                return;
                            }

                            // Записываем IP в кеш IPtables и журнал
                            SetBlockedToIPtables(Msg, Expires, PtrHostName);
                        }

                        #endregion

                        // Переменная для кеша
                        CacheValue cacheValue;

                        #region Метод блокировки
                        LimitToBlockType BlockType = limitRequest.BlockType;
                        if (BlockType == LimitToBlockType.reCAPTCHA && (antiBotToGlobalConf.conf.limitRequest.IsEnabled || Domain.limitRequest.UseGlobalConf))
                        {
                            // Если домена нету в глобальных настройках
                            if (!Regex.IsMatch(host, antiBotToGlobalConf.DomainsToreCaptchaRegex, RegexOptions.IgnoreCase))
                            {
                                BlockType = LimitToBlockType._403;
                            }
                        }
                        #endregion

                        #region Минутный лимит
                        if (limitRequest.MinuteLimit != 0 && CheckToLimit("Minute", limitRequest.MinuteLimit, 1, out cacheValue))
                        {
                            switch (BlockType)
                            {
                            case LimitToBlockType._403:
                                BlockedToIP("Превышен минутный лимит на запросы", cacheValue.Expires);
                                memoryCache.Remove($"LimitRequestToMinute-{IP}_{host}");
                                break;

                            case LimitToBlockType.reCAPTCHA:
                            {
                                if (СheckingToreCAPTCHA(out Task res, 2))
                                {
                                    return(res);
                                }
                            }
                            break;
                            }
                        }
                        #endregion

                        #region Часовой лимит
                        if (limitRequest.HourLimit != 0 && CheckToLimit("Hour", limitRequest.HourLimit, 60, out cacheValue))
                        {
                            switch (BlockType)
                            {
                            case LimitToBlockType._403:
                                BlockedToIP("Превышен часовой лимит на запросы", cacheValue.Expires);
                                memoryCache.Remove($"LimitRequestToHour-{IP}_{host}");
                                break;

                            case LimitToBlockType.reCAPTCHA:
                            {
                                if (СheckingToreCAPTCHA(out Task res, 61))
                                {
                                    return(res);
                                }
                            }
                            break;
                            }
                        }
                        #endregion

                        #region Дневной лимит
                        if (limitRequest.DayLimit != 0 && CheckToLimit("Day", limitRequest.DayLimit, 1440, out cacheValue))
                        {
                            switch (BlockType)
                            {
                            case LimitToBlockType._403:
                                BlockedToIP("Превышен дневной лимит на запросы", cacheValue.Expires);
                                memoryCache.Remove($"LimitRequestToHour-{IP}_{host}");
                                memoryCache.Remove($"LimitRequestToDay-{IP}_{host}");
                                break;

                            case LimitToBlockType.reCAPTCHA:
                            {
                                if (СheckingToreCAPTCHA(out Task res, 1441))
                                {
                                    return(res);
                                }
                            }
                            break;
                            }
                        }
                        #endregion
                    }
                }
                #endregion
            }

            #region Защита от Brute Force
            if (Domain.StopBruteForce != BruteForceType.Not)
            {
                // Настройки
                var BrutConf = jsonDB.BruteForceConf;

                // Переменная для кеша
                CacheValue cacheValue;

                #region Локальный метод - "CheckToLimit"
                bool CheckToLimit(string keyName, int limit, int ExpiresToMinute, out CacheValue _cacheValue)
                {
                    string key = $"BruteForceTo{keyName}-{IP}_{host}";

                    if (memoryCache.TryGetValue(key, out CacheValue item))
                    {
                        _cacheValue = item;
                        if (item.value >= limit)
                        {
                            return(true);
                        }
                    }

                    _cacheValue = null;
                    return(false);
                }

                #endregion

                #region Локальный метод - "BlockedToIP"
                void BlockedToIP(string Msg, DateTime Expires)
                {
                    string KeyLimitRequestToBlockedWait = $"BruteForceToBlockedWait-{IP}_{host}";

                    if (memoryCache.TryGetValue(KeyLimitRequestToBlockedWait, out _))
                    {
                        return;
                    }
                    memoryCache.Set(KeyLimitRequestToBlockedWait, (byte)0, TimeSpan.FromMinutes(5));

                    // Записываем IP в кеш IPtables и журнал
                    SetBlockedToIPtables(Msg, Expires, null);

                    // Сносим временную запись
                    memoryCache.Remove(KeyLimitRequestToBlockedWait);
                }

                #endregion

                // Блокировка IP
                if (CheckToLimit("Day", BrutConf.DayLimit, 1440, out cacheValue) || CheckToLimit("Hour", BrutConf.HourLimit, 60, out cacheValue) || CheckToLimit("Minute", BrutConf.MinuteLimit, 1, out cacheValue))
                {
                    BlockedToIP("Защита от Brute Force", cacheValue.Expires);
                }

                // Была авторизация
                if (BruteForce.IsLogin(Domain.StopBruteForce, method, uri, FormData))
                {
                    #region Локальный метод - "SetValue"
                    void SetValue(string keyName, int ExpiresToMinute)
                    {
                        string key = $"BruteForceTo{keyName}-{IP}_{host}";

                        if (memoryCache.TryGetValue(key, out CacheValue item))
                        {
                            item.value++;
                        }
                        else
                        {
                            memoryCache.Set(key, new CacheValue()
                            {
                                value = 1, Expires = DateTime.Now.AddMinutes(ExpiresToMinute)
                            }, TimeSpan.FromMinutes(ExpiresToMinute));
                        }
                    }

                    #endregion

                    // Обновляем счетчики
                    SetValue("Day", 1440);
                    SetValue("Hour", 60);
                    SetValue("Minute", 1);
                }
            }
            #endregion

            #region ViewBag
            if (jsonDB.Base.DebugEnabled)
            {
                viewBag.IP                  = IP;
                viewBag.jsonDomain          = JsonConvert.SerializeObject(Domain, Formatting.Indented);
                viewBag.antiBotToGlobalConf = JsonConvert.SerializeObject(antiBotToGlobalConf, Formatting.Indented);
                viewBag.FormData            = FormData;
            }

            viewBag.method    = method;
            viewBag.host      = host;
            viewBag.uri       = uri;
            viewBag.Referer   = context.Request.Headers["Referer"];
            viewBag.UserAgent = userAgent;
            #endregion

            #region Замена ответа - 302/код
            try
            {
                // Проверка url и GET аргументов
                if (Regex.IsMatch(uri, Domain.RuleReplaces.RuleGetToRegex, RegexOptions.IgnoreCase))
                {
                    // Проверка POST аргументов
                    if (method != "POST" || (method == "POST" && Regex.IsMatch($"{(new Regex(@"^(/[^\?\&]+)").Match(uri).Groups[1].Value)}{FormData}", Domain.RuleReplaces.RulePostToRegex, RegexOptions.IgnoreCase)))
                    {
                        // Разделяем URL на аргументы
                        var    g    = new Regex(@"^(/([^\?&]+)?((\?|&).*)?)$").Match(uri).Groups;
                        string args = g[3].Value.Replace("?", "&");

                        #region Локальный метод - GetRule
                        ModelCache.Rules.RuleReplace GetRule()
                        {
                            foreach (var item in Domain.RuleReplaces.Rules)
                            {
                                // Url не подходит
                                if (!Regex.IsMatch($"/{g[2].Value}", $"^{item.uri}$", RegexOptions.IgnoreCase))
                                {
                                    continue;
                                }

                                if (method == "POST")
                                {
                                    // Get или POST аргументы подходят
                                    if (Regex.IsMatch(args, item.GetArgsToRegex, RegexOptions.IgnoreCase) || Regex.IsMatch(FormData, item.PostArgsToRegex, RegexOptions.IgnoreCase))
                                    {
                                        return(item);
                                    }
                                }
                                else
                                {
                                    // Get аргументы подходят
                                    if (Regex.IsMatch(args, item.GetArgsToRegex, RegexOptions.IgnoreCase))
                                    {
                                        return(item);
                                    }
                                }
                            }

                            return(null);
                        }
                        #endregion

                        // Находим правило которое подходит для нашего запроса
                        if (GetRule() is ModelCache.Rules.RuleReplace rule)
                        {
                            #region Локальный метод - "ReplaceArgs"
                            string ReplaceArgs(string _args, string regexArgs)
                            {
                                StringBuilder mass = new StringBuilder();

                                foreach (var arg in _args.Split('&'))
                                {
                                    if (string.IsNullOrWhiteSpace(arg) || !arg.Contains('='))
                                    {
                                        continue;
                                    }

                                    var tmpArg = arg.Split('=');

                                    // Список аргументов для замены
                                    if (Regex.IsMatch(regexArgs, tmpArg[0], RegexOptions.IgnoreCase))
                                    {
                                        mass.Append("&" + tmpArg[0] + "=" + Regex.Replace(tmpArg[1], rule.RegexWhite, ""));
                                    }
                                    else
                                    {
                                        mass.Append("&" + arg);
                                    }
                                }

                                return(mass.ToString());
                            }
                            #endregion

                            #region Локальный метод - "ResponseContent"
                            Task ResponseContent(string _argsGet)
                            {
                                // Записываем данные пользователя
                                AddJurnalTo200();
                                SetCountRequestToHour(TypeRequest._200, host, Domain.confToLog.EnableCountRequest);

                                // Тип ответа
                                if (rule.TypeResponse == TypeResponseRule.kode)
                                {
                                    // Пользовательский код
                                    context.Response.ContentType = rule.ContentType;
                                    return(context.Response.WriteAsync(rule.kode, context.RequestAborted));
                                }
                                else
                                {
                                    if (string.IsNullOrWhiteSpace(rule.ResponceUri))
                                    {
                                        // Если url для 302 не указан
                                        return(RewriteTo.Local(context, g[2].Value + Regex.Replace(_argsGet, "^&", "?")));
                                    }
                                    else
                                    {
                                        // Редирект на указаный URL
                                        return(RewriteTo.Local(context, rule.ResponceUri.Replace("{arg}", Regex.Replace(_argsGet, "^&", "?"))));
                                    }
                                }
                            }
                            #endregion

                            // Если аргументы для проверки не указаны
                            if (rule.GetArgs == "" && rule.PostArgs == "")
                            {
                                return(ResponseContent(string.Empty));
                            }

                            #region argsGet / argsPOST
                            string argsGet  = ReplaceArgs(args, rule.GetArgs);
                            string argsPOST = string.Empty;

                            if (method == "POST")
                            {
                                argsPOST = ReplaceArgs(FormData, rule.PostArgs);
                            }
                            #endregion

                            // Замена ответа, если в аргументах есть лишние символы
                            if (args != argsGet || FormData != argsPOST)
                            {
                                return(ResponseContent(argsGet));
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // Записываем данные ошибки в журнал
                AddJurnalTo500(ex.Message);
                SetCountRequestToHour(TypeRequest._500, host, Domain.confToLog.EnableCountRequest);

                // Выводим ошибку
                viewBag.IsErrorRule         = true;
                viewBag.ErrorTitleException = "Ошибка в правиле";
                viewBag.ErrorRuleException  = jsonDB.Base.DebugEnabled ? ex.Message : "Данные ошибки доступны в журнале 500";
                return(View(context, viewBag, ActionCheckLink.deny));
            }
            #endregion

            // Переопределенные правила
            if (OpenPageToRule(Domain.RuleOverrideAllow, Domain.RuleOverride2FA, Domain.RuleOverrideDeny) is Task pageToRuleOverride)
            {
                return(pageToRuleOverride);
            }

            // Обычные правила
            if (OpenPageToRule(Domain.RuleAllow, Domain.Rule2FA, Domain.RuleDeny) is Task pageToRule)
            {
                return(pageToRule);
            }

            // Записываем данные пользователя
            AddJurnalTo403And303(Is303: true);
            SetCountRequestToHour(TypeRequest._303, host, Domain.confToLog.EnableCountRequest);

            // Если не одно правило не подошло
            return(View(context, viewBag, ActionCheckLink.allow));

            #region Локальный метод - "OpenPageToRule"
            Task OpenPageToRule(ModelCache.Rules.Rule RuleAllow, ModelCache.Rules.Rule Rule2FA, ModelCache.Rules.Rule RuleDeny)
            {
                #region  азрешенные запросы
                if (IsRequestTheRules(RuleAllow))
                {
                    // Записываем данные пользователя
                    AddJurnalTo403And303(Is303: true);
                    SetCountRequestToHour(TypeRequest._303, host, Domain.confToLog.EnableCountRequest);

                    // Если режим дебага выключен
                    if (!jsonDB.Base.DebugEnabled)
                    {
                        context.Response.StatusCode = 303;
                        return(context.Response.WriteAsync("303", context.RequestAborted));
                    }

                    // Разрешаем запрос
                    return(View(context, viewBag, ActionCheckLink.allow));
                }
                #endregion

                #region Правила 2FA
                else if (IsRequestTheRules(Rule2FA))
                {
                    // Записываем данные пользователя
                    AddJurnalTo200(Is2FA: true);
                    SetCountRequestToHour(TypeRequest._200, host, Domain.confToLog.EnableCountRequest);

                    // Если IP для 2FA уже есть
                    if (memoryCache.TryGetValue(KeyToMemoryCache.CheckLinkWhitelistTo2FA(host, IP), out byte _))
                    {
                        // Авторизация в Telegram
                        if (!TelegramBot.IsAuth(IP, Is2FA: true))
                        {
                            context.Response.ContentType = "text/html";
                            return(context.Response.WriteAsync(TelegramBot.AuthToHtml(IP), context.RequestAborted));
                        }

                        // Успех
                        return(View(context, viewBag, ActionCheckLink.allow));
                    }

                    // Просим пройти 2FA авторизацию
                    viewBag.CoreAPI = jsonDB.Base.CoreAPI;
                    return(View(context, viewBag, ActionCheckLink.Is2FA));
                }
                #endregion

                #region Запрещенные запросы
                else if (IsRequestTheRules(RuleDeny))
                {
                    // Записываем данные пользователя
                    AddJurnalTo403And303(Is403: true);
                    SetCountRequestToHour(TypeRequest._403, host, Domain.confToLog.EnableCountRequest);

                    // Отдаем страницу 403
                    return(View(context, viewBag, ActionCheckLink.deny));
                }
                #endregion

                // Если не одно правило не подошло
                return(null);
            }

            #endregion

            #region Локальный метод - "IsRequestTheRules"
            bool IsRequestTheRules(ModelCache.Rules.Rule rule)
            {
                #region Быстрая проверка 'GET/POST' запроса
                try
                {
                    switch (method)
                    {
                    case "GET":
                        return(rule.RuleGetToRegex != "^$" && Regex.IsMatch(uri, rule.RuleGetToRegex, RegexOptions.IgnoreCase));

                    case "POST":
                    {
                        if (rule.RulePostToRegex != "^$" && Regex.IsMatch(uri, rule.RulePostToRegex, RegexOptions.IgnoreCase))
                        {
                            return(true);
                        }
                        break;
                    }

                    default:
                    {
                        // Записываем данные ошибки в журнал
                        AddJurnalTo500($"Метод '{method}' не поддерживается", IsException: true);
                        SetCountRequestToHour(TypeRequest._500, host, Domain.confToLog.EnableCountRequest);
                        return(true);
                    }
                    }

                    // Быстрая проверка POST запроса
                    if (rule.RuleArgsCheckPostToRegex == "^$" || !Regex.IsMatch(uri, rule.RuleArgsCheckPostToRegex, RegexOptions.IgnoreCase))
                    {
                        return(false);
                    }
                }
                catch (Exception ex)
                {
                    // Записываем данные ошибки в журнал
                    AddJurnalTo500(ex.Message);
                    SetCountRequestToHour(TypeRequest._500, host, Domain.confToLog.EnableCountRequest);

                    // Если есть ошибка в одном из регексов
                    viewBag.IsErrorRule         = true;
                    viewBag.ErrorTitleException = "Ошибка в правиле";
                    viewBag.ErrorRuleException  = jsonDB.Base.DebugEnabled ? ex.Message : "Данные ошибки доступны в журнале 500";
                    return(true);
                }
                #endregion

                #region Полная проверка POST запроса
                // Если POST правил нету - (ложное срабатывание в 'RuleArgsCheckPostToRegex')
                if (rule.postRules == null && rule.postRules.Count < 1)
                {
                    return(false);
                }

                foreach (var postRules in rule.postRules)
                {
                    try
                    {
                        if (Regex.IsMatch(uri, postRules.rule, RegexOptions.IgnoreCase))
                        {
                            // Проверяем есть ли в запросе POST аргументы не указаные в списке правил
                            if (Regex.IsMatch(FormData, postRules.RulePostToRegex, RegexOptions.IgnoreCase))
                            {
                                return(true);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // Записываем данные ошибки в журнал
                        AddJurnalTo500(ex.Message);
                        SetCountRequestToHour(TypeRequest._500, host, Domain.confToLog.EnableCountRequest);

                        // Если есть ошибка в одном из регексов
                        viewBag.IsErrorRule         = true;
                        viewBag.ErrorTitleException = "Ошибка в правиле";
                        viewBag.ErrorRuleException  = jsonDB.Base.DebugEnabled ? ex.Message : "Данные ошибки доступны в журнале 500";
                        return(true);
                    }
                }
                #endregion

                // Если ничего не подошло
                return(false);
            }

            #endregion

            #region Локальный метод - "AddJurnalTo500"
            void AddJurnalTo500(string errorMsg, bool IsException = false)
            {
                if (IsException)
                {
                    viewBag.IsErrorRule         = true;
                    viewBag.ErrorTitleException = "Ошибка в запросе";
                    viewBag.ErrorRuleException  = errorMsg;
                }

                if (Domain.confToLog.Jurn500 != WriteLogMode.off)
                {
                    // Игнорирование логов
                    if (!Regex.IsMatch(uri, Domain.IgnoreLogToRegex, RegexOptions.IgnoreCase))
                    {
                        var model = new Jurnal500()
                        {
                            IP        = IP,
                            Host      = host,
                            Method    = method,
                            Uri       = uri,
                            FormData  = FormData,
                            UserAgent = userAgent,
                            Referer   = context.Request.Headers["Referer"],
                            Time      = DateTime.Now,
                            ErrorMsg  = errorMsg
                        };

                        // Записываем данные в журнал
                        switch (Domain.confToLog.Jurn500)
                        {
                        case WriteLogMode.File:
                            WriteLogTo.FileStream(model);
                            break;

                        case WriteLogMode.SQL:
                            WriteLogTo.SQL(model);
                            break;

                        case WriteLogMode.all:
                            WriteLogTo.SQL(model);
                            WriteLogTo.FileStream(model);
                            break;
                        }
                    }
                }
            }

            #endregion

            #region Локальный метод - "AddJurnalTo403And303"
            void AddJurnalTo403And303(bool Is403 = false, bool Is303 = false)
            {
                if (viewBag.IsErrorRule)
                {
                    return;
                }

                // Игнорирование логов
                if (Domain.confToLog.IsActive && (Domain.confToLog.Jurn403 != WriteLogMode.off || Domain.confToLog.Jurn303 != WriteLogMode.off) && !Regex.IsMatch(uri, Domain.IgnoreLogToRegex, RegexOptions.IgnoreCase))
                {
                    ThreadPool.QueueUserWorkItem(ob =>
                    {
                        var geoIP = (Country: "Disabled", City: "Disabled", Region: "Disabled");
                        if (Domain.confToLog.EnableGeoIP)
                        {
                            geoIP = GeoIP2.City(IP);
                        }


                        #region 403
                        if (Is403)
                        {
                            var model = new Jurnal403()
                            {
                                IP        = IP,
                                Host      = host,
                                Method    = method,
                                Uri       = uri,
                                FormData  = FormData,
                                UserAgent = userAgent,
                                Referer   = Referer,
                                Country   = geoIP.Country,
                                City      = geoIP.City,
                                Region    = geoIP.Region,
                                Time      = DateTime.Now
                            };

                            // Записываем данные в журнал
                            switch (Domain.confToLog.Jurn403)
                            {
                            case WriteLogMode.File:
                                WriteLogTo.FileStream(model);
                                break;

                            case WriteLogMode.SQL:
                                WriteLogTo.SQL(model);
                                break;

                            case WriteLogMode.all:
                                WriteLogTo.SQL(model);
                                WriteLogTo.FileStream(model);
                                break;
                            }
                        }
                        #endregion

                        #region 303
                        if (Is303)
                        {
                            var model = new Jurnal303()
                            {
                                IP        = IP,
                                Host      = host,
                                Method    = method,
                                Uri       = uri,
                                FormData  = FormData,
                                UserAgent = userAgent,
                                Referer   = Referer,
                                Country   = geoIP.Country,
                                City      = geoIP.City,
                                Region    = geoIP.Region,
                                Time      = DateTime.Now
                            };

                            // Записываем данные в журнал
                            switch (Domain.confToLog.Jurn303)
                            {
                            case WriteLogMode.File:
                                WriteLogTo.FileStream(model);
                                break;

                            case WriteLogMode.SQL:
                                WriteLogTo.SQL(model);
                                break;

                            case WriteLogMode.all:
                                WriteLogTo.SQL(model);
                                WriteLogTo.FileStream(model);
                                break;
                            }
                        }
                        #endregion
                    });
                }
            }

            #endregion

            #region Локальный метод - "AddJurnalTo200"
            void AddJurnalTo200(bool IsAntiBot = false, bool Is2FA = false, bool IsIPtables = false)
            {
                // Игнорирование логов
                if (Domain.confToLog.IsActive && !Regex.IsMatch(uri, Domain.IgnoreLogToRegex, RegexOptions.IgnoreCase))
                {
                    ThreadPool.QueueUserWorkItem(ob =>
                    {
                        var geoIP = (Country: "Disabled", City: "Disabled", Region: "Disabled");
                        if (Domain.confToLog.EnableGeoIP)
                        {
                            geoIP = GeoIP2.City(IP);
                        }

                        #region Тип журнала
                        var typeJurn = TypeJurn200.Unknown;

                        if (IsAntiBot)
                        {
                            typeJurn = TypeJurn200.AntiBot;
                        }

                        if (Is2FA)
                        {
                            typeJurn = TypeJurn200._2FA;
                        }

                        if (IsIPtables)
                        {
                            typeJurn = TypeJurn200.IPtables;
                        }
                        #endregion

                        var model = new Jurnal200()
                        {
                            typeJurn  = typeJurn,
                            IP        = IP,
                            Host      = host,
                            Method    = method,
                            Uri       = uri,
                            FormData  = FormData,
                            UserAgent = userAgent,
                            Referer   = Referer,
                            Country   = geoIP.Country,
                            City      = geoIP.City,
                            Region    = geoIP.Region,
                            Time      = DateTime.Now
                        };

                        // Записываем данные в журнал
                        switch (Domain.confToLog.Jurn200)
                        {
                        case WriteLogMode.File:
                            WriteLogTo.FileStream(model);
                            break;

                        case WriteLogMode.SQL:
                            WriteLogTo.SQL(model);
                            break;

                        case WriteLogMode.all:
                            WriteLogTo.FileStream(model);
                            break;
                        }
                    });
                }
            }

            #endregion

            #region Локальный метод - "SetBlockedToIPtables"
            void SetBlockedToIPtables(string Msg, DateTime Expires, string PtrHostName)
            {
                // Данные для статистики
                SetCountRequestToHour(TypeRequest._401, host, Domain.confToLog.EnableCountRequest);

                // Записываем IP в кеш IPtables
                memoryCache.Set(KeyToMemoryCache.IPtables(IP, host), new IPtables(Msg, Expires), Expires);

                // Дублируем информацию в SQL
                WriteLogTo.SQL(new BlockedIP()
                {
                    IP           = IP,
                    BlockingTime = Expires,
                    Description  = Msg,
                    typeBlockIP  = TypeBlockIP.domain,
                    BlockedHost  = host
                });

                // Игнорирование логов
                if (Domain.confToLog.IsActive && !Regex.IsMatch(uri, Domain.IgnoreLogToRegex, RegexOptions.IgnoreCase))
                {
                    var geoIP = (Country : "Disabled", City : "Disabled", Region : "Disabled");
                    if (Domain.confToLog.EnableGeoIP)
                    {
                        geoIP = GeoIP2.City(IP);
                    }

                    // Модель
                    Jurnal401 model = new Jurnal401()
                    {
                        Host      = host,
                        IP        = IP,
                        Msg       = Msg,
                        Ptr       = PtrHostName,
                        UserAgent = userAgent,
                        Country   = geoIP.Country,
                        City      = geoIP.City,
                        Region    = geoIP.Region,
                        Time      = DateTime.Now
                    };

                    // Записываем данные в журнал
                    switch (Domain.confToLog.Jurn401)
                    {
                    case WriteLogMode.File:
                        WriteLogTo.FileStream(model);
                        break;

                    case WriteLogMode.SQL:
                        WriteLogTo.SQL(model);
                        break;

                    case WriteLogMode.all:
                        WriteLogTo.SQL(model);
                        WriteLogTo.FileStream(model);
                        break;
                    }
                }
            }

            #endregion

            #region Локальный метод - "CheckLinkWhitelistToAllDomain"
            bool CheckLinkWhitelistToAllDomain()
            {
                // Глобальный доступ для IP ко всем сайтам
                // Глобальный доступ для IP в этому сайту
                if (memoryCache.TryGetValue(KeyToMemoryCache.CheckLinkWhitelistToAllDomain(IP), out byte _) || memoryCache.TryGetValue(KeyToMemoryCache.CheckLinkWhitelistToAll(host, IP), out byte _))
                {
                    return(true);
                }

                // IP для проверки в формате /24
                string ipCache = Regex.Replace(IP, @"\.[0-9]+$", "");;

                // Глобальный доступ для IP ко всем сайтам
                // Глобальный доступ для IP в этому сайту
                if (memoryCache.TryGetValue(KeyToMemoryCache.CheckLinkWhitelistToAllDomain(ipCache), out byte _) || memoryCache.TryGetValue(KeyToMemoryCache.CheckLinkWhitelistToAll(host, ipCache), out byte _))
                {
                    return(true);
                }

                // IP нету в белом списке
                return(false);
            }

            #endregion
        }
예제 #11
0
        public static void CreateToOnCallback()
        {
            try
            {
                // Настройка
                tlg = Service.Get <JsonDB>().TelegramBot;
                Bot = new TelegramBotClient(tlg.Token);
                Bot.SetWebhookAsync("").Wait();

                // Callback
                Bot.OnCallbackQuery += async(object sc, CallbackQueryEventArgs ev) =>
                {
                    try
                    {
                        var message = ev.CallbackQuery.Message;
                        if (ev.CallbackQuery.Data.Contains("AuthCmd"))
                        {
                            // IP адрес
                            string IP = new Regex("([^\n\r\t ]+)([\n\r\t ]+)?$").Match(message.Text).Groups[0].Value;

                            #region Действие
                            switch (ev.CallbackQuery.Data)
                            {
                            case "AuthCmd-Access":
                            {
                                memoryCache.Set(GetKey(IP, message.Text.Contains("2FA")), (byte)0, TimeSpan.FromMinutes(20));
                                await Bot.SendTextMessageAsync(message.Chat.Id, $"Доступ для '{IP}' разрешен");

                                break;
                            }

                            case "AuthCmd-NotAccess":
                            {
                                await Bot.SendTextMessageAsync(message.Chat.Id, "Рекомендуем сменить пароли");

                                break;
                            }

                            case "AuthCmd-BlockedIP":
                            {
                                // Записываем IP в кеш IPtables
                                memoryCache.Set(KeyToMemoryCache.IPtables(IP), new IPtables("TelegramBot", DateTime.Now.AddHours(1)), TimeSpan.FromHours(1));
                                await Bot.SendTextMessageAsync(message.Chat.Id, $"IP '{IP}' заблокирован\nРекомендуем сменить пароли");

                                break;
                            }
                            }
                            #endregion

                            // Отсылаем пустое, чтобы убрать "часики" на кнопке
                            await Bot.AnswerCallbackQueryAsync(ev.CallbackQuery.Id);
                        }
                    }
                    catch { }
                };

                // Запускаем прием обновлений
                new System.Threading.Thread(() => Bot.StartReceiving()).Start();
            }
            catch { }
        }
예제 #12
0
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime applicationLifetime, IMemoryCache memoryCache)
        {
            #region Системные настройки
            loggerFactory.AddConsole();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();

                // Страница для тестов
                app.UseMvc(routes => routes.MapRoute("TestPage", "test", new { controller = "Test", action = "Index" }));
            }
            #endregion

            #region Добовляем порт в белый список
            if (Platform.Get == PlatformOS.Unix)
            {
                if (string.IsNullOrWhiteSpace(new Bash().Run("iptables -L INPUT -v -n 2>/dev/null | grep 8793")))
                {
                    new Bash().Run("iptables -I INPUT -p tcp --dport 8793 -j ACCEPT");
                }
            }
            #endregion

            #region Unix Socket
            try
            {
                applicationLifetime.ApplicationStarted.Register(() =>
                {
                    if (Platform.Get == PlatformOS.Unix || Platform.Get == PlatformOS.Docker)
                    {
                        ThreadPool.QueueUserWorkItem((s) =>
                        {
                            while (true)
                            {
                                // Ждем 3 секунды
                                Thread.Sleep(1000 * 3);

                                // Меняем права доступа
                                if (File.Exists("/var/run/ispcore.sock"))
                                {
                                    new Bash().Run("chmod 666 /var/run/ispcore.sock");
                                    return;
                                }
                            }
                        });
                    }
                });
            }
            catch { }
            #endregion

            // Создаем сервис
            Service.Create(memoryCache);

            #region Загружаем список BlockedIP в кеш
            using (CoreDB coreDB = Service.Get <CoreDB>())
            {
                // IP который нужно удалить
                string unlockip = string.Empty;
                if (File.Exists($"{Folders.Tmp}/unlockip.root"))
                {
                    unlockip = File.ReadAllText($"{Folders.Tmp}/unlockip.root").Trim();
                }

                // Загружаем IP адреса
                foreach (var blockedIP in coreDB.BlockedsIP.AsNoTracking())
                {
                    if (blockedIP.BlockingTime > DateTime.Now && blockedIP.typeBlockIP != TypeBlockIP.UserAgent)
                    {
                        // IP адрес
                        string RemoteIpAddress = blockedIP.IP.Replace(".*", "").Replace(":*", "");

                        // Белый IP
                        if (RemoteIpAddress.Contains(unlockip))
                        {
                            continue;
                        }

                        // Где именно блокировать IP
                        string keyIPtables = blockedIP.typeBlockIP == TypeBlockIP.domain ? KeyToMemoryCache.IPtables(RemoteIpAddress, blockedIP.BlockedHost) : KeyToMemoryCache.IPtables(RemoteIpAddress);

                        // Записываем IP в кеш IPtables
                        memoryCache.Set(keyIPtables, new IPtables(blockedIP.Description, blockedIP.BlockingTime), blockedIP.BlockingTime);
                    }
                }
            }
            #endregion

            #region Загружаем список WhitePtrIP в кеш
            using (CoreDB coreDB = Service.Get <CoreDB>())
            {
                // Загружаем IP адреса
                foreach (var item in coreDB.WhitePtrIPs.AsNoTracking())
                {
                    // Добовляем IP в кеш
                    if (item.Expires > DateTime.Now)
                    {
                        memoryCache.Set(KeyToMemoryCache.WhitePtrIP(item.IPv4Or6), (byte)0, item.Expires);
                    }
                }
            }
            #endregion

            #region Загружаем список "Разрешенные доступы" в кеш
            foreach (var item in AccessIP.List())
            {
                // IP для кеша
                string ipCache = item.IP.Replace(".*", "").Replace(":*", "");

                switch (item.accessType)
                {
                case AccessType.all:
                    memoryCache.Set(KeyToMemoryCache.CheckLinkWhitelistToAll(item.host, ipCache), (byte)1, item.Expires);
                    break;

                case AccessType.Is2FA:
                    memoryCache.Set(KeyToMemoryCache.CheckLinkWhitelistTo2FA(item.host, ipCache), (byte)1, item.Expires);
                    break;

                case AccessType.allDomain:
                    memoryCache.Set(KeyToMemoryCache.CheckLinkWhitelistToAllDomain(ipCache), (byte)1, item.Expires);
                    break;
                }
            }
            #endregion

            // Статичиские файлы
            app.UseStaticFiles();

            #region IP-адрес клиента
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
                KnownProxies     = { IPAddress.Parse("172.17.42.1"), IPAddress.Parse("127.0.0.1") },
            });
            #endregion

            // Страницы ошибок
            app.UseMvc(routes => {
                routes.MapRoute("ErrorPage-404", "404", new { controller = "Error", action = "_404" });
            });

            // Блокировка IP
            app.UseIPtablesMiddleware();

            #region Core API
            // Доступ запрещен с порта панели 8793
            app.UseCoreMiddleware();

            // Core CheckRequest
            app.Map("/core/check/request", ap => ap.Run(context =>
            {
                // Состояние потока
                bool RanToCompletion = false;

                // Завершаем подключение через 10 секунд
                var token = new CancellationTokenSource(1000 * 10).Token;
                token.Register(() =>
                {
                    if (!RanToCompletion)
                    {
                        context.Abort();
                    }
                });

                // Проверка запроса
                var task        = Engine.core.Check.Request.Check(context);
                RanToCompletion = task.Status == TaskStatus.RanToCompletion;

                // Успех
                return(task);
            }));

            // Core API
            app.UseMvc(routes => {
                routes.MapRoute(null, "core/unlock/2fa", new { controller = "CoreUnlock2FA", action = "Index" });
                routes.MapRoute(null, "core/check/cookie", new { controller = "CoreCheckCookie", action = "Index" });
                routes.MapRoute(null, "core/check/recaptcha", new { controller = "CoreCheckRecaptcha", action = "Base" });
                routes.MapRoute(null, "core/check/recaptcha/limitrequest", new { controller = "CoreCheckRecaptcha", action = "LimitRequest" });
            });

            // AntiBotHub
            app.UseSignalR(routes => routes.MapHub <AntiBotHub>("core/AntiBotHub"));

            // Генерация скриптов
            app.UseMvc(routes => {
                routes.MapRoute(null, "core/gen/antibot.js", new { controller = "CoreGenToAntiBot", action = "Index" });
            });

            // Заглушка для "Core API"
            app.Map("/core", ap => ap.Run(context => context.Response.WriteAsync("404  Not Found")));
            #endregion

            #region Открытый API
            {
                // Проверка авторизации
                app.UseAuthApiMiddleware();

                #region API - List
                app.UseMvc(routes =>
                {
                    routes.MapRoute(null, "api/list/home/jurnal", new { controller = "ApiListHome", action = "Jurnal" });
                    routes.MapRoute(null, "api/list/notifications", new { controller = "ApiListNotifications", action = "Jurnal" });
                    routes.MapRoute(null, "api/list/jsondb", new { controller = "ApiListJsonDB", action = "Get" });

                    routes.MapRoute(null, "api/list/security/anti-ddos/stats/day", new { controller = "ApiListAntiDdos", action = "StatsDay" });
                    routes.MapRoute(null, "api/list/security/anti-ddos/stats/month", new { controller = "ApiListAntiDdos", action = "StatsMonth" });
                    routes.MapRoute(null, "api/list/security/anti-ddos/jurnal", new { controller = "ApiListAntiDdos", action = "Jurnal" });

                    routes.MapRoute(null, "api/list/security/iptables/blockedip", new { controller = "ApiListIptables", action = "BlockedsIP" });
                    routes.MapRoute(null, "api/list/security/av/report", new { controller = "ApiListAntiVirus", action = "Report" });

                    routes.MapRoute(null, "api/list/requests-filter/domain", new { controller = "ApiListDomain", action = "Domain" });
                    routes.MapRoute(null, "api/list/requests-filter/domains", new { controller = "ApiListDomain", action = "Domains" });
                    routes.MapRoute(null, "api/list/requests-filter/template", new { controller = "ApiListTemplate", action = "Template" });
                    routes.MapRoute(null, "api/list/requests-filter/templates", new { controller = "ApiListTemplate", action = "Templates" });
                    routes.MapRoute(null, "api/list/requests-filter/access", new { controller = "ApiListAccess", action = "Get" });

                    routes.MapRoute(null, "api/list/requests-filter/monitoring/stats/day", new { controller = "ApiListMonitoring", action = "StatsDay" });
                    routes.MapRoute(null, "api/list/requests-filter/monitoring/stats/month", new { controller = "ApiListMonitoring", action = "StatsMonth" });
                    routes.MapRoute(null, "api/list/requests-filter/monitoring/jurnal", new { controller = "ApiListMonitoring", action = "Jurnal" });

                    routes.MapRoute(null, "api/list/backup/task", new { controller = "ApiListBackup", action = "Task" });
                    routes.MapRoute(null, "api/list/backup/tasks", new { controller = "ApiListBackup", action = "Tasks" });
                    routes.MapRoute(null, "api/list/backup/operations", new { controller = "ApiListBackup", action = "Operation" });
                });
                #endregion

                #region API - Add
                app.UseMvc(routes =>
                {
                    routes.MapRoute(null, "api/add/whitelist", new { controller = "ApiAddWhiteList", action = "Base" });
                    routes.MapRoute(null, "api/add/security/iptables", new { controller = "ApiAddIptables", action = "Base" });

                    routes.MapRoute(null, "api/add/backup/task", new { controller = "ApiAddBackup", action = "Task" });
                    routes.MapRoute(null, "api/add/backup/ignore", new { controller = "ApiAddBackup", action = "Ignore" });

                    routes.MapRoute(null, "api/add/requests-filter/template", new { controller = "ApiAddTemplate", action = "Base" });
                    routes.MapRoute(null, "api/add/requests-filter/template/rule", new { controller = "ApiAddRule", action = "RuleTemplate" });

                    routes.MapRoute(null, "api/add/requests-filter/domain", new { controller = "ApiAddDomain", action = "Domain" });
                    routes.MapRoute(null, "api/add/requests-filter/aliases", new { controller = "ApiAddDomain", action = "Aliases" });
                    routes.MapRoute(null, "api/add/requests-filter/domain/rule", new { controller = "ApiAddRule", action = "RuleDomain" });
                    routes.MapRoute(null, "api/add/requests-filter/domain/template", new { controller = "ApiAddDomain", action = "TemplatesId" });
                    routes.MapRoute(null, "api/add/requests-filter/domain/ignore", new { controller = "ApiAddDomain", action = "IgnoreLogs" });
                    routes.MapRoute(null, "api/add/requests-filter/access", new { controller = "ApiAddAccess", action = "Base" });
                });
                #endregion

                #region API - Remove
                app.UseMvc(routes =>
                {
                    routes.MapRoute(null, "api/remove/whitelist", new { controller = "ApiRemoveWhiteList", action = "Base" });
                    routes.MapRoute(null, "api/remove/security/iptables", new { controller = "ApiRemoveIptables", action = "BlockedsIP" });
                    routes.MapRoute(null, "api/remove/security/antivirus", new { controller = "ApiRemoveAntivirus", action = "Base" });

                    routes.MapRoute(null, "api/remove/backup/task", new { controller = "ApiRemoveBackup", action = "Task" });
                    routes.MapRoute(null, "api/remove/backup/ignore", new { controller = "ApiRemoveBackup", action = "Ignore" });

                    routes.MapRoute(null, "api/remove/requests-filter/rules/base", new { controller = "ApiRemoveRules", action = "Rule" });
                    routes.MapRoute(null, "api/remove/requests-filter/rules/replace", new { controller = "ApiRemoveRules", action = "RuleReplace" });
                    routes.MapRoute(null, "api/remove/requests-filter/rules/override", new { controller = "ApiRemoveRules", action = "RuleOverride" });
                    routes.MapRoute(null, "api/remove/requests-filter/rules/arg", new { controller = "ApiRemoveRules", action = "RuleArg" });
                    routes.MapRoute(null, "api/remove/requests-filter/alias", new { controller = "ApiRemoveDomain", action = "Alias" });
                    routes.MapRoute(null, "api/remove/requests-filter/domain", new { controller = "ApiRemoveDomain", action = "Base" });
                    routes.MapRoute(null, "api/remove/requests-filter/domain/template", new { controller = "ApiRemoveDomain", action = "Template" });
                    routes.MapRoute(null, "api/remove/requests-filter/domain/ignore", new { controller = "ApiRemoveDomain", action = "Ignore" });
                    routes.MapRoute(null, "api/remove/requests-filter/template", new { controller = "ApiRemoveTemplate", action = "Base" });
                    routes.MapRoute(null, "api/remove/requests-filter/access", new { controller = "ApiRemoveAccess", action = "Base" });
                });
                #endregion

                #region API - Common
                app.UseMvc(routes =>
                {
                    routes.MapRoute(null, "api/common/av/start", new { controller = "ApiCommonAV", action = "Start" });
                    routes.MapRoute(null, "api/common/av/stop", new { controller = "ApiCommonAV", action = "Stop" });

                    routes.MapRoute(null, "api/common/template/export", new { controller = "ApiCommonTemplate", action = "Export" });
                    routes.MapRoute(null, "api/common/template/import", new { controller = "ApiCommonTemplate", action = "Import" });

                    routes.MapRoute(null, "api/common/backup/clearing/cache", new { controller = "ApiCommonBackup", action = "ClearingCache" });
                    routes.MapRoute(null, "api/common/backup/recovery", new { controller = "ApiCommonBackup", action = "Recovery" });
                });
                #endregion

                #region API - Edit
                app.UseMvc(routes =>
                {
                    routes.MapRoute(null, "api/edit/settings/base", new { controller = "ApiEditSettings", action = "Base" });
                    routes.MapRoute(null, "api/edit/settings/api", new { controller = "ApiEditSettings", action = "API" });
                    routes.MapRoute(null, "api/edit/settings/security", new { controller = "ApiEditSettings", action = "Security" });
                    routes.MapRoute(null, "api/edit/settings/passwd", new { controller = "ApiEditSettings", action = "Passwd" });
                    routes.MapRoute(null, "api/edit/settings/brute-force", new { controller = "ApiEditSettings", action = "BruteForce" });
                    routes.MapRoute(null, "api/edit/settings/telegrambot", new { controller = "ApiEditSettings", action = "TelegramBot" });

                    routes.MapRoute(null, "api/edit/settings/anti-ddos", new { controller = "ApiEditSettings", action = "AntiDdos" });
                    routes.MapRoute(null, "api/edit/settings/antivirus", new { controller = "ApiEditSettings", action = "AntiVirus" });

                    routes.MapRoute(null, "api/edit/antibot/base", new { controller = "ApiEditAntiBot", action = "Base" });
                    routes.MapRoute(null, "api/edit/antibot/limit", new { controller = "ApiEditAntiBot", action = "Limit" });

                    routes.MapRoute(null, "api/edit/domain/base", new { controller = "ApiEditDomain", action = "Base" });
                    routes.MapRoute(null, "api/edit/domain/log", new { controller = "ApiEditDomain", action = "LogSettings" });
                    routes.MapRoute(null, "api/edit/domain/av", new { controller = "ApiEditDomain", action = "AntiVirus" });
                    routes.MapRoute(null, "api/edit/domain/antibot", new { controller = "ApiEditDomain", action = "AntiBot" });
                    routes.MapRoute(null, "api/edit/domain/limit/request", new { controller = "ApiEditDomain", action = "LimitRequest" });

                    routes.MapRoute(null, "api/edit/template", new { controller = "ApiEditTemplate", action = "Base" });

                    routes.MapRoute(null, "api/edit/backup/task", new { controller = "ApiEditBackup", action = "Task" });
                    routes.MapRoute(null, "api/edit/backup/ftp", new { controller = "ApiEditBackup", action = "FTP" });
                    routes.MapRoute(null, "api/edit/backup/webdav", new { controller = "ApiEditBackup", action = "WebDav" });
                    routes.MapRoute(null, "api/edit/backup/onedrive", new { controller = "ApiEditBackup", action = "OneDrive" });
                });
                #endregion
            }
            #endregion

            #region Авторизация
            // Страница авторизации
            app.UseMvc(routes => {
                routes.MapRoute(null, "auth", new { controller = "Auth", action = "Index" });
                routes.MapRoute(null, "auth/unlock", new { controller = "Auth", action = "Unlock" });
                routes.MapRoute(null, "auth/signout", new { controller = "Auth", action = "SignOut" });
            });

            // Проверка авторизации
            app.UseAuthMiddleware();
            #endregion

            // Главная страница
            app.UseMvc(routes => {
                routes.MapRoute(null, "", new { controller = "Home", action = "Index" });
            });

            #region API
            // FAQ
            app.UseMvc(routes => routes.MapRoute(null, "api/faq", new { controller = "ApiFaq", action = "Index" }));

            // Заглушка для "API"
            app.Map("/api", ap => ap.Run(context => context.Response.WriteAsync("404  Not Found")));
            #endregion

            #region Настройки
            app.UseMvc(routes => {
                routes.MapRoute(null, "settings", new { controller = "Settings", action = "Index" });
                routes.MapRoute(null, "settings/save/base", new { controller = "Settings", action = "Save" });
                routes.MapRoute(null, "settings/remove/whiteList", new { controller = "Settings", action = "RemoveWhiteList" });
            });
            #endregion

            #region Безопастность системы
            // Брандмауэр
            app.UseMvc(routes => {
                routes.MapRoute(null, "security/iptables", new { controller = "SecurityToIPtables", action = "Index" });
                routes.MapRoute(null, "security/iptables/remove", new { controller = "SecurityToIPtables", action = "Remove" });
                routes.MapRoute(null, "security/iptables/add", new { controller = "SecurityToIPtables", action = "Add" });
            });

            // Антивирус
            app.UseMvc(routes => {
                routes.MapRoute(null, "security/antivirus", new { controller = "SecurityToAntiVirus", action = "Index" });
                routes.MapRoute(null, "security/antivirus/save", new { controller = "SecurityToAntiVirus", action = "Save" });
                routes.MapRoute(null, "security/antivirus/remove", new { controller = "SecurityToAntiVirus", action = "Remove" });
                routes.MapRoute(null, "security/antivirus/start", new { controller = "SecurityToAntiVirus", action = "Start" });
                routes.MapRoute(null, "security/antivirus/stop", new { controller = "SecurityToAntiVirus", action = "Stop" });
            });

            // Антидосс
            if (Platform.Get == PlatformOS.Unix)
            {
                app.UseMvc(routes =>
                {
                    routes.MapRoute(null, "security/anti-ddos", new { controller = "SecurityToAntiDdos", action = "Index" });
                    routes.MapRoute(null, "security/anti-ddos/save", new { controller = "SecurityToAntiDdos", action = "Save" });
                });
            }

            // Anti-Bot
            app.UseMvc(routes =>
            {
                routes.MapRoute(null, "security/antibot", new { controller = "SecurityToAntiBot", action = "Index" });
                routes.MapRoute(null, "security/antibot/save", new { controller = "SecurityToAntiBot", action = "Save" });
            });
            #endregion

            #region Фильтрация запросов
            // Views
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/domains", new { controller = "RequestsFilterToDomains", action = "Index" });
                routes.MapRoute(null, "requests-filter/templates", new { controller = "RequestsFilterToTemplates", action = "Index" });
                routes.MapRoute(null, "requests-filter/monitoring", new { controller = "RequestsFilterToMonitoring", action = "Index" });
            });

            // Common
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/common/remove/rule", new { controller = "RequestsFilterToCommon", action = "RemoveToRule" });
                routes.MapRoute(null, "requests-filter/common/remove/rulereplace", new { controller = "RequestsFilterToCommon", action = "RemoveToRuleReplace" });
                routes.MapRoute(null, "requests-filter/common/remove/ruleoverride", new { controller = "RequestsFilterToCommon", action = "RemoveToRuleOverride" });
                routes.MapRoute(null, "requests-filter/common/remove/rulearg", new { controller = "RequestsFilterToCommon", action = "RemoveToRuleArg" });
                routes.MapRoute(null, "requests-filter/common/remove/alias", new { controller = "RequestsFilterToCommon", action = "RemoveToAlias" });
            });

            // Шаблон
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/template", new { controller = "RequestsFilterToTemplate", action = "Index" });
                routes.MapRoute(null, "requests-filter/template/save", new { controller = "RequestsFilterToTemplate", action = "Save" });
                routes.MapRoute(null, "requests-filter/template/remove", new { controller = "RequestsFilterToTemplate", action = "Remove" });
                routes.MapRoute(null, "requests-filter/template/import", new { controller = "RequestsFilterToTemplate", action = "Import" });
                routes.MapRoute(null, "requests-filter/template/export", new { controller = "RequestsFilterToTemplate", action = "Export" });
            });

            // Разрешенные доступы
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/access", new { controller = "RequestsFilterToAccess", action = "Index" });
                routes.MapRoute(null, "requests-filter/access/open", new { controller = "RequestsFilterToAccess", action = "Open" });
                routes.MapRoute(null, "requests-filter/access/remove", new { controller = "RequestsFilterToAccess", action = "Remove" });
            });
            #endregion

            #region Фильтрация запросов - Домен
            // Домен - Главная/FAQ
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/domain/base", new { controller = "RequestsFilterToDomainBase", action = "Index" });
                routes.MapRoute(null, "requests-filter/domain/faq", new { controller = "RequestsFilterToDomainBase", action = "Faq" });
                routes.MapRoute(null, "requests-filter/domain/remove", new { controller = "RequestsFilterToDomainBase", action = "Remove" });
                routes.MapRoute(null, "requests-filter/domain/save/base", new { controller = "RequestsFilterToDomainBase", action = "Save" });
                routes.MapRoute(null, "requests-filter/domain/import", new { controller = "RequestsFilterToDomainBase", action = "Import" });
                routes.MapRoute(null, "requests-filter/domain/export", new { controller = "RequestsFilterToDomainBase", action = "Export" });
            });

            // Домен - Алиасы
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/domain/aliases", new { controller = "RequestsFilterToDomainAliases", action = "Index" });
                routes.MapRoute(null, "requests-filter/domain/save/aliases", new { controller = "RequestsFilterToDomainAliases", action = "Save" });
            });

            // Домен - Правила
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/domain/rules", new { controller = "RequestsFilterToDomainRules", action = "Index" });
                routes.MapRoute(null, "requests-filter/domain/save/rules", new { controller = "RequestsFilterToDomainRules", action = "Save" });
            });

            // Домен - Настройки журнала
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/domain/logsettings", new { controller = "RequestsFilterToDomainLogSettings", action = "Index" });
                routes.MapRoute(null, "requests-filter/domain/save/logsettings", new { controller = "RequestsFilterToDomainLogSettings", action = "Save" });
            });

            // Домен - Антивирус
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/domain/av", new { controller = "RequestsFilterToDomainAv", action = "Index" });
                routes.MapRoute(null, "requests-filter/domain/save/av", new { controller = "RequestsFilterToDomainAv", action = "Save" });
            });

            // Домен - AntiBot
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/domain/antibot", new { controller = "RequestsFilterToDomainAntiBot", action = "Index" });
                routes.MapRoute(null, "requests-filter/domain/save/antibot", new { controller = "RequestsFilterToDomainAntiBot", action = "Save" });
            });

            // Домен - Лимит запросов
            app.UseMvc(routes => {
                routes.MapRoute(null, "requests-filter/domain/limitrequest", new { controller = "RequestsFilterToDomainLimitRequest", action = "Index" });
                routes.MapRoute(null, "requests-filter/domain/save/limitrequest", new { controller = "RequestsFilterToDomainLimitRequest", action = "Save" });
            });
            #endregion

            #region SyncBackup
            // Views
            app.UseMvc(routes =>
            {
                routes.MapRoute(null, "backup/tasks", new { controller = "SyncBackupToTasks", action = "Index" });
                routes.MapRoute(null, "backup/operation", new { controller = "SyncBackupToOperation", action = "Index" });
            });

            // Задание
            app.UseMvc(routes =>
            {
                routes.MapRoute(null, "backup/task", new { controller = "SyncBackupToTask", action = "Index" });
                routes.MapRoute(null, "backup/task/remove", new { controller = "SyncBackupToTask", action = "Remove" });
                routes.MapRoute(null, "backup/task/save", new { controller = "SyncBackupToTask", action = "Save" });
                routes.MapRoute(null, "backup/task/clearing-cache", new { controller = "SyncBackupToTask", action = "ClearingCache" });
            });

            // Улиты
            app.UseMvc(routes =>
            {
                routes.MapRoute(null, "backup/tools", new { controller = "SyncBackupToTools", action = "Index" });
                routes.MapRoute(null, "backup/tools/recover", new { controller = "SyncBackupToTools", action = "Recovery" });
            });

            // Получение токенов
            app.UseMvc(routes =>
            {
                routes.MapRoute(null, "backup/authorize/onedrive", new { controller = "SyncBackupToAuthorize", action = "OneDrive" });
            });
            #endregion

            // Уведомления
            app.UseMvc(routes => {
                routes.MapRoute(null, "notifications", new { controller = "Notifications", action = "Index" });
            });

            // Ошибка 404
            app.Run(async(context) =>
            {
                await RewriteTo.Local(context, "404" + (context.Request.QueryString.Value.Contains("ajax=true") ? "?ajax=true" : ""));
            });
        }