• Модуль: security
  • Путь к файлу: ~/bitrix/modules/security/classes/general/iprule.php
  • Класс: CSecurityIPRule
  • Вызов: CSecurityIPRule::OnPageStart
static function OnPageStart($use_query = false)
{
	//ToDo: good candidate for refactoring
	global $DB, $CACHE_MANAGER;

	if(
		!CSecuritySystemInformation::isCliMode()
		&& CSecurityIPRule::GetActiveCount()
	)
	{
		if(CSecurityIPRule::CheckAntiFile())
			return;

		$bMatch = false;

		$uri = $_SERVER['REQUEST_URI'];
		if (($pos = mb_strpos($uri, '?')) !== false)
			$uri = mb_substr($uri, 0, $pos);

		$uri = urldecode($uri);
		$uri = preg_replace('#/+#', '/', $uri);
		//Block any invalid uri
		if (!static::isValidUri($uri))
			include($_SERVER['DOCUMENT_ROOT'].'/bitrix/admin/security_403.php'); //die inside

		//Normalize on Windows, because my. == my
		if (CSecuritySystemInformation::isRunOnWin())
			$uri = preg_replace('#(. )+[/\]+#', '/', $uri);

		$ip2check = CSecurityIPRule::ip2number($_SERVER["REMOTE_ADDR"]);

		if(!$use_query && CACHED_b_sec_iprule !== false)
		{
			$cache_id = "b_sec_iprule";
			if($CACHE_MANAGER->Read(CACHED_b_sec_iprule, $cache_id, "b_sec_iprule"))
			{
				$arRules = $CACHE_MANAGER->Get($cache_id);
			}
			else
			{
				$arRules = array();

				$rs = $DB->Query("
					SELECT
						r.ID,
						r.ADMIN_SECTION,
						r.SITE_ID,
						r.ACTIVE_FROM_TIMESTAMP,
						r.ACTIVE_TO_TIMESTAMP
					FROM
						b_sec_iprule r
					WHERE
						r.ACTIVE='Y'
						AND (
							r.ACTIVE_TO IS NULL
							OR r.ACTIVE_TO >= ".$DB->CurrentTimeFunction()."
						)
				");
				while($ar = $rs->Fetch())
				{
					$ar["ACTIVE_FROM_TIMESTAMP"] = intval($ar["ACTIVE_FROM_TIMESTAMP"]);
					$ar["ACTIVE_TO_TIMESTAMP"] = intval($ar["ACTIVE_TO_TIMESTAMP"]);
					$ar["INCL_MASKS"] = array();
					$ar["EXCL_MASKS"] = array();
					$ar["INCL_IPS"] = array();
					$ar["EXCL_IPS"] = array();
					$arRules[$ar["ID"]] = $ar;
				}

				$rs = $DB->Query("
					SELECT
						im.IPRULE_ID,
						im.PREG_MASK
					FROM
						b_sec_iprule r
						INNER JOIN b_sec_iprule_incl_mask im on im.IPRULE_ID = r.ID
					WHERE
						r.ACTIVE='Y'
						AND (
							r.ACTIVE_TO IS NULL
							OR r.ACTIVE_TO >= ".$DB->CurrentTimeFunction()."
						)
				");
				while($ar = $rs->Fetch())
					if(array_key_exists($ar["IPRULE_ID"], $arRules))
						$arRules[$ar["IPRULE_ID"]]["INCL_MASKS"][] = $ar["PREG_MASK"];

				foreach($arRules as $ID => $ar)
					if(count($ar["INCL_MASKS"]) <= 0)
						unset($arRules[$ID]);

				$rs = $DB->Query("
					SELECT
						em.IPRULE_ID,
						em.PREG_MASK
					FROM
						b_sec_iprule r
						INNER JOIN b_sec_iprule_excl_mask em on em.IPRULE_ID = r.ID
					WHERE
						r.ACTIVE='Y'
						AND (
							r.ACTIVE_TO IS NULL
							OR r.ACTIVE_TO >= ".$DB->CurrentTimeFunction()."
						)
				");
				while($ar = $rs->Fetch())
					if(array_key_exists($ar["IPRULE_ID"], $arRules))
						$arRules[$ar["IPRULE_ID"]]["EXCL_MASKS"][] = $ar["PREG_MASK"];

				$rs = $DB->Query("
					SELECT
						ii.IPRULE_ID,
						ii.IP_START,
						ii.IP_END
					FROM
						b_sec_iprule r
						INNER JOIN b_sec_iprule_incl_ip ii on ii.IPRULE_ID = r.ID
					WHERE
						r.ACTIVE='Y'
						AND (
							r.ACTIVE_TO IS NULL
							OR r.ACTIVE_TO >= ".$DB->CurrentTimeFunction()."
						)
				");
				while($ar = $rs->Fetch())
					if(array_key_exists($ar["IPRULE_ID"], $arRules))
						$arRules[$ar["IPRULE_ID"]]["INCL_IPS"][] = array(
							doubleval($ar["IP_START"]),
							doubleval($ar["IP_END"]),
						);

				foreach($arRules as $ID => $ar)
					if(count($ar["INCL_IPS"]) <= 0)
						unset($arRules[$ID]);

				$rs = $DB->Query("
					SELECT
						ei.IPRULE_ID,
						ei.IP_START,
						ei.IP_END
					FROM
						b_sec_iprule r
						INNER JOIN b_sec_iprule_excl_ip ei on ei.IPRULE_ID = r.ID
					WHERE
						r.ACTIVE='Y'
						AND (
							r.ACTIVE_TO IS NULL
							OR r.ACTIVE_TO >= ".$DB->CurrentTimeFunction()."
						)
				");
				while($ar = $rs->Fetch())
					if(array_key_exists($ar["IPRULE_ID"], $arRules))
						$arRules[$ar["IPRULE_ID"]]["EXCL_IPS"][] = array(
							doubleval($ar["IP_START"]),
							doubleval($ar["IP_END"]),
						);

				$CACHE_MANAGER->Set($cache_id, $arRules);
			}

			foreach($arRules as $arRule)
			{
				//Check if this rule is active
				if(
					($arRule["ACTIVE_FROM_TIMESTAMP"] <= 0 || $arRule["ACTIVE_FROM_TIMESTAMP"] <= time())
					&& ($arRule["ACTIVE_TO_TIMESTAMP"] <= 0 || $arRule["ACTIVE_TO_TIMESTAMP"] >= time())
				)
				{
					$bMatch = true;
				}
				else
				{
					$bMatch = false;
				}

				//Check if site does match
				if($bMatch)
				{
					if(defined("ADMIN_SECTION") && ADMIN_SECTION===true)
						$bMatch = $arRule["ADMIN_SECTION"] == "Y";
					else
						$bMatch = (!$arRule["SITE_ID"] || $arRule["SITE_ID"] == SITE_ID);
				}
				else
				{
					continue;
				}

				//Check if IP in blocked
				if($bMatch)
				{
					$bMatch = false;
					foreach($arRule["INCL_IPS"] as $arIP)
					{
						if($ip2check >= $arIP[0] && $ip2check <= $arIP[1])
						{
							$bMatch = true;
							break;
						}
					}
					//IP is in blocked range so check if it is excluded
					if($bMatch)
					{
						foreach($arRule["EXCL_IPS"] as $arIP)
						{
							if($ip2check >= $arIP[0] && $ip2check <= $arIP[1])
							{
								$bMatch = false;
								break;
							}
						}
					}
				}
				else
				{
					continue;
				}

				//IP does match to blocking condition let's check path
				if($bMatch)
				{
					$bMatch = false;
					foreach($arRule["INCL_MASKS"] as $mask)
					{
						if(preg_match("#^".$mask."$#", $uri))
						{
							$bMatch = true;
							break;
						}
					}
					//Check path for exclusion
					if($bMatch)
					{
						foreach($arRule["EXCL_MASKS"] as $mask)
						{
							if(preg_match("#^".$mask."$#", $uri))
							{
								$bMatch = false;
								break;
							}
						}
					}
				}
				else
				{
					continue;
				}

				//Found blocking rule
				if($bMatch)
					break;
			}
		}
		else
		{
			$strSql = "
				SELECT r.ID
				FROM
					b_sec_iprule r
					INNER JOIN b_sec_iprule_incl_mask im on im.IPRULE_ID = r.ID
					LEFT  JOIN b_sec_iprule_excl_mask em on em.IPRULE_ID = r.ID AND '".$DB->ForSQL($uri)."' like em.LIKE_MASK
					INNER JOIN b_sec_iprule_incl_ip   ii on ii.IPRULE_ID = r.ID
					LEFT  JOIN b_sec_iprule_excl_ip   ei on ei.IPRULE_ID = r.ID AND ".$ip2check." between ei.IP_START and ei.IP_END
				WHERE
					r.ACTIVE = 'Y'
					AND (r.ACTIVE_FROM IS NULL OR r.ACTIVE_FROM <= ".$DB->CurrentTimeFunction().")
					AND (r.ACTIVE_TO IS NULL OR r.ACTIVE_TO >= ".$DB->CurrentTimeFunction().")
					".(defined("ADMIN_SECTION") && ADMIN_SECTION===true?
						"AND r.ADMIN_SECTION = 'Y'":
						"AND (r.SITE_ID IS NULL OR r.SITE_ID = '".$DB->ForSQL(SITE_ID)."')"
					)."
					AND '".$DB->ForSQL($uri)."' like im.LIKE_MASK
					AND em.IPRULE_ID is null
					AND ".$ip2check." between ii.IP_START and ii.IP_END
					AND ei.IPRULE_ID is null
			";

			$rs = $DB->Query($strSql);

			if($arRule = $rs->Fetch())
				$bMatch = true;
			else
				$bMatch = false;
		}

		if($bMatch)
			include($_SERVER["DOCUMENT_ROOT"]."/bitrix/admin/security_403.php");

	}
}